Blender  V2.93
util_gpu.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * util.c
19  */
20 
25 #include "imbuf.h"
26 
27 #include "BLI_math.h"
28 #include "BLI_utildefines.h"
29 #include "MEM_guardedalloc.h"
30 
31 #include "BKE_global.h"
32 
33 #include "GPU_capabilities.h"
34 #include "GPU_texture.h"
35 
36 #include "IMB_colormanagement.h"
37 #include "IMB_imbuf.h"
38 #include "IMB_imbuf_types.h"
39 
40 /* gpu ibuf utils */
41 
42 static void imb_gpu_get_format(const ImBuf *ibuf,
43  bool high_bitdepth,
44  eGPUDataFormat *r_data_format,
45  eGPUTextureFormat *r_texture_format)
46 {
47  const bool float_rect = (ibuf->rect_float != NULL);
48  const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
50  high_bitdepth = (!(ibuf->flags & IB_halffloat) && high_bitdepth);
51 
52  *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
53 
54  if (float_rect) {
55  *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
56  }
57  else {
58  *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
59  }
60 }
61 
62 /* Return false if no suitable format was found. */
63 #ifdef WITH_DDS
64 static bool IMB_gpu_get_compressed_format(const ImBuf *ibuf, eGPUTextureFormat *r_texture_format)
65 {
66  /* For DDS we only support data, scene linear and sRGB. Converting to
67  * different colorspace would break the compression. */
68  const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
70 
71  if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
72  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
73  }
74  else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
75  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
76  }
77  else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
78  *r_texture_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
79  }
80  else {
81  return false;
82  }
83  return true;
84 }
85 #endif
86 
91 static void *imb_gpu_get_data(const ImBuf *ibuf,
92  const bool do_rescale,
93  const int rescale_size[2],
94  const bool compress_as_srgb,
95  const bool store_premultiplied,
96  bool *r_freedata)
97 {
98  const bool is_float_rect = (ibuf->rect_float != NULL);
99  void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
100  bool freedata = false;
101 
102  if (is_float_rect) {
103  /* Float image is already in scene linear colorspace or non-color data by
104  * convention, no colorspace conversion needed. But we do require 4 channels
105  * currently. */
106  if (ibuf->channels != 4 || !store_premultiplied) {
107  data_rect = MEM_mallocN(sizeof(float[4]) * ibuf->x * ibuf->y, __func__);
108  *r_freedata = freedata = true;
109 
110  if (data_rect == NULL) {
111  return NULL;
112  }
113 
115  (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
116  }
117  }
118  else {
119  /* Byte image is in original colorspace from the file. If the file is sRGB
120  * scene linear, or non-color data no conversion is needed. Otherwise we
121  * compress as scene linear + sRGB transfer function to avoid precision loss
122  * in common cases.
123  *
124  * We must also convert to premultiplied for correct texture interpolation
125  * and consistency with float images. */
127  data_rect = MEM_mallocN(sizeof(uchar[4]) * ibuf->x * ibuf->y, __func__);
128  *r_freedata = freedata = true;
129 
130  if (data_rect == NULL) {
131  return NULL;
132  }
133 
134  /* Texture storage of images is defined by the alpha mode of the image. The
135  * downside of this is that there can be artifacts near alpha edges. However,
136  * this allows us to use sRGB texture formats and preserves color values in
137  * zero alpha areas, and appears generally closer to what game engines that we
138  * want to be compatible with do. */
140  (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
141  }
142  }
143 
144  if (do_rescale) {
145  uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
146  float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
147 
148  ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
149  IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
150 
151  if (freedata) {
152  MEM_freeN(data_rect);
153  }
154 
155  data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
156  *r_freedata = true;
157  /* Steal the rescaled buffer to avoid double free. */
158  scale_ibuf->rect_float = NULL;
159  scale_ibuf->rect = NULL;
160  IMB_freeImBuf(scale_ibuf);
161  }
162  return data_rect;
163 }
164 
165 /* The ibuf is only here to detect the storage type. The produced texture will have undefined
166  * content. It will need to be populated by using IMB_update_gpu_texture_sub(). */
168  const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
169 {
170  eGPUDataFormat data_format;
171  eGPUTextureFormat tex_format;
172  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
173 
174  GPUTexture *tex;
175  if (layers > 0) {
176  tex = GPU_texture_create_2d_array(name, w, h, layers, 1, tex_format, NULL);
177  }
178  else {
179  tex = GPU_texture_create_2d(name, w, h, 9999, tex_format, NULL);
180  }
181 
183  return tex;
184 }
185 
186 /* Will update a GPUTexture using the content of the ImBuf. Only one layer will be updated.
187  * Will resize the ibuf if needed.
188  * z is the layer to update. Unused if the texture is 2D. */
190  ImBuf *ibuf,
191  int x,
192  int y,
193  int z,
194  int w,
195  int h,
196  bool use_high_bitdepth,
197  bool use_premult)
198 {
199  const bool do_rescale = (ibuf->x != w || ibuf->y != h);
200  const int size[2] = {w, h};
201 
202  eGPUDataFormat data_format;
203  eGPUTextureFormat tex_format;
204  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
205 
206  const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
207  bool freebuf = false;
208 
209  void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
210 
211  /* Update Texture. */
212  GPU_texture_update_sub(tex, data_format, data, x, y, z, w, h, 1);
213 
214  if (freebuf) {
215  MEM_freeN(data);
216  }
217 }
218 
220  ImBuf *ibuf,
221  bool use_high_bitdepth,
222  bool use_premult,
223  bool limit_gl_texture_size)
224 {
225  GPUTexture *tex = NULL;
226  int size[2] = {GPU_texture_size_with_limit(ibuf->x, limit_gl_texture_size),
227  GPU_texture_size_with_limit(ibuf->y, limit_gl_texture_size)};
228  bool do_rescale = (ibuf->x != size[0]) || (ibuf->y != size[1]);
229 
230 #ifdef WITH_DDS
231  if (ibuf->ftype == IMB_FTYPE_DDS) {
232  eGPUTextureFormat compressed_format;
233  if (!IMB_gpu_get_compressed_format(ibuf, &compressed_format)) {
234  fprintf(stderr, "Unable to find a suitable DXT compression,");
235  }
236  else if (do_rescale) {
237  fprintf(stderr, "Unable to load DXT image resolution,");
238  }
239  else if (!is_power_of_2_i(ibuf->x) || !is_power_of_2_i(ibuf->y)) {
240  fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
241  }
242  else {
244  ibuf->x,
245  ibuf->y,
246  ibuf->dds_data.nummipmaps,
247  compressed_format,
248  ibuf->dds_data.data);
249 
250  if (tex != NULL) {
251  return tex;
252  }
253 
254  fprintf(stderr, "ST3C support not found,");
255  }
256  /* Fallback to uncompressed texture. */
257  fprintf(stderr, " falling back to uncompressed.\n");
258  }
259 #endif
260 
261  eGPUDataFormat data_format;
262  eGPUTextureFormat tex_format;
263  imb_gpu_get_format(ibuf, use_high_bitdepth, &data_format, &tex_format);
264 
265  const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
266  bool freebuf = false;
267 
268  /* Create Texture. */
269  tex = GPU_texture_create_2d(name, UNPACK2(size), 9999, tex_format, NULL);
270  if (tex == NULL) {
271  size[0] = max_ii(1, size[0] / 2);
272  size[1] = max_ii(1, size[1] / 2);
273  tex = GPU_texture_create_2d(name, UNPACK2(size), 9999, tex_format, NULL);
274  do_rescale = true;
275  }
276  BLI_assert(tex != NULL);
277  void *data = imb_gpu_get_data(ibuf, do_rescale, size, compress_as_srgb, use_premult, &freebuf);
278  GPU_texture_update(tex, data_format, data);
279 
281 
282  if (freebuf) {
283  MEM_freeN(data);
284  }
285 
286  return tex;
287 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:86
unsigned int uint
Definition: BLI_sys_types.h:83
#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, bool limit_gl_texture_size)
_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:256
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:356
struct GPUTexture GPUTexture
Definition: GPU_texture.h:33
eGPUDataFormat
Definition: GPU_texture.h:171
@ GPU_DATA_UBYTE
Definition: GPU_texture.h:175
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:172
void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:391
GPUTexture * GPU_texture_create_2d(const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:250
GPUTexture * GPU_texture_create_compressed_2d(const char *name, int w, int h, int miplen, eGPUTextureFormat format, const void *data)
Definition: gpu_texture.cc:290
eGPUTextureFormat
Definition: GPU_texture.h:84
@ GPU_SRGB8_A8
Definition: GPU_texture.h:122
@ GPU_SRGB8_A8_DXT5
Definition: GPU_texture.h:152
@ GPU_RGBA32F
Definition: GPU_texture.h:91
@ GPU_RGBA16F
Definition: GPU_texture.h:94
@ GPU_SRGB8_A8_DXT1
Definition: GPU_texture.h:150
@ GPU_RGBA8_DXT1
Definition: GPU_texture.h:153
@ GPU_SRGB8_A8_DXT3
Definition: GPU_texture.h:151
@ GPU_RGBA8_DXT3
Definition: GPU_texture.h:154
@ GPU_RGBA8_DXT5
Definition: GPU_texture.h:155
@ GPU_RGBA8
Definition: GPU_texture.h:88
void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso)
Definition: gpu_texture.cc:487
bool IMB_colormanagement_space_is_scene_linear(struct ColorSpace *colorspace)
void IMB_colormanagement_imbuf_to_byte_texture(unsigned char *out_buffer, const int x, const int y, const int width, const int height, const struct ImBuf *ibuf, const bool compress_as_srgb, const bool store_premultiplied)
bool IMB_colormanagement_space_is_data(struct ColorSpace *colorspace)
void IMB_colormanagement_imbuf_to_float_texture(float *out_buffer, const int offset_x, const int offset_y, const int width, const int height, const struct ImBuf *ibuf, const bool store_premultiplied)
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1667
void IMB_freeImBuf(struct ImBuf *ibuf)
Definition: allocimbuf.c:211
struct ImBuf * IMB_allocFromBuffer(const unsigned int *rect, const float *rectf, unsigned int w, unsigned int h, unsigned int channels)
Definition: allocimbuf.c:433
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
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
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
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:189
static void * imb_gpu_get_data(const ImBuf *ibuf, const bool do_rescale, const int rescale_size[2], const bool compress_as_srgb, const bool store_premultiplied, bool *r_freedata)
Definition: util_gpu.c:91
GPUTexture * IMB_touch_gpu_texture(const char *name, ImBuf *ibuf, int w, int h, int layers, bool use_high_bitdepth)
Definition: util_gpu.c:167
GPUTexture * IMB_create_gpu_texture(const char *name, ImBuf *ibuf, bool use_high_bitdepth, bool use_premult, bool limit_gl_texture_size)
Definition: util_gpu.c:219
static void imb_gpu_get_format(const ImBuf *ibuf, bool high_bitdepth, eGPUDataFormat *r_data_format, eGPUTextureFormat *r_texture_format)
Definition: util_gpu.c:42