Blender V4.3
blender/image.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "MEM_guardedalloc.h"
6
7#include "blender/image.h"
8#include "blender/session.h"
9#include "blender/util.h"
10
11#include "util/half.h"
12
14
15/* Packed Images */
16
18 const int frame,
19 const int tile_number,
20 const bool is_preview_render)
21 : b_image(b_image),
22 frame(frame),
23 tile_number(tile_number),
24 /* Don't free cache for preview render to avoid race condition from #93560, to be fixed
25 * properly later as we are close to release. */
26 free_cache(!is_preview_render && !b_image.has_data())
27{
28}
29
31{
32 if (b_image.source() != BL::Image::source_TILED) {
33 /* Image sequence might have different dimensions, and hence needs to be handled in a special
34 * manner.
35 * NOTE: Currently the sequences are not handled by this image loader. */
36 assert(b_image.source() != BL::Image::source_SEQUENCE);
37
38 metadata.width = b_image.size()[0];
39 metadata.height = b_image.size()[1];
40 metadata.channels = b_image.channels();
41 }
42 else {
43 /* Different UDIM tiles might have different resolutions, so get resolution from the actual
44 * tile. */
45 BL::UDIMTile b_udim_tile = b_image.tiles.get(tile_number);
46 if (b_udim_tile) {
47 metadata.width = b_udim_tile.size()[0];
48 metadata.height = b_udim_tile.size()[1];
49 metadata.channels = b_udim_tile.channels();
50 }
51 else {
52 metadata.width = 0;
53 metadata.height = 0;
54 metadata.channels = 0;
55 }
56 }
57
58 metadata.depth = 1;
59
60 if (b_image.is_float()) {
61 if (metadata.channels == 1) {
62 metadata.type = IMAGE_DATA_TYPE_FLOAT;
63 }
64 else if (metadata.channels == 4) {
66 }
67 else {
68 return false;
69 }
70
71 /* Float images are already converted on the Blender side,
72 * no need to do anything in Cycles. */
74 }
75 else {
76 /* In some cases (e.g. #94135), the colorspace setting in Blender gets updated as part of the
77 * metadata queries in this function, so update the colorspace setting here. */
78 PointerRNA colorspace_ptr = b_image.colorspace_settings().ptr;
79 metadata.colorspace = get_enum_identifier(colorspace_ptr, "name");
80
81 if (metadata.channels == 1) {
82 metadata.type = IMAGE_DATA_TYPE_BYTE;
83 }
84 else if (metadata.channels == 4) {
85 metadata.type = IMAGE_DATA_TYPE_BYTE4;
86 }
87 else {
88 return false;
89 }
90 }
91
92 return true;
93}
94
96 void *out_pixels,
97 const size_t out_pixels_size,
98 const bool associate_alpha)
99{
100 const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
101 const int channels = metadata.channels;
102
103 if (metadata.type == IMAGE_DATA_TYPE_FLOAT || metadata.type == IMAGE_DATA_TYPE_FLOAT4) {
104 /* Float. */
106
107 if (in_pixels && num_pixels * channels == out_pixels_size) {
108 /* Straight copy pixel data. */
109 memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(float));
110 }
111 else {
112 /* Missing or invalid pixel data. */
113 if (channels == 1) {
114 memset(out_pixels, 0, num_pixels * sizeof(float));
115 }
116 else {
117 const size_t num_pixels_safe = out_pixels_size / channels;
118 float *out_pixel = (float *)out_pixels;
119 for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
120 out_pixel[0] = 1.0f;
121 out_pixel[1] = 0.0f;
122 out_pixel[2] = 1.0f;
123 if (channels == 4) {
124 out_pixel[3] = 1.0f;
125 }
126 }
127 }
128 }
129
130 if (in_pixels) {
131 MEM_freeN(in_pixels);
132 }
133 }
134 else if (metadata.type == IMAGE_DATA_TYPE_HALF || metadata.type == IMAGE_DATA_TYPE_HALF4) {
135 /* Half float. Blender does not have a half type, but in some cases
136 * we up-sample byte to half to avoid precision loss for colorspace
137 * conversion. */
138 unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
139
140 if (in_pixels && num_pixels * channels == out_pixels_size) {
141 /* Convert uchar to half. */
142 const uchar *in_pixel = in_pixels;
143 half *out_pixel = (half *)out_pixels;
144 if (associate_alpha && channels == 4) {
145 for (size_t i = 0; i < num_pixels; i++, in_pixel += 4, out_pixel += 4) {
146 const float alpha = util_image_cast_to_float(in_pixel[3]);
147 out_pixel[0] = float_to_half_image(util_image_cast_to_float(in_pixel[0]) * alpha);
148 out_pixel[1] = float_to_half_image(util_image_cast_to_float(in_pixel[1]) * alpha);
149 out_pixel[2] = float_to_half_image(util_image_cast_to_float(in_pixel[2]) * alpha);
150 out_pixel[3] = float_to_half_image(alpha);
151 }
152 }
153 else {
154 for (size_t i = 0; i < num_pixels; i++) {
155 for (int c = 0; c < channels; c++, in_pixel++, out_pixel++) {
156 *out_pixel = float_to_half_image(util_image_cast_to_float(*in_pixel));
157 }
158 }
159 }
160 }
161 else {
162 /* Missing or invalid pixel data. */
163 if (channels == 1) {
164 memset(out_pixels, 0, num_pixels * sizeof(half));
165 }
166 else {
167 const size_t num_pixels_safe = out_pixels_size / channels;
168 half *out_pixel = (half *)out_pixels;
169 for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
170 out_pixel[0] = float_to_half_image(1.0f);
171 out_pixel[1] = float_to_half_image(0.0f);
172 out_pixel[2] = float_to_half_image(1.0f);
173 if (channels == 4) {
174 out_pixel[3] = float_to_half_image(1.0f);
175 }
176 }
177 }
178 }
179
180 if (in_pixels) {
181 MEM_freeN(in_pixels);
182 }
183 }
184 else {
185 /* Byte. */
186 unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
187
188 if (in_pixels && num_pixels * channels == out_pixels_size) {
189 /* Straight copy pixel data. */
190 memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(unsigned char));
191
192 if (associate_alpha && channels == 4) {
193 /* Premultiply, byte images are always straight for Blender. */
194 unsigned char *out_pixel = (unsigned char *)out_pixels;
195 for (size_t i = 0; i < num_pixels; i++, out_pixel += 4) {
196 out_pixel[0] = (out_pixel[0] * out_pixel[3]) / 255;
197 out_pixel[1] = (out_pixel[1] * out_pixel[3]) / 255;
198 out_pixel[2] = (out_pixel[2] * out_pixel[3]) / 255;
199 }
200 }
201 }
202 else {
203 /* Missing or invalid pixel data. */
204 if (channels == 1) {
205 memset(out_pixels, 0, out_pixels_size * sizeof(unsigned char));
206 }
207 else {
208 const size_t num_pixels_safe = out_pixels_size / channels;
209 unsigned char *out_pixel = (unsigned char *)out_pixels;
210 for (size_t i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
211 out_pixel[0] = 255;
212 out_pixel[1] = 0;
213 out_pixel[2] = 255;
214 if (channels == 4) {
215 out_pixel[3] = 255;
216 }
217 }
218 }
219 }
220
221 if (in_pixels) {
222 MEM_freeN(in_pixels);
223 }
224 }
225
226 /* Free image buffers to save memory during render. */
227 if (free_cache) {
228 b_image.buffers_free();
229 }
230
231 return true;
232}
233
235{
236 return BL::Image(b_image).name();
237}
238
240{
241 const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
242 return b_image == other_loader.b_image && frame == other_loader.frame &&
243 tile_number == other_loader.tile_number;
244}
245
247{
248 return tile_number;
249}
250
251/* Point Density */
252
254 BL::ShaderNodeTexPointDensity b_node)
255 : b_depsgraph(b_depsgraph), b_node(b_node)
256{
257}
258
260{
261 metadata.channels = 4;
262 metadata.width = b_node.resolution();
263 metadata.height = metadata.width;
264 metadata.depth = metadata.width;
265 metadata.type = IMAGE_DATA_TYPE_FLOAT4;
266 return true;
267}
268
270 void *pixels,
271 const size_t,
272 const bool)
273{
274 int length;
275 b_node.calc_point_density(b_depsgraph, &length, (float **)&pixels);
276 return true;
277}
278
280{
281 /* Force builtin images to be loaded along with Blender data sync. This
282 * is needed because we may be reading from depsgraph evaluated data which
283 * can be freed by Blender before Cycles reads it.
284 *
285 * TODO: the assumption that no further access to builtin image data will
286 * happen is really weak, and likely to break in the future. We should find
287 * a better solution to hand over the data directly to the image manager
288 * instead of through callbacks whose timing is difficult to control. */
290 Device *device = session->device;
291 manager->device_load_builtin(device, session->scene, session->progress);
292}
293
295{
296 return BL::ShaderNodeTexPointDensity(b_node).name();
297}
298
300{
301 const BlenderPointDensityLoader &other_loader = (const BlenderPointDensityLoader &)other;
302 return b_node == other_loader.b_node && b_depsgraph == other_loader.b_depsgraph;
303}
304
unsigned char uchar
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override
bool load_pixels(const ImageMetaData &metadata, void *pixels, const size_t pixels_size, const bool associate_alpha) override
BlenderImageLoader(BL::Image b_image, const int frame, const int tile_number, const bool is_preview_render)
bool equals(const ImageLoader &other) const override
int get_tile_number() const override
string name() const override
bool equals(const ImageLoader &other) const override
BL::ShaderNodeTexPointDensity b_node
BlenderPointDensityLoader(BL::Depsgraph depsgraph, BL::ShaderNodeTexPointDensity b_node)
string name() const override
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override
bool load_pixels(const ImageMetaData &metadata, void *pixels, const size_t pixels_size, const bool associate_alpha) override
void device_load_builtin(Device *device, Scene *scene, Progress &progress)
ImageDataType type
Device * device
Progress progress
Scene * scene
Definition half.h:42
ustring u_colorspace_raw
static float * image_get_float_pixels_for_frame(BL::Image &image, int frame, int tile)
static string get_enum_identifier(PointerRNA &ptr, const char *name)
static unsigned char * image_get_pixels_for_frame(BL::Image &image, int frame, int tile)
float util_image_cast_to_float(T value)
#define CCL_NAMESPACE_END
ccl_device_inline half float_to_half_image(float f)
Definition half.h:71
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ImageManager * image_manager
Definition scene.h:140
@ IMAGE_DATA_TYPE_BYTE
@ IMAGE_DATA_TYPE_FLOAT
@ IMAGE_DATA_TYPE_FLOAT4
@ IMAGE_DATA_TYPE_HALF
@ IMAGE_DATA_TYPE_BYTE4
@ IMAGE_DATA_TYPE_HALF4