Blender  V3.3
util_gpu.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "imbuf.h"
9 
10 #include "BLI_math.h"
11 #include "BLI_utildefines.h"
12 #include "MEM_guardedalloc.h"
13 
14 #include "BKE_global.h"
15 
16 #include "GPU_capabilities.h"
17 #include "GPU_texture.h"
18 
19 #include "IMB_colormanagement.h"
20 #include "IMB_imbuf.h"
21 #include "IMB_imbuf_types.h"
22 
23 /* gpu ibuf utils */
24 
25 static void imb_gpu_get_format(const ImBuf *ibuf,
26  bool high_bitdepth,
27  eGPUDataFormat *r_data_format,
28  eGPUTextureFormat *r_texture_format)
29 {
30  const bool float_rect = (ibuf->rect_float != NULL);
31 
32  if (float_rect) {
33  /* Float. */
34  const bool use_high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
35  *r_data_format = GPU_DATA_FLOAT;
36  *r_texture_format = use_high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
37  }
38  else {
41  /* Non-color data or scene linear, just store buffer as is. */
42  *r_data_format = GPU_DATA_UBYTE;
43  *r_texture_format = GPU_RGBA8;
44  }
46  /* sRGB, store as byte texture that the GPU can decode directly. */
47  *r_data_format = GPU_DATA_UBYTE;
48  *r_texture_format = GPU_SRGB8_A8;
49  }
50  else {
51  /* Other colorspace, store as half float texture to avoid precision loss. */
52  *r_data_format = GPU_DATA_FLOAT;
53  *r_texture_format = GPU_RGBA16F;
54  }
55  }
56 }
57 
58 /* Return false if no suitable format was found. */
59 #ifdef WITH_DDS
60 static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
61 {
62  /* For DDS we only support data, scene linear and sRGB. Converting to
63  * different colorspace would break the compression. */
64  const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
66 
67  if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
68  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
69  }
70  else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
71  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
72  }
73  else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
74  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
75  }
76  else {
77  return false;
78  }
79  return true;
80 }
81 #endif
82 
87 static void *imb_gpu_get_data(const ImBuf *ibuf,
88  const bool do_rescale,
89  const int rescale_size[2],
90  const bool store_premultiplied,
91  bool *r_freedata)
92 {
93  const bool is_float_rect = (ibuf->rect_float != NULL);
94  void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
95  bool freedata = false;
96 
97  if (is_float_rect) {
98  /* Float image is already in scene linear colorspace or non-color data by
99  * convention, no colorspace conversion needed. But we do require 4 channels
100  * currently. */
101  if (ibuf->channels != 4 || !store_premultiplied) {
102  data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
103  *r_freedata = freedata = true;
104 
105  if (data_rect == NULL) {
106  return NULL;
107  }
108 
110  (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
111  }
112  }
113  else {
114  /* Byte image is in original colorspace from the file, and may need conversion.
115  *
116  * We must also convert to premultiplied for correct texture interpolation
117  * and consistency with float images. */
119  /* Non-color data, just store buffer as is. */
120  }
123  /* sRGB or scene linear, store as byte texture that the GPU can decode directly. */
124  data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
125  *r_freedata = freedata = true;
126 
127  if (data_rect == NULL) {
128  return NULL;
129  }
130 
131  /* Texture storage of images is defined by the alpha mode of the image. The
132  * downside of this is that there can be artifacts near alpha edges. However,
133  * this allows us to use sRGB texture formats and preserves color values in
134  * zero alpha areas, and appears generally closer to what game engines that we
135  * want to be compatible with do. */
137  (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
138  }
139  else {
140  /* Other colorspace, store as float texture to avoid precision loss. */
141  data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
142  *r_freedata = freedata = true;
143 
144  if (data_rect == NULL) {
145  return NULL;
146  }
147 
148  /* Texture storage of images is defined by the alpha mode of the image. The
149  * downside of this is that there can be artifacts near alpha edges. However,
150  * this allows us to use sRGB texture formats and preserves color values in
151  * zero alpha areas, and appears generally closer to what game engines that we
152  * want to be compatible with do. */
154  (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
155  }
156  }
157 
158  if (do_rescale) {
159  uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
160  float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
161 
162  ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
163  IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
164 
165  if (freedata) {
166  MEM_freeN(data_rect);
167  }
168 
169  data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
170  *r_freedata = true;
171  /* Steal the rescaled buffer to avoid double free. */
172  scale_ibuf->rect_float = NULL;
173  scale_ibuf->rect = NULL;
174  IMB_freeImBuf(scale_ibuf);
175  }
176  return data_rect;
177 }
178 
180  const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
181 {
182  eGPUDataFormat data_format;
183  eGPUTextureFormat tex_format;
184  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
185 
186  GPUTexture *tex;
187  if (layers > 0) {
188  tex = GPU_texture_create_2d_array(name, w, h, layers, 9999, tex_format, NULL);
189  }
190  else {
191  tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL);
192  }
193 
195  return tex;
196 }
197 
199  ImBuf *ibuf,
200  int x,
201  int y,
202  int z,
203  int w,
204  int h,
205  bool use_high_bitdepth,
206  bool use_premult)
207 {
208  const bool do_rescale = (ibuf->x != w || ibuf->y != h);
209  const int size[2] = {w, h};
210 
211  eGPUDataFormat data_format;
212  eGPUTextureFormat tex_format;
213  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
214 
215  bool freebuf = false;
216 
217  void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
218 
219  /* Update Texture. */
220  GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
221 
222  if (freebuf) {
223  MEM_freeN(data);
224  }
225 }
226 
228  ImBuf *ibuf,
229  bool use_high_bitdepth,
230  bool use_premult)
231 {
232  GPUTexture *tex = NULL;
234  bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
235 
236 #ifdef WITH_DDS
237  if (ibuf->ftype == IMB_FTYPE_DDS) {
238  eGPUTextureFormat compressed_format;
239  if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
240  fprintf(stderr, "Unable to find a suitable DXT compression,");
241  }
242  else if (do_rescale) {
243  fprintf(stderr, "Unable to load DXT image resolution,");
244  }
245  else if (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) {
246  fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
247  }
248  else {
250  ibuf->x,
251  ibuf->y,
252  ibuf->dds_data.nummipmaps,
253  compressed_format,
254  ibuf->dds_data.data);
255 
256  if (tex != NULL) {
257  return tex;
258  }
259 
260  fprintf(stderr, "ST3C support not found,");
261  }
262  /* Fallback to uncompressed texture. */
263  fprintf(stderr, " falling back to uncompressed.\n");
264  }
265 #endif
266 
267  eGPUDataFormat data_format;
268  eGPUTextureFormat tex_format;
269  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
270 
271  bool freebuf = false;
272 
273  /* Create Texture. */
274  tex = GPU_texture_create_2d(name, UNPACK2(size), 9999, tex_format, NULL);
275  if (tex == NULL) {
276  size[0] = max_ii(1, size[0] / 2);
277  size[1] = max_ii(1, size[1] / 2);
278  tex = GPU_texture_create_2d(name, UNPACK2(size), 9999, tex_format, NULL);
279  do_rescale = true;
280  }
281  BLI_assert(tex != NULL);
282  void *data = imb_gpu_get_data(ibuf, do_rescale, size, use_premult, &freebuf);
283  GPU_texture_update(tex, data_format, data);
284 
286 
287  if (freebuf) {
288  MEM_freeN(data);
289  }
290 
291  return tex;
292 }
293 
294 void IMB_gpu_clamp_half_float(ImBuf *image_buffer)
295 {
296  const float half_min = -65504;
297  const float half_max = 65504;
298  if (!image_buffer->rect_float) {
299  return;
300  }
301 
302  int rect_float_len = image_buffer->x * image_buffer->y *
303  (image_buffer->channels == 0 ? 4 : image_buffer->channels);
304 
305  for (int i = 0; i < rect_float_len; i++) {
306  image_buffer->rect_float[i] = clamp_f(image_buffer->rect_float[i], half_min, half_max);
307  }
308 }
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE float clamp_f(float value, float min, float max)
MINLINE int max_ii(int a, int b)
MINLINE int is_power_of_2_i(int n)
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK2(a)
static const uint FOURCC_DXT3
static const uint FOURCC_DXT5
static const uint FOURCC_DXT1
int GPU_texture_size_with_limit(int res)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble z
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
GPUTexture * GPU_texture_create_2d_array(const char *name, int w, int h, int d, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:297
void GPU_texture_update_sub(GPUTexture *tex, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
Definition: gpu_texture.cc:417
struct GPUTexture GPUTexture
Definition: GPU_texture.h:17
eGPUDataFormat
Definition: GPU_texture.h:170
@ GPU_DATA_UBYTE
Definition: GPU_texture.h:174
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:444
GPUTexture * GPU_texture_create_2d(const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:291
GPUTexture * GPU_texture_create_compressed_2d(const char *name, int w, int h, int miplen, eGPUTextureFormat format, const void *data)
Definition: gpu_texture.cc:336
eGPUTextureFormat
Definition: GPU_texture.h:83
@ GPU_SRGB8_A8
Definition: GPU_texture.h:121
@ GPU_SRGB8_A8_DXT5
Definition: GPU_texture.h:151
@ GPU_RGBA32F
Definition: GPU_texture.h:90
@ GPU_SRGB8_A8_DXT1
Definition: GPU_texture.h:149
@ GPU_RGBA8_DXT1
Definition: GPU_texture.h:152
@ GPU_SRGB8_A8_DXT3
Definition: GPU_texture.h:150
@ GPU_RGBA8_DXT3
Definition: GPU_texture.h:153
@ GPU_RGBA8_DXT5
Definition: GPU_texture.h:154
@ GPU_RGBA8
Definition: GPU_texture.h:87
void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso)
Definition: gpu_texture.cc:537
bool IMB_colormanagement_space_is_srgb(struct ColorSpace *colorspace)
bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace)
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, int offset_x, int offset_y, int width, int height, const struct ImBuf *ibuf, bool store_premultiplied)
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, int x, int y, int width, int height, const struct ImBuf *ibuf, bool store_premultiplied)
bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace)
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1644
struct ImBuf * IMB_allocFromBuffer(const unsigned int *rect, const float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:447
Contains defines and structs used throughout the imbuf module.
@ IB_halffloat
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img GPU_RGBA16F
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
unsigned int nummipmaps
unsigned char * data
unsigned int fourcc
struct DDSData dds_data
int channels
struct ColorSpace * rect_colorspace
enum eImbFileType ftype
unsigned int * rect
float * rect_float
GPUTexture * IMB_create_gpu_texture(const char *name, ImBuf *ibuf, bool use_high_bitdepth, bool use_premult)
Definition: util_gpu.c:227
void IMB_update_gpu_texture_sub(GPUTexture *tex, ImBuf *ibuf, int x, int y, int z, int w, int h, bool use_high_bitdepth, bool use_premult)
Definition: util_gpu.c:198
static void * imb_gpu_get_data(const ImBuf *ibuf, const bool do_rescale, const int rescale_size[2], const bool store_premultiplied, bool *r_freedata)
Definition: util_gpu.c:87
GPUTexture * IMB_touch_gpu_texture(const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
Definition: util_gpu.c:179
static void imb_gpu_get_format(const ImBuf *ibuf, bool high_bitdepth, eGPUDataFormat *r_data_format, eGPUTextureFormat *r_texture_format)
Definition: util_gpu.c:25
void IMB_gpu_clamp_half_float(ImBuf *image_buffer)
Definition: util_gpu.c:294