Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-07-29 05:55:21 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-07-29 16:03:02 +0300
commite749643793809248dfc6ffd078be04aec3eeab82 (patch)
treee9b12ab51205aeb344c17ebd0d38d21c76e7cd69
parente4ee9de63899e2da58cdfdd9cbf2ac5bb2e3755a (diff)
GPU: Refactor gpu_texture_image to not use GL calls
This is also a bit of code cleanup, reorganisation. Tried to be DRYed but avoid too much code change to (hopefully) minimize breakage. - GPU: remove TEXTARGET_CUBE_MAP, this is no longer used in the codebase. - GPUTexture: Move compressed texture upload to gpu_texture.cc - GPUTexture: Add per texture Anisotropic filtering switch
-rw-r--r--source/blender/gpu/GPU_draw.h10
-rw-r--r--source/blender/gpu/GPU_texture.h16
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc209
-rw-r--r--source/blender/gpu/intern/gpu_texture_image.cc1321
-rw-r--r--source/blender/gpu/intern/gpu_texture_smoke.cc1
-rw-r--r--source/blender/makesdna/DNA_image_types.h4
-rw-r--r--source/blender/makesdna/DNA_movieclip_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_environment.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c3
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c5
11 files changed, 559 insertions, 1021 deletions
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index 01af654b52f..8110920527d 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -42,23 +42,13 @@ struct Main;
/* Mipmap settings
* - these will free textures on changes */
-void GPU_set_mipmap(struct Main *bmain, bool mipmap);
-bool GPU_get_mipmap(void);
-void GPU_set_linear_mipmap(bool linear);
-bool GPU_get_linear_mipmap(void);
void GPU_paint_set_mipmap(struct Main *bmain, bool mipmap);
-/* Anisotropic filtering settings
- * - these will free textures on changes */
-void GPU_set_anisotropic(float value);
-float GPU_get_anisotropic(void);
-
/* Image updates and free
* - these deal with images bound as opengl textures */
void GPU_paint_update_image(
struct Image *ima, struct ImageUser *iuser, int x, int y, int w, int h);
-bool GPU_upload_dxt_texture(struct ImBuf *ibuf, bool use_srgb, uint *bindcode);
void GPU_free_image(struct Image *ima);
void GPU_free_images(struct Main *bmain);
void GPU_free_images_anim(struct Main *bmain);
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 6685e2a2171..42afe2b63bf 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -41,7 +41,6 @@ typedef struct GPUTexture GPUTexture;
/* Used to get the correct gpu texture from an Image datablock. */
typedef enum eGPUTextureTarget {
TEXTARGET_2D = 0,
- TEXTARGET_CUBE_MAP,
TEXTARGET_2D_ARRAY,
TEXTARGET_TILE_MAPPING,
TEXTARGET_COUNT,
@@ -131,7 +130,6 @@ typedef enum eGPUTextureFormat {
#if 0
GPU_RGB10_A2,
GPU_RGB10_A2UI,
- GPU_SRGB8_A8,
#endif
GPU_R11F_G11F_B10F,
GPU_DEPTH32F_STENCIL8,
@@ -160,7 +158,13 @@ typedef enum eGPUTextureFormat {
GPU_R8_SNORM,
#endif
-/* Special formats texture only */
+ /* Special formats texture only */
+ GPU_SRGB8_A8_DXT1,
+ GPU_SRGB8_A8_DXT3,
+ GPU_SRGB8_A8_DXT5,
+ GPU_RGBA8_DXT1,
+ GPU_RGBA8_DXT3,
+ GPU_RGBA8_DXT5,
#if 0
GPU_SRGB8,
GPU_RGB9_E5,
@@ -233,7 +237,10 @@ GPUTexture *GPU_texture_create_cube_array(
GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert);
GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer);
-GPUTexture *GPU_texture_from_bindcode(eGPUTextureTarget target, int bindcode);
+GPUTexture *GPU_texture_create_error(eGPUTextureTarget target);
+GPUTexture *GPU_texture_create_compressed(
+ int w, int h, int miplen, eGPUTextureFormat format, const void *data);
+
GPUTexture *GPU_texture_from_blender(struct Image *ima,
struct ImageUser *iuser,
struct ImBuf *ibuf,
@@ -279,6 +286,7 @@ void GPU_texture_unbind_all(void);
void GPU_texture_copy(GPUTexture *dst, GPUTexture *src);
void GPU_texture_generate_mipmap(GPUTexture *tex);
+void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso);
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare);
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter);
void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter);
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 2afba122cfd..db9d961e2e3 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_image_types.h"
+#include "DNA_userdef_types.h"
#include "BLI_blenlib.h"
#include "BLI_math_base.h"
@@ -439,6 +440,13 @@ static uint gpu_get_bytesize(eGPUTextureFormat data_type)
case GPU_R8:
case GPU_R8UI:
return 1;
+ case GPU_SRGB8_A8_DXT1:
+ case GPU_SRGB8_A8_DXT3:
+ case GPU_SRGB8_A8_DXT5:
+ case GPU_RGBA8_DXT1:
+ case GPU_RGBA8_DXT3:
+ case GPU_RGBA8_DXT5:
+ return 1; /* Incorrect but actual size is fractional. */
default:
BLI_assert(!"Texture format incorrect or unsupported\n");
return 0;
@@ -524,7 +532,18 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
case GPU_RGB16F:
return GL_RGB16F;
/* Special formats texture only */
- /* ** Add Format here */
+ case GPU_SRGB8_A8_DXT1:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
+ case GPU_SRGB8_A8_DXT3:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
+ case GPU_SRGB8_A8_DXT5:
+ return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
+ case GPU_RGBA8_DXT1:
+ return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ case GPU_RGBA8_DXT3:
+ return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ case GPU_RGBA8_DXT5:
+ return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
/* Depth Formats */
case GPU_DEPTH_COMPONENT32F:
return GL_DEPTH_COMPONENT32F;
@@ -538,99 +557,6 @@ static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
}
}
-static eGPUTextureFormat gl_internalformat_to_gpu_format(const GLint glformat)
-{
- /* You can add any of the available type to this list
- * For available types see GPU_texture.h */
- switch (glformat) {
- /* Formats texture & renderbuffer */
- case GL_RGBA8UI:
- return GPU_RGBA8UI;
- case GL_RGBA8I:
- return GPU_RGBA8I;
- case GL_RGBA8:
- return GPU_RGBA8;
- case GL_RGBA32UI:
- return GPU_RGBA32UI;
- case GL_RGBA32I:
- return GPU_RGBA32I;
- case GL_RGBA32F:
- return GPU_RGBA32F;
- case GL_RGBA16UI:
- return GPU_RGBA16UI;
- case GL_RGBA16I:
- return GPU_RGBA16I;
- case GL_RGBA16F:
- return GPU_RGBA16F;
- case GL_RGBA16:
- return GPU_RGBA16;
- case GL_RG8UI:
- return GPU_RG8UI;
- case GL_RG8I:
- return GPU_RG8I;
- case GL_RG8:
- return GPU_RG8;
- case GL_RG32UI:
- return GPU_RG32UI;
- case GL_RG32I:
- return GPU_RG32I;
- case GL_RG32F:
- return GPU_RG32F;
- case GL_RG16UI:
- return GPU_RG16UI;
- case GL_RG16I:
- return GPU_RG16I;
- case GL_RG16F:
- return GPU_RGBA32F;
- case GL_RG16:
- return GPU_RG16;
- case GL_R8UI:
- return GPU_R8UI;
- case GL_R8I:
- return GPU_R8I;
- case GL_R8:
- return GPU_R8;
- case GL_R32UI:
- return GPU_R32UI;
- case GL_R32I:
- return GPU_R32I;
- case GL_R32F:
- return GPU_R32F;
- case GL_R16UI:
- return GPU_R16UI;
- case GL_R16I:
- return GPU_R16I;
- case GL_R16F:
- return GPU_R16F;
- case GL_R16:
- return GPU_R16;
- /* Special formats texture & renderbuffer */
- case GL_R11F_G11F_B10F:
- return GPU_R11F_G11F_B10F;
- case GL_DEPTH32F_STENCIL8:
- return GPU_DEPTH32F_STENCIL8;
- case GL_DEPTH24_STENCIL8:
- return GPU_DEPTH24_STENCIL8;
- case GL_SRGB8_ALPHA8:
- return GPU_SRGB8_A8;
- /* Texture only format */
- case GL_RGB16F:
- return GPU_RGB16F;
- /* Special formats texture only */
- /* ** Add Format here */
- /* Depth Formats */
- case GL_DEPTH_COMPONENT32F:
- return GPU_DEPTH_COMPONENT32F;
- case GL_DEPTH_COMPONENT24:
- return GPU_DEPTH_COMPONENT24;
- case GL_DEPTH_COMPONENT16:
- return GPU_DEPTH_COMPONENT16;
- default:
- BLI_assert(!"Internal format incorrect or unsupported\n");
- return GPU_RGBA8;
- }
-}
-
static GLenum gpu_get_gl_datatype(eGPUDataFormat format)
{
switch (format) {
@@ -1197,8 +1123,6 @@ static GLenum convert_target_to_gl(eGPUTextureTarget target)
switch (target) {
case TEXTARGET_2D:
return GL_TEXTURE_2D;
- case TEXTARGET_CUBE_MAP:
- return GL_TEXTURE_CUBE_MAP;
case TEXTARGET_2D_ARRAY:
return GL_TEXTURE_2D_ARRAY;
case TEXTARGET_TILE_MAPPING:
@@ -1209,48 +1133,72 @@ static GLenum convert_target_to_gl(eGPUTextureTarget target)
}
}
-/* TODO(fclem) This function should be remove and gpu_texture_image rewritten to not use any GL
- * commands. */
-GPUTexture *GPU_texture_from_bindcode(eGPUTextureTarget target, int bindcode)
+/* Create an error texture that will bind an invalid texture (pink) at draw time. */
+GPUTexture *GPU_texture_create_error(eGPUTextureTarget target)
{
GLenum textarget = convert_target_to_gl(target);
GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
- tex->bindcode = bindcode;
+ tex->bindcode = 0;
tex->refcount = 1;
tex->target = textarget;
tex->target_base = textarget;
tex->samples = 0;
- tex->sampler_state = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO;
- if (GPU_get_mipmap()) {
- tex->sampler_state |= (GPU_SAMPLER_MIPMAP | GPU_SAMPLER_FILTER);
- }
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
tex->number = -1;
- if (!glIsTexture(tex->bindcode)) {
- GPU_print_error_debug("Blender Texture Not Loaded");
+ GPU_print_error_debug("Blender Texture Not Loaded");
+ return tex;
+}
+
+/* DDS texture loading. Return NULL if support is not available. */
+GPUTexture *GPU_texture_create_compressed(
+ int w, int h, int miplen, eGPUTextureFormat tex_format, const void *data)
+{
+ if (!GLEW_EXT_texture_compression_s3tc) {
+ return NULL;
}
- else {
- GLint w, h, gl_format;
- GLenum gettarget;
- gettarget = (textarget == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : textarget;
-
- glBindTexture(textarget, tex->bindcode);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h);
- glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_INTERNAL_FORMAT, &gl_format);
- tex->w = w;
- tex->h = h;
- tex->format = gl_internalformat_to_gpu_format(gl_format);
- tex->components = gpu_get_component_count(tex->format);
- glBindTexture(textarget, 0);
-
- /* Depending on how this bindcode was obtained, the memory used here could
- * already have been computed.
- * But that is not the case currently. */
- gpu_texture_memory_footprint_add(tex);
+
+ GPUTexture *tex = (GPUTexture *)MEM_callocN(sizeof(GPUTexture), __func__);
+ tex->w = w;
+ tex->h = h;
+ tex->refcount = 1;
+ tex->target = tex->target_base = GL_TEXTURE_2D;
+ tex->format_flag = static_cast<eGPUTextureFormatFlag>(0);
+ tex->components = gpu_get_component_count(tex_format);
+ tex->mipmaps = miplen - 1;
+ tex->sampler_state = GPU_SAMPLER_DEFAULT;
+ tex->number = -1;
+
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
+
+ glGenTextures(1, &tex->bindcode);
+ glBindTexture(tex->target, tex->bindcode);
+
+ /* Reset to opengl Defaults. (Untested, might not be needed) */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ int blocksize = (ELEM(tex_format, GPU_RGBA8_DXT1, GPU_SRGB8_A8_DXT1)) ? 8 : 16;
+
+ size_t ofs = 0;
+ for (int mip = 0; mip < miplen && (w || h); mip++, w >>= 1, h >>= 1) {
+ w = max_ii(1, w);
+ h = max_ii(1, h);
+ size_t size = ((w + 3) / 4) * ((h + 3) / 4) * blocksize;
+
+ glCompressedTexImage2D(tex->target, mip, internalformat, w, h, 0, size, (uchar *)data + ofs);
+
+ ofs += size;
}
+ /* Restore Blender default. */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexParameteri(tex->target, GL_TEXTURE_MAX_LEVEL, tex->mipmaps);
+ glTexParameteri(tex->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glBindTexture(tex->target, 0);
+
return tex;
}
@@ -1970,6 +1918,14 @@ void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter)
SET_FLAG_FROM_TEST(tex->sampler_state, use_filter, GPU_SAMPLER_FILTER);
}
+void GPU_texture_anisotropic_filter(GPUTexture *tex, bool use_aniso)
+{
+ /* Stencil and integer format does not support filtering. */
+ BLI_assert(!(use_aniso) || !(GPU_texture_stencil(tex) || GPU_texture_integer(tex)));
+
+ SET_FLAG_FROM_TEST(tex->sampler_state, use_aniso, GPU_SAMPLER_ANISO);
+}
+
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
{
SET_FLAG_FROM_TEST(tex->sampler_state, use_repeat, GPU_SAMPLER_REPEAT);
@@ -2194,8 +2150,9 @@ void GPU_samplers_init(void)
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
((state & GPU_SAMPLER_MIPMAP) ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
GLenum compare_mode = (state & GPU_SAMPLER_COMPARE) ? GL_COMPARE_REF_TO_TEXTURE : GL_NONE;
+ /* TODO(fclem) Anisotropic level should be a render engine parameter. */
float aniso_filter = ((state & GPU_SAMPLER_MIPMAP) && (state & GPU_SAMPLER_ANISO)) ?
- GPU_get_anisotropic() :
+ U.anisotropic_filter :
1.0f;
glSamplerParameteri(GG.samplers[i], GL_TEXTURE_WRAP_S, wrap_s);
diff --git a/source/blender/gpu/intern/gpu_texture_image.cc b/source/blender/gpu/intern/gpu_texture_image.cc
index 5b53ba0544b..cd422c6ee04 100644
--- a/source/blender/gpu/intern/gpu_texture_image.cc
+++ b/source/blender/gpu/intern/gpu_texture_image.cc
@@ -54,7 +54,6 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_texture.h"
@@ -63,22 +62,14 @@
static void gpu_free_image(Image *ima, const bool immediate);
static void gpu_free_unused_buffers(void);
-static void gpu_create_gl_tex_compressed(unsigned int *bind,
- eGPUTextureTarget textarget,
- Image *ima,
- ImBuf *ibuf);
-static void gpu_create_gl_tex(uint *bind,
- uint *rect,
- float *frect,
- int rectw,
- int recth,
- eGPUTextureTarget textarget,
- bool mipmap,
- bool half_float,
- bool use_srgb,
- Image *ima);
-
-//* Checking powers of two for images since OpenGL ES requires it */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility functions
+ * \{ */
+
+/** Checking powers of two for images since OpenGL ES requires it */
#ifdef WITH_DDS
static bool is_power_of_2_resolution(int w, int h)
{
@@ -86,9 +77,9 @@ static bool is_power_of_2_resolution(int w, int h)
}
#endif
-static bool is_over_resolution_limit(GLenum textarget, int w, int h)
+static bool is_over_resolution_limit(int w, int h)
{
- int size = (textarget == GL_TEXTURE_CUBE_MAP) ? GPU_max_cube_map_size() : GPU_max_texture_size();
+ int size = GPU_max_texture_size();
int reslimit = (U.glreslimit != 0) ? min_ii(U.glreslimit, size) : size;
return (w > reslimit || h > reslimit);
@@ -106,108 +97,177 @@ static int smaller_power_of_2_limit(int num)
return power_of_2_min_i(num);
}
-/* Current OpenGL state caching for GPU_set_tpage */
-
-static struct GPUTextureState {
- /* also controls min/mag filtering */
- bool domipmap;
- /* only use when 'domipmap' is set */
- bool linearmipmap;
- /* store this so that new images created while texture painting won't be set to mipmapped */
- bool texpaint;
-
- float anisotropic;
-} GTS = {1, 0, 0, 1.0f};
-
-/* Mipmap settings */
-
-void GPU_set_mipmap(Main *bmain, bool mipmap)
+static GPUTexture **gpu_get_image_gputexture(Image *ima,
+ eGPUTextureTarget textarget,
+ const int multiview_eye)
{
- if (GTS.domipmap != mipmap) {
- GPU_free_images(bmain);
- GTS.domipmap = mipmap;
+ const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
+ BLI_assert(in_range);
+
+ if (in_range) {
+ return &(ima->gputexture[textarget][multiview_eye]);
}
+ return NULL;
}
-void GPU_set_linear_mipmap(bool linear)
+static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
+ MovieClipUser *cuser,
+ eGPUTextureTarget textarget)
{
- if (GTS.linearmipmap != linear) {
- GTS.linearmipmap = linear;
+ LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) {
+ if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
+ if (tex == NULL) {
+ tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture),
+ __func__);
+
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ tex->gputexture[i] = NULL;
+ }
+
+ memcpy(&tex->user, cuser, sizeof(MovieClipUser));
+ BLI_addtail(&clip->runtime.gputextures, tex);
+ }
+
+ return &tex->gputexture[textarget];
+ }
}
+ return NULL;
}
-bool GPU_get_mipmap(void)
+/* Apply colormanagement and scale buffer if needed. */
+static void *get_ibuf_data(const Image *ima,
+ const ImBuf *ibuf,
+ const bool do_rescale,
+ const int rescale_size[2],
+ const bool compress_as_srgb,
+ bool *r_freebuf)
{
- return GTS.domipmap && !GTS.texpaint;
-}
+ const bool is_float_rect = (ibuf->rect_float != NULL);
+ void *data_rect = (is_float_rect) ? (void *)ibuf->rect_float : (void *)ibuf->rect;
-bool GPU_get_linear_mipmap(void)
-{
- return GTS.linearmipmap;
-}
+ if (is_float_rect) {
+ /* Float image is already in scene linear colorspace or non-color data by
+ * convention, no colorspace conversion needed. But we do require 4 channels
+ * currently. */
+ const bool store_premultiplied = ima ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
-static GLenum gpu_get_mipmap_filter(bool mag)
-{
- /* linearmipmap is off by default *when mipmapping is off,
- * use unfiltered display */
- if (mag) {
- if (GTS.domipmap) {
- return GL_LINEAR;
- }
- else {
- return GL_NEAREST;
+ if (ibuf->channels != 4 || !store_premultiplied) {
+ data_rect = MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
+ *r_freebuf = true;
+
+ if (data_rect == NULL) {
+ return NULL;
+ }
+
+ IMB_colormanagement_imbuf_to_float_texture(
+ (float *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
}
}
else {
- if (GTS.domipmap) {
- if (GTS.linearmipmap) {
- return GL_LINEAR_MIPMAP_LINEAR;
- }
- else {
- return GL_LINEAR_MIPMAP_NEAREST;
+ /* Byte image is in original colorspace from the file. If the file is sRGB
+ * scene linear, or non-color data no conversion is needed. Otherwise we
+ * compress as scene linear + sRGB transfer function to avoid precision loss
+ * in common cases.
+ *
+ * We must also convert to premultiplied for correct texture interpolation
+ * and consistency with float images. */
+ if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
+ data_rect = MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
+ *r_freebuf = true;
+
+ if (data_rect == NULL) {
+ return NULL;
}
- }
- else {
- return GL_NEAREST;
+
+ /* Texture storage of images is defined by the alpha mode of the image. The
+ * downside of this is that there can be artifacts near alpha edges. However,
+ * this allows us to use sRGB texture formats and preserves color values in
+ * zero alpha areas, and appears generally closer to what game engines that we
+ * want to be compatible with do. */
+ const bool store_premultiplied = ima ? (ima->alpha_mode == IMA_ALPHA_PREMUL) : true;
+ IMB_colormanagement_imbuf_to_byte_texture(
+ (uchar *)data_rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
}
}
-}
-/* Anisotropic filtering settings */
-void GPU_set_anisotropic(float value)
-{
- if (GTS.anisotropic != value) {
- GPU_samplers_free();
+ if (do_rescale) {
+ uint *rect = (is_float_rect) ? NULL : (uint *)data_rect;
+ float *rect_float = (is_float_rect) ? (float *)data_rect : NULL;
- /* Clamp value to the maximum value the graphics card supports */
- const float max = GPU_max_texture_anisotropy();
- if (value > max) {
- value = max;
- }
+ ImBuf *scale_ibuf = IMB_allocFromBuffer(rect, rect_float, ibuf->x, ibuf->y, 4);
+ IMB_scaleImBuf(scale_ibuf, UNPACK2(rescale_size));
- GTS.anisotropic = value;
-
- GPU_samplers_init();
+ data_rect = (is_float_rect) ? (void *)scale_ibuf->rect_float : (void *)scale_ibuf->rect;
+ *r_freebuf = true;
+ /* Steal the rescaled buffer to avoid double free. */
+ scale_ibuf->rect_float = NULL;
+ scale_ibuf->rect = NULL;
+ IMB_freeImBuf(scale_ibuf);
}
+ return data_rect;
}
-float GPU_get_anisotropic(void)
+static void get_texture_format_from_ibuf(const Image *ima,
+ const ImBuf *ibuf,
+ eGPUDataFormat *r_data_format,
+ eGPUTextureFormat *r_texture_format)
{
- return GTS.anisotropic;
+ const bool float_rect = (ibuf->rect_float != NULL);
+ const bool high_bitdepth = (!(ibuf->flags & IB_halffloat) && (ima->flag & IMA_HIGH_BITDEPTH));
+ const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
+ !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
+
+ *r_data_format = (float_rect) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+
+ if (float_rect) {
+ *r_texture_format = high_bitdepth ? GPU_RGBA32F : GPU_RGBA16F;
+ }
+ else {
+ *r_texture_format = use_srgb ? GPU_SRGB8_A8 : GPU_RGBA8;
+ }
}
-static GPUTexture **gpu_get_image_gputexture(Image *ima, int textarget, const int multiview_eye)
+/* Return false if no suitable format was found. */
+static bool get_texture_compressed_format_from_ibuf(const ImBuf *ibuf,
+ eGPUTextureFormat *r_data_format)
{
- const bool in_range = (textarget >= 0) && (textarget < TEXTARGET_COUNT);
- BLI_assert(in_range);
+#ifdef WITH_DDS
+ /* For DDS we only support data, scene linear and sRGB. Converting to
+ * different colorspace would break the compression. */
+ const bool use_srgb = (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace) &&
+ !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- if (in_range) {
- return &(ima->gputexture[textarget][multiview_eye]);
+ if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
+ *r_data_format = (use_srgb) ? GPU_SRGB8_A8_DXT1 : GPU_RGBA8_DXT1;
}
- return NULL;
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
+ *r_data_format = (use_srgb) ? GPU_SRGB8_A8_DXT3 : GPU_RGBA8_DXT3;
+ }
+ else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
+ *r_data_format = (use_srgb) ? GPU_SRGB8_A8_DXT5 : GPU_RGBA8_DXT5;
+ }
+ else {
+ return false;
+ }
+ return true;
+#else
+ return false;
+#endif
}
-static uint gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
+static bool mipmap_enabled(void)
+{
+ /* This used to be a userpref option. Maybe it will be re-introduce late. */
+ return true;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UDIM gpu texture
+ * \{ */
+
+static GPUTexture *gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
{
GPUTexture *tilearray = ima->gputexture[TEXTARGET_2D_ARRAY][multiview_eye];
@@ -223,10 +283,6 @@ static uint gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
int max_tile = last_tile->tile_number - 1001;
/* create image */
- int bindcode;
- glGenTextures(1, (GLuint *)&bindcode);
- glBindTexture(GL_TEXTURE_1D_ARRAY, bindcode);
-
int width = max_tile + 1;
float *data = (float *)MEM_callocN(width * 8 * sizeof(float), __func__);
for (int i = 0; i < width; i++) {
@@ -243,15 +299,12 @@ static uint gpu_texture_create_tile_mapping(Image *ima, const int multiview_eye)
tile_info[3] = tile->runtime.tilearray_size[1] / array_h;
}
- glTexImage2D(GL_TEXTURE_1D_ARRAY, 0, GL_RGBA32F, width, 2, 0, GL_RGBA, GL_FLOAT, data);
- MEM_freeN(data);
+ GPUTexture *tex = GPU_texture_create_1d_array(width, 2, GPU_RGBA32F, data, NULL);
+ GPU_texture_mipmap_mode(tex, false, false);
- glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_1D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- glBindTexture(GL_TEXTURE_1D_ARRAY, 0);
+ MEM_freeN(data);
- return bindcode;
+ return tex;
}
typedef struct PackTile {
@@ -268,10 +321,9 @@ static int compare_packtile(const void *a, const void *b)
return tile_a->pack_score < tile_b->pack_score;
}
-static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
+static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
{
int arraywidth = 0, arrayheight = 0;
-
ListBase boxes = {NULL};
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
@@ -286,8 +338,7 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
packtile->boxpack.w = ibuf->x;
packtile->boxpack.h = ibuf->y;
- if (is_over_resolution_limit(
- GL_TEXTURE_2D_ARRAY, packtile->boxpack.w, packtile->boxpack.h)) {
+ if (is_over_resolution_limit(packtile->boxpack.w, packtile->boxpack.h)) {
packtile->boxpack.w = smaller_power_of_2_limit(packtile->boxpack.w);
packtile->boxpack.h = smaller_power_of_2_limit(packtile->boxpack.h);
}
@@ -330,38 +381,17 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
arraylayers++;
}
- /* create image */
- int bindcode;
- glGenTextures(1, (GLuint *)&bindcode);
- glBindTexture(GL_TEXTURE_2D_ARRAY, bindcode);
+ eGPUDataFormat data_format;
+ eGPUTextureFormat tex_format;
+ get_texture_format_from_ibuf(ima, main_ibuf, &data_format, &tex_format);
- GLenum data_type, internal_format;
- if (main_ibuf->rect_float) {
- data_type = GL_FLOAT;
- internal_format = (!(main_ibuf->flags & IB_halffloat) && (ima->flag & IMA_HIGH_BITDEPTH)) ?
- GL_RGBA32F :
- GL_RGBA16F;
- }
- else {
- data_type = GL_UNSIGNED_BYTE;
- internal_format = GL_RGBA8;
- if (!IMB_colormanagement_space_is_data(main_ibuf->rect_colorspace) &&
- !IMB_colormanagement_space_is_scene_linear(main_ibuf->rect_colorspace)) {
- internal_format = GL_SRGB8_ALPHA8;
- }
- }
+ /* Create Texture. */
+ GPUTexture *tex = GPU_texture_create_nD(
+ arraywidth, arrayheight, arraylayers, 2, NULL, tex_format, data_format, 0, false, NULL);
- glTexImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- internal_format,
- arraywidth,
- arrayheight,
- arraylayers,
- 0,
- GL_RGBA,
- data_type,
- NULL);
+ GPU_texture_bind(tex, 0);
+ /* Upload each tile one by one. */
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
int tilelayer = tile->runtime.tilearray_layer;
int *tileoffset = tile->runtime.tilearray_offset;
@@ -377,209 +407,226 @@ static uint gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf)
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL);
if (ibuf) {
- bool needs_scale = (ibuf->x != tilesize[0] || ibuf->y != tilesize[1]);
-
- ImBuf *scale_ibuf = NULL;
- if (ibuf->rect_float) {
- float *rect_float = ibuf->rect_float;
-
- const bool store_premultiplied = ima->alpha_mode != IMA_ALPHA_STRAIGHT;
- if (ibuf->channels != 4 || !store_premultiplied) {
- rect_float = (float *)MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
- IMB_colormanagement_imbuf_to_float_texture(
- rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
- }
-
- float *pixeldata = rect_float;
- if (needs_scale) {
- scale_ibuf = IMB_allocFromBuffer(NULL, rect_float, ibuf->x, ibuf->y, 4);
- IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
- pixeldata = scale_ibuf->rect_float;
- }
+ const bool needs_scale = (ibuf->x != tilesize[0] || ibuf->y != tilesize[1]);
+ const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
+ bool freebuf = false;
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- tileoffset[0],
- tileoffset[1],
- tilelayer,
- tilesize[0],
- tilesize[1],
- 1,
- GL_RGBA,
- GL_FLOAT,
- pixeldata);
-
- if (rect_float != ibuf->rect_float) {
- MEM_freeN(rect_float);
- }
- }
- else {
- unsigned int *rect = ibuf->rect;
-
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- rect = (uint *)MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
- IMB_colormanagement_imbuf_to_byte_texture((uchar *)rect,
- 0,
- 0,
- ibuf->x,
- ibuf->y,
- ibuf,
- internal_format == GL_SRGB8_ALPHA8,
- ima->alpha_mode == IMA_ALPHA_PREMUL);
- }
+ void *pixeldata = get_ibuf_data(
+ ima, ibuf, needs_scale, tilesize, compress_as_srgb, &freebuf);
+ GPU_texture_update_sub(
+ tex, data_format, pixeldata, UNPACK2(tileoffset), tilelayer, UNPACK2(tilesize), 1);
- unsigned int *pixeldata = rect;
- if (needs_scale) {
- scale_ibuf = IMB_allocFromBuffer(rect, NULL, ibuf->x, ibuf->y, 4);
- IMB_scaleImBuf(scale_ibuf, tilesize[0], tilesize[1]);
- pixeldata = scale_ibuf->rect;
- }
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- tileoffset[0],
- tileoffset[1],
- tilelayer,
- tilesize[0],
- tilesize[1],
- 1,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- pixeldata);
-
- if (rect != ibuf->rect) {
- MEM_freeN(rect);
- }
- }
- if (scale_ibuf != NULL) {
- IMB_freeImBuf(scale_ibuf);
+ if (freebuf) {
+ MEM_SAFE_FREE(pixeldata);
}
}
BKE_image_release_ibuf(ima, ibuf, NULL);
}
- if (GPU_get_mipmap()) {
- glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ if (mipmap_enabled()) {
+ GPU_texture_generate_mipmap(tex);
if (ima) {
ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
}
- glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
+ GPU_texture_unbind(tex);
- return bindcode;
+ return tex;
}
-static uint gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf, eGPUTextureTarget textarget)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Regular gpu texture
+ * \{ */
+
+static GPUTexture *gpu_texture_create_from_ibuf(Image *ima, ImBuf *ibuf)
{
- uint bindcode = 0;
- const bool mipmap = GPU_get_mipmap();
- const bool half_float = (ibuf->flags & IB_halffloat) != 0;
+ GPUTexture *tex = NULL;
+ bool do_rescale = is_over_resolution_limit(ibuf->x, ibuf->y);
#ifdef WITH_DDS
if (ibuf->ftype == IMB_FTYPE_DDS) {
- /* DDS is loaded directly in compressed form. */
- gpu_create_gl_tex_compressed(&bindcode, textarget, ima, ibuf);
- return bindcode;
+ eGPUTextureFormat compressed_format;
+ if (!get_texture_compressed_format_from_ibuf(ibuf, &compressed_format)) {
+ fprintf(stderr, "Unable to find a suitable DXT compression,");
+ }
+ else if (do_rescale) {
+ fprintf(stderr, "Unable to load DXT image resolution,");
+ }
+ else if (!is_power_of_2_resolution(ibuf->x, ibuf->y)) {
+ fprintf(stderr, "Unable to load non-power-of-two DXT image resolution,");
+ }
+ else {
+ tex = GPU_texture_create_compressed(
+ ibuf->x, ibuf->y, ibuf->dds_data.nummipmaps, compressed_format, ibuf->dds_data.data);
+
+ if (tex != NULL) {
+ return tex;
+ }
+ else {
+ fprintf(stderr, "ST3C support not found,");
+ }
+ }
+ /* Fallback to uncompressed texture. */
+ fprintf(stderr, " falling back to uncompressed.\n");
}
#else
- (void)gpu_create_gl_tex_compressed;
+ (void)get_texture_compressed_format_from_ibuf;
#endif
- /* Regular uncompressed texture. */
- float *rect_float = ibuf->rect_float;
- uchar *rect = (uchar *)ibuf->rect;
- bool compress_as_srgb = false;
+ eGPUDataFormat data_format;
+ eGPUTextureFormat tex_format;
+ get_texture_format_from_ibuf(ima, ibuf, &data_format, &tex_format);
- if (rect_float == NULL) {
- /* Byte image is in original colorspace from the file. If the file is sRGB
- * scene linear, or non-color data no conversion is needed. Otherwise we
- * compress as scene linear + sRGB transfer function to avoid precision loss
- * in common cases.
- *
- * We must also convert to premultiplied for correct texture interpolation
- * and consistency with float images. */
- if (!IMB_colormanagement_space_is_data(ibuf->rect_colorspace)) {
- compress_as_srgb = !IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace);
+ int size[2] = {ibuf->x, ibuf->y};
+ if (do_rescale) {
+ size[0] = smaller_power_of_2_limit(size[0]);
+ size[1] = smaller_power_of_2_limit(size[1]);
+ }
- rect = (uchar *)MEM_mallocN(sizeof(uchar) * 4 * ibuf->x * ibuf->y, __func__);
- if (rect == NULL) {
- return bindcode;
- }
+ const bool compress_as_srgb = (tex_format == GPU_SRGB8_A8);
+ bool freebuf = false;
- /* Texture storage of images is defined by the alpha mode of the image. The
- * downside of this is that there can be artifacts near alpha edges. However,
- * this allows us to use sRGB texture formats and preserves color values in
- * zero alpha areas, and appears generally closer to what game engines that we
- * want to be compatible with do. */
- const bool store_premultiplied = ima ? (ima->alpha_mode == IMA_ALPHA_PREMUL) : true;
- IMB_colormanagement_imbuf_to_byte_texture(
- rect, 0, 0, ibuf->x, ibuf->y, ibuf, compress_as_srgb, store_premultiplied);
+ void *data = get_ibuf_data(ima, ibuf, do_rescale, size, compress_as_srgb, &freebuf);
+
+ /* Create Texture. */
+ tex = GPU_texture_create_nD(UNPACK2(size), 0, 2, data, tex_format, data_format, 0, false, NULL);
+
+ GPU_texture_anisotropic_filter(tex, true);
+
+ if (mipmap_enabled()) {
+ GPU_texture_bind(tex, 0);
+ GPU_texture_generate_mipmap(tex);
+ GPU_texture_unbind(tex);
+ if (ima) {
+ ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
}
+ GPU_texture_mipmap_mode(tex, true, true);
}
else {
- /* Float image is already in scene linear colorspace or non-color data by
- * convention, no colorspace conversion needed. But we do require 4 channels
- * currently. */
- const bool store_premultiplied = ima ? (ima->alpha_mode != IMA_ALPHA_STRAIGHT) : false;
+ GPU_texture_mipmap_mode(tex, false, true);
+ }
- if (ibuf->channels != 4 || !store_premultiplied) {
- rect_float = (float *)MEM_mallocN(sizeof(float) * 4 * ibuf->x * ibuf->y, __func__);
- if (rect_float == NULL) {
- return bindcode;
- }
- IMB_colormanagement_imbuf_to_float_texture(
- rect_float, 0, 0, ibuf->x, ibuf->y, ibuf, store_premultiplied);
- }
+ if (freebuf) {
+ MEM_SAFE_FREE(data);
}
- /* Create OpenGL texture. */
- gpu_create_gl_tex(&bindcode,
- (uint *)rect,
- rect_float,
- ibuf->x,
- ibuf->y,
- textarget,
- mipmap,
- half_float,
- compress_as_srgb,
- ima);
+ return tex;
+}
- /* Free buffers if needed. */
- if (rect && rect != (uchar *)ibuf->rect) {
- MEM_freeN(rect);
+/* Get the GPUTexture for a given `Image`.
+ *
+ * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
+ * available. It is also required when requesting the GPUTexture for a render result. */
+GPUTexture *GPU_texture_from_blender(Image *ima,
+ ImageUser *iuser,
+ ImBuf *ibuf,
+ eGPUTextureTarget textarget)
+{
+#ifndef GPU_STANDALONE
+ if (ima == NULL) {
+ return NULL;
}
- if (rect_float && rect_float != ibuf->rect_float) {
- MEM_freeN(rect_float);
+
+ /* Free any unused GPU textures, since we know we are in a thread with OpenGL
+ * context and might as well ensure we have as much space free as possible. */
+ gpu_free_unused_buffers();
+
+ /* currently, gpu refresh tagging is used by ima sequences */
+ if (ima->gpuflag & IMA_GPU_REFRESH) {
+ gpu_free_image(ima, true);
+ ima->gpuflag &= ~IMA_GPU_REFRESH;
+ }
+
+ /* Tag as in active use for garbage collector. */
+ BKE_image_tag_time(ima);
+
+ /* Test if we already have a texture. */
+ GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0);
+ if (*tex) {
+ return *tex;
+ }
+
+ /* Check if we have a valid image. If not, we return a dummy
+ * texture with zero bindcode so we don't keep trying. */
+ ImageTile *tile = BKE_image_get_tile(ima, 0);
+ if (tile == NULL || tile->ok == 0) {
+ *tex = GPU_texture_create_error(textarget);
+ return *tex;
+ }
+
+ /* check if we have a valid image buffer */
+ ImBuf *ibuf_intern = ibuf;
+ if (ibuf_intern == NULL) {
+ ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ if (ibuf_intern == NULL) {
+ *tex = GPU_texture_create_error(textarget);
+ return *tex;
+ }
+ }
+
+ if (textarget == TEXTARGET_2D_ARRAY) {
+ *tex = gpu_texture_create_tile_array(ima, ibuf_intern);
+ }
+ else if (textarget == TEXTARGET_TILE_MAPPING) {
+ *tex = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
+ }
+ else {
+ *tex = gpu_texture_create_from_ibuf(ima, ibuf_intern);
+ }
+
+ /* if `ibuf` was given, we don't own the `ibuf_intern` */
+ if (ibuf == NULL) {
+ BKE_image_release_ibuf(ima, ibuf_intern, NULL);
}
- return bindcode;
+ GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
+
+ return *tex;
+#endif
+ return NULL;
}
-static GPUTexture **gpu_get_movieclip_gputexture(MovieClip *clip,
- MovieClipUser *cuser,
- eGPUTextureTarget textarget)
+GPUTexture *GPU_texture_from_movieclip(MovieClip *clip,
+ MovieClipUser *cuser,
+ eGPUTextureTarget textarget)
{
- LISTBASE_FOREACH (MovieClip_RuntimeGPUTexture *, tex, &clip->runtime.gputextures) {
- if (memcmp(&tex->user, cuser, sizeof(MovieClipUser)) == 0) {
- if (tex == NULL) {
- tex = (MovieClip_RuntimeGPUTexture *)MEM_mallocN(sizeof(MovieClip_RuntimeGPUTexture),
- __func__);
-
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- tex->gputexture[i] = NULL;
- }
+#ifndef GPU_STANDALONE
+ if (clip == NULL) {
+ return NULL;
+ }
- memcpy(&tex->user, cuser, sizeof(MovieClipUser));
- BLI_addtail(&clip->runtime.gputextures, tex);
- }
+ GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, textarget);
+ if (*tex) {
+ return *tex;
+ }
- return &tex->gputexture[textarget];
- }
+ /* check if we have a valid image buffer */
+ ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
+ if (ibuf == NULL) {
+ *tex = GPU_texture_create_error(textarget);
+ return *tex;
}
+
+ *tex = gpu_texture_create_from_ibuf(NULL, ibuf);
+
+ IMB_freeImBuf(ibuf);
+
+ return *tex;
+#else
return NULL;
+#endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Update
+ * \{ */
+
static ImBuf *update_do_scale(uchar *rect,
float *rect_float,
int *x,
@@ -619,108 +666,70 @@ static ImBuf *update_do_scale(uchar *rect,
return ibuf;
}
-static void gpu_texture_update_scaled_array(uchar *rect,
- float *rect_float,
- int full_w,
- int full_h,
- int x,
- int y,
- int layer,
- const int *tile_offset,
- const int *tile_size,
- int w,
- int h)
+static void gpu_texture_update_scaled(GPUTexture *tex,
+ uchar *rect,
+ float *rect_float,
+ int full_w,
+ int full_h,
+ int x,
+ int y,
+ int layer,
+ const int *tile_offset,
+ const int *tile_size,
+ int w,
+ int h)
{
- ImBuf *ibuf = update_do_scale(
- rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
-
- /* Shift to account for tile packing. */
- x += tile_offset[0];
- y += tile_offset[1];
+ ImBuf *ibuf;
+ if (layer > -1) {
+ ibuf = update_do_scale(
+ rect, rect_float, &x, &y, &w, &h, tile_size[0], tile_size[1], full_w, full_h);
- if (ibuf->rect_float) {
- glTexSubImage3D(
- GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+ /* Shift to account for tile packing. */
+ x += tile_offset[0];
+ y += tile_offset[1];
}
else {
- glTexSubImage3D(
- GL_TEXTURE_2D_ARRAY, 0, x, y, layer, w, h, 1, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- }
-
- IMB_freeImBuf(ibuf);
-}
+ /* Partial update with scaling. */
+ int limit_w = smaller_power_of_2_limit(full_w);
+ int limit_h = smaller_power_of_2_limit(full_h);
-static void gpu_texture_update_scaled(
- uchar *rect, float *rect_float, int full_w, int full_h, int x, int y, int w, int h)
-{
- /* Partial update with scaling. */
- int limit_w = smaller_power_of_2_limit(full_w);
- int limit_h = smaller_power_of_2_limit(full_h);
+ ibuf = update_do_scale(rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
+ }
- ImBuf *ibuf = update_do_scale(
- rect, rect_float, &x, &y, &w, &h, limit_w, limit_h, full_w, full_h);
+ void *data = (ibuf->rect_float) ? (void *)(ibuf->rect_float) : (void *)(ibuf->rect);
+ eGPUDataFormat data_format = (ibuf->rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
- if (ibuf->rect_float) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, ibuf->rect_float);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- }
+ GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
IMB_freeImBuf(ibuf);
}
-static void gpu_texture_update_unscaled(uchar *rect,
+static void gpu_texture_update_unscaled(GPUTexture *tex,
+ uchar *rect,
float *rect_float,
int x,
int y,
int layer,
+ const int tile_offset[2],
int w,
int h,
- GLint tex_stride,
- GLint tex_offset)
+ int tex_stride,
+ int tex_offset)
{
+ if (layer > -1) {
+ /* Shift to account for tile packing. */
+ x += tile_offset[0];
+ y += tile_offset[1];
+ }
+
+ void *data = (rect_float) ? (void *)(rect_float + tex_offset) : (void *)(rect + tex_offset);
+ eGPUDataFormat data_format = (rect_float) ? GPU_DATA_FLOAT : GPU_DATA_UNSIGNED_BYTE;
+
/* Partial update without scaling. Stride and offset are used to copy only a
* subset of a possible larger buffer than what we are updating. */
GPU_unpack_row_length_set(tex_stride);
- if (layer >= 0) {
- if (rect_float == NULL) {
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- x,
- y,
- layer,
- w,
- h,
- 1,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- rect + tex_offset);
- }
- else {
- glTexSubImage3D(GL_TEXTURE_2D_ARRAY,
- 0,
- x,
- y,
- layer,
- w,
- h,
- 1,
- GL_RGBA,
- GL_FLOAT,
- rect_float + tex_offset);
- }
- }
- else {
- if (rect_float == NULL) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect + tex_offset);
- }
- else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA, GL_FLOAT, rect_float + tex_offset);
- }
- }
-
+ GPU_texture_update_sub(tex, data_format, data, x, y, layer, w, h, 1);
/* Restore default. */
GPU_unpack_row_length_set(0);
}
@@ -738,7 +747,7 @@ static void gpu_texture_update_from_ibuf(
scaled = (ibuf->x != tilesize[0]) || (ibuf->y != tilesize[1]);
}
else {
- scaled = is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y);
+ scaled = is_over_resolution_limit(ibuf->x, ibuf->y);
}
if (scaled) {
@@ -755,8 +764,8 @@ static void gpu_texture_update_from_ibuf(
/* Get texture data pointers. */
float *rect_float = ibuf->rect_float;
uchar *rect = (uchar *)ibuf->rect;
- GLint tex_stride = ibuf->x;
- GLint tex_offset = ibuf->channels * (y * ibuf->x + x);
+ int tex_stride = ibuf->x;
+ int tex_offset = ibuf->channels * (y * ibuf->x + x);
if (rect_float == NULL) {
/* Byte pixels. */
@@ -803,11 +812,12 @@ static void gpu_texture_update_from_ibuf(
int *tileoffset = tile->runtime.tilearray_offset;
int *tilesize = tile->runtime.tilearray_size;
int tilelayer = tile->runtime.tilearray_layer;
- gpu_texture_update_scaled_array(
- rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
+ gpu_texture_update_scaled(
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, tilelayer, tileoffset, tilesize, w, h);
}
else {
- gpu_texture_update_scaled(rect, rect_float, ibuf->x, ibuf->y, x, y, w, h);
+ gpu_texture_update_scaled(
+ tex, rect, rect_float, ibuf->x, ibuf->y, x, y, -1, NULL, NULL, w, h);
}
}
else {
@@ -815,18 +825,12 @@ static void gpu_texture_update_from_ibuf(
if (tile != NULL) {
int *tileoffset = tile->runtime.tilearray_offset;
int tilelayer = tile->runtime.tilearray_layer;
- gpu_texture_update_unscaled(rect,
- rect_float,
- x + tileoffset[0],
- y + tileoffset[1],
- tilelayer,
- w,
- h,
- tex_stride,
- tex_offset);
+ gpu_texture_update_unscaled(
+ tex, rect, rect_float, x, y, tilelayer, tileoffset, w, h, tex_stride, tex_offset);
}
else {
- gpu_texture_update_unscaled(rect, rect_float, x, y, -1, w, h, tex_stride, tex_offset);
+ gpu_texture_update_unscaled(
+ tex, rect, rect_float, x, y, -1, NULL, w, h, tex_stride, tex_offset);
}
}
@@ -838,8 +842,8 @@ static void gpu_texture_update_from_ibuf(
MEM_freeN(rect_float);
}
- if (GPU_get_mipmap()) {
- glGenerateMipmap((tile != NULL) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D);
+ if (mipmap_enabled()) {
+ GPU_texture_generate_mipmap(tex);
}
else {
ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
@@ -848,425 +852,30 @@ static void gpu_texture_update_from_ibuf(
GPU_texture_unbind(tex);
}
-/* Get the GPUTexture for a given `Image`.
- *
- * `iuser` and `ibuf` are mutual exclusive parameters. The caller can pass the `ibuf` when already
- * available. It is also required when requesting the GPUTexture for a render result. */
-GPUTexture *GPU_texture_from_blender(Image *ima,
- ImageUser *iuser,
- ImBuf *ibuf,
- eGPUTextureTarget textarget)
-{
-#ifndef GPU_STANDALONE
- if (ima == NULL) {
- return NULL;
- }
-
- /* Free any unused GPU textures, since we know we are in a thread with OpenGL
- * context and might as well ensure we have as much space free as possible. */
- gpu_free_unused_buffers();
-
- /* currently, gpu refresh tagging is used by ima sequences */
- if (ima->gpuflag & IMA_GPU_REFRESH) {
- gpu_free_image(ima, true);
- ima->gpuflag &= ~IMA_GPU_REFRESH;
- }
-
- /* Tag as in active use for garbage collector. */
- BKE_image_tag_time(ima);
-
- /* Test if we already have a texture. */
- GPUTexture **tex = gpu_get_image_gputexture(ima, textarget, iuser ? iuser->multiview_eye : 0);
- if (*tex) {
- return *tex;
- }
-
- /* Check if we have a valid image. If not, we return a dummy
- * texture with zero bindcode so we don't keep trying. */
- uint bindcode = 0;
- ImageTile *tile = BKE_image_get_tile(ima, 0);
- if (tile == NULL || tile->ok == 0) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
-
- /* check if we have a valid image buffer */
- ImBuf *ibuf_intern = ibuf;
- if (ibuf_intern == NULL) {
- ibuf_intern = BKE_image_acquire_ibuf(ima, iuser, NULL);
- if (ibuf_intern == NULL) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
- }
-
- if (textarget == TEXTARGET_2D_ARRAY) {
- bindcode = gpu_texture_create_tile_array(ima, ibuf_intern);
- }
- else if (textarget == TEXTARGET_TILE_MAPPING) {
- bindcode = gpu_texture_create_tile_mapping(ima, iuser ? iuser->multiview_eye : 0);
- }
- else {
- bindcode = gpu_texture_create_from_ibuf(ima, ibuf_intern, textarget);
- }
-
- /* if `ibuf` was given, we don't own the `ibuf_intern` */
- if (ibuf == NULL) {
- BKE_image_release_ibuf(ima, ibuf_intern, NULL);
- }
-
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
-
- GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y);
-
- if (textarget == TEXTARGET_TILE_MAPPING) {
- /* Special for tile mapping. */
- GPU_texture_mipmap_mode(*tex, false, false);
- }
-
- return *tex;
-#endif
- return NULL;
-}
-
-GPUTexture *GPU_texture_from_movieclip(MovieClip *clip,
- MovieClipUser *cuser,
- eGPUTextureTarget textarget)
+void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
{
#ifndef GPU_STANDALONE
- if (clip == NULL) {
- return NULL;
- }
-
- GPUTexture **tex = gpu_get_movieclip_gputexture(clip, cuser, textarget);
- if (*tex) {
- return *tex;
- }
-
- /* check if we have a valid image buffer */
- uint bindcode = 0;
- ImBuf *ibuf = BKE_movieclip_get_ibuf(clip, cuser);
- if (ibuf == NULL) {
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
- }
-
- bindcode = gpu_texture_create_from_ibuf(NULL, ibuf, textarget);
- IMB_freeImBuf(ibuf);
-
- *tex = GPU_texture_from_bindcode(textarget, bindcode);
- return *tex;
-#else
- return NULL;
-#endif
-}
-
-void GPU_free_texture_movieclip(struct MovieClip *clip)
-{
- /* number of gpu textures to keep around as cache
- * We don't want to keep too many GPU textures for
- * movie clips around, as they can be large.*/
- const int MOVIECLIP_NUM_GPUTEXTURES = 1;
-
- while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
- MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead(
- &clip->runtime.gputextures);
- for (int i = 0; i < TEXTARGET_COUNT; i++) {
- /* free glsl image binding */
- if (tex->gputexture[i]) {
- GPU_texture_free(tex->gputexture[i]);
- tex->gputexture[i] = NULL;
- }
- }
- MEM_freeN(tex);
- }
-}
-
-static void **gpu_gen_cube_map(uint *rect, float *frect, int rectw, int recth)
-{
- size_t block_size = frect ? sizeof(float[4]) : sizeof(uchar[4]);
- void **sides = NULL;
- int h = recth / 2;
- int w = rectw / 3;
-
- if (w != h) {
- return sides;
- }
-
- /* PosX, NegX, PosY, NegY, PosZ, NegZ */
- sides = (void **)MEM_mallocN(sizeof(void *) * 6, "");
- for (int i = 0; i < 6; i++) {
- sides[i] = MEM_mallocN(block_size * w * h, "");
- }
-
- /* divide image into six parts */
- /* ______________________
- * | | | |
- * | NegX | NegY | PosX |
- * |______|______|______|
- * | | | |
- * | NegZ | PosZ | PosY |
- * |______|______|______|
- */
- if (frect) {
- float(*frectb)[4] = (float(*)[4])frect;
- float(**fsides)[4] = (float(**)[4])sides;
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- memcpy(&fsides[0][x * h + y], &frectb[(recth - y - 1) * rectw + 2 * w + x], block_size);
- memcpy(&fsides[1][x * h + y], &frectb[(y + h) * rectw + w - 1 - x], block_size);
- memcpy(
- &fsides[3][y * w + x], &frectb[(recth - y - 1) * rectw + 2 * w - 1 - x], block_size);
- memcpy(&fsides[5][y * w + x], &frectb[(h - y - 1) * rectw + w - 1 - x], block_size);
- }
- memcpy(&fsides[2][y * w], frectb[y * rectw + 2 * w], block_size * w);
- memcpy(&fsides[4][y * w], frectb[y * rectw + w], block_size * w);
- }
- }
- else {
- uint **isides = (uint **)sides;
-
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- isides[0][x * h + y] = rect[(recth - y - 1) * rectw + 2 * w + x];
- isides[1][x * h + y] = rect[(y + h) * rectw + w - 1 - x];
- isides[3][y * w + x] = rect[(recth - y - 1) * rectw + 2 * w - 1 - x];
- isides[5][y * w + x] = rect[(h - y - 1) * rectw + w - 1 - x];
- }
- memcpy(&isides[2][y * w], &rect[y * rectw + 2 * w], block_size * w);
- memcpy(&isides[4][y * w], &rect[y * rectw + w], block_size * w);
- }
- }
-
- return sides;
-}
-
-static void gpu_del_cube_map(void **cube_map)
-{
- int i;
- if (cube_map == NULL) {
- return;
- }
- for (i = 0; i < 6; i++) {
- MEM_freeN(cube_map[i]);
- }
- MEM_freeN(cube_map);
-}
-
-/* Image *ima can be NULL */
-static void gpu_create_gl_tex(uint *bind,
- uint *rect,
- float *frect,
- int rectw,
- int recth,
- eGPUTextureTarget target,
- bool mipmap,
- bool half_float,
- bool use_srgb,
- Image *ima)
-{
- GLenum textarget = (target == TEXTARGET_2D) ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP;
-
- ImBuf *ibuf = NULL;
-
- if (textarget == GL_TEXTURE_2D && is_over_resolution_limit(textarget, rectw, recth)) {
- int tpx = rectw;
- int tpy = recth;
- rectw = smaller_power_of_2_limit(rectw);
- recth = smaller_power_of_2_limit(recth);
-
- if (frect) {
- ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy, 4);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- frect = ibuf->rect_float;
- }
- else {
- ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy, 4);
- IMB_scaleImBuf(ibuf, rectw, recth);
-
- rect = ibuf->rect;
- }
- }
-
- /* create image */
- glGenTextures(1, (GLuint *)bind);
- glBindTexture(textarget, *bind);
-
- GLenum float_format = (!half_float && (ima && (ima->flag & IMA_HIGH_BITDEPTH))) ? GL_RGBA32F :
- GL_RGBA16F;
- GLenum internal_format = (frect) ? float_format : (use_srgb) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
-
- if (textarget == GL_TEXTURE_2D) {
- if (frect) {
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_FLOAT, frect);
- }
- else {
- glTexImage2D(
- GL_TEXTURE_2D, 0, internal_format, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- }
-
- if (GPU_get_mipmap() && mipmap) {
- glGenerateMipmap(GL_TEXTURE_2D);
- if (ima) {
- ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
- }
- }
- }
- else if (textarget == GL_TEXTURE_CUBE_MAP) {
- int w = rectw / 3, h = recth / 2;
-
- if (h == w && is_power_of_2_i(h) && !is_over_resolution_limit(textarget, h, w)) {
- void **cube_map = gpu_gen_cube_map(rect, frect, rectw, recth);
- GLenum type = frect ? GL_FLOAT : GL_UNSIGNED_BYTE;
-
- if (cube_map) {
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
- 0,
- internal_format,
- w,
- h,
- 0,
- GL_RGBA,
- type,
- cube_map[i]);
- }
- }
-
- if (GPU_get_mipmap() && mipmap) {
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
-
- if (ima) {
- ima->gpuflag |= IMA_GPU_MIPMAP_COMPLETE;
- }
- }
-
- gpu_del_cube_map(cube_map);
- }
- else {
- printf("Incorrect envmap size\n");
- }
- }
-
- glBindTexture(textarget, 0);
-
- if (ibuf) {
- IMB_freeImBuf(ibuf);
- }
-}
-
-/**
- * Returns false if the provided ImBuf doesn't have a supported DXT compression format
- */
-bool GPU_upload_dxt_texture(ImBuf *ibuf, bool use_srgb, uint *bindcode)
-{
-#ifdef WITH_DDS
- glGenTextures(1, (GLuint *)bindcode);
- glBindTexture(GL_TEXTURE_2D, *bindcode);
-
- GLint format = 0;
- int blocksize, height, width, i, size, offset = 0;
-
- width = ibuf->x;
- height = ibuf->y;
-
- if (GLEW_EXT_texture_compression_s3tc) {
- if (ibuf->dds_data.fourcc == FOURCC_DXT1) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- }
- else if (ibuf->dds_data.fourcc == FOURCC_DXT3) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- }
- else if (ibuf->dds_data.fourcc == FOURCC_DXT5) {
- format = (use_srgb) ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT :
- GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- }
- }
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+ ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
- if (format == 0) {
- fprintf(stderr, "Unable to find a suitable DXT compression, falling back to uncompressed\n");
- glDeleteTextures(1, (GLuint *)bindcode);
- return false;
+ if ((ibuf == NULL) || (w == 0) || (h == 0)) {
+ /* Full reload of texture. */
+ GPU_free_image(ima);
}
- if (!is_power_of_2_resolution(width, height)) {
- fprintf(
- stderr,
- "Unable to load non-power-of-two DXT image resolution, falling back to uncompressed\n");
- glDeleteTextures(1, (GLuint *)bindcode);
- return false;
+ GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
+ /* Check if we need to update the main gputexture. */
+ if (tex != NULL && tile == ima->tiles.first) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
-
- /* Reset to opengl Defaults. (Untested, might not be needed) */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
-
- blocksize = (ibuf->dds_data.fourcc == FOURCC_DXT1) ? 8 : 16;
- for (i = 0; i < ibuf->dds_data.nummipmaps && (width || height); i++) {
- if (width == 0) {
- width = 1;
- }
- if (height == 0) {
- height = 1;
- }
-
- size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
-
- glCompressedTexImage2D(
- GL_TEXTURE_2D, i, format, width, height, 0, size, ibuf->dds_data.data + offset);
-
- offset += size;
- width >>= 1;
- height >>= 1;
+ /* Check if we need to update the array gputexture. */
+ tex = ima->gputexture[TEXTARGET_2D_ARRAY][0];
+ if (tex != NULL) {
+ gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
}
- /* Restore Blender default. */
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- /* set number of mipmap levels we have, needed in case they don't go down to 1x1 */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i - 1);
- glBindTexture(GL_TEXTURE_2D, 0);
- return true;
-#else
- UNUSED_VARS(ibuf, use_srgb, bindcode);
- return false;
-#endif
-}
-
-static void gpu_create_gl_tex_compressed(unsigned int *bind,
- eGPUTextureTarget textarget,
- Image *ima,
- ImBuf *ibuf)
-{
- /* For DDS we only support data, scene linear and sRGB. Converting to
- * different colorspace would break the compression. */
- const bool use_srgb = !(IMB_colormanagement_space_is_data(ibuf->rect_colorspace) ||
- IMB_colormanagement_space_is_scene_linear(ibuf->rect_colorspace));
- const bool mipmap = GPU_get_mipmap();
- const bool half_float = (ibuf->flags & IB_halffloat) != 0;
-
-#ifndef WITH_DDS
- (void)ibuf;
- /* Fall back to uncompressed if DDS isn't enabled */
- gpu_create_gl_tex(
- bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, half_float, use_srgb, ima);
-#else
-
- if (textarget == TEXTARGET_2D) {
- if (GPU_upload_dxt_texture(ibuf, use_srgb, bind)) {
- /* All went fine! */
- return;
- }
- }
- /* Fallback. */
- gpu_create_gl_tex(
- bind, ibuf->rect, NULL, ibuf->x, ibuf->y, textarget, mipmap, half_float, use_srgb, ima);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
#endif
}
@@ -1277,95 +886,40 @@ static void gpu_create_gl_tex_compressed(unsigned int *bind,
void GPU_paint_set_mipmap(Main *bmain, bool mipmap)
{
#ifndef GPU_STANDALONE
- if (!GTS.domipmap) {
- return;
- }
-
- GTS.texpaint = !mipmap;
-
- if (mipmap) {
-
- LISTBASE_FOREACH (Image *, ima, &bmain->images) {
- if (BKE_image_has_opengl_texture(ima)) {
- if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
- for (int eye = 0; eye < 2; eye++) {
- for (int a = 0; a < TEXTARGET_COUNT; a++) {
- if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
- GPUTexture *tex = ima->gputexture[a][eye];
- if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gpu_get_mipmap_filter(0));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(tex);
- }
- }
- }
- }
- }
- else {
- GPU_free_image(ima);
- }
- }
- else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
- }
- }
- }
- else {
- LISTBASE_FOREACH (Image *, ima, &bmain->images) {
- if (BKE_image_has_opengl_texture(ima)) {
+ LISTBASE_FOREACH (Image *, ima, &bmain->images) {
+ if (BKE_image_has_opengl_texture(ima)) {
+ if (ima->gpuflag & IMA_GPU_MIPMAP_COMPLETE) {
for (int eye = 0; eye < 2; eye++) {
for (int a = 0; a < TEXTARGET_COUNT; a++) {
if (ELEM(a, TEXTARGET_2D, TEXTARGET_2D_ARRAY)) {
GPUTexture *tex = ima->gputexture[a][eye];
if (tex != NULL) {
- GPU_texture_bind(tex, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gpu_get_mipmap_filter(1));
- GPU_texture_unbind(tex);
+ GPU_texture_mipmap_mode(tex, mipmap, true);
}
}
}
}
}
else {
- ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ GPU_free_image(ima);
}
}
+ else {
+ ima->gpuflag &= ~IMA_GPU_MIPMAP_COMPLETE;
+ }
}
#endif /* GPU_STANDALONE */
}
-void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h)
-{
-#ifndef GPU_STANDALONE
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
- ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser);
+/** \} */
- if ((ibuf == NULL) || (w == 0) || (h == 0)) {
- /* Full reload of texture. */
- GPU_free_image(ima);
- }
-
- GPUTexture *tex = ima->gputexture[TEXTARGET_2D][0];
- /* Check if we need to update the main gputexture. */
- if (tex != NULL && tile == ima->tiles.first) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, NULL, x, y, w, h);
- }
-
- /* Check if we need to update the array gputexture. */
- tex = ima->gputexture[TEXTARGET_2D_ARRAY][0];
- if (tex != NULL) {
- gpu_texture_update_from_ibuf(tex, ima, ibuf, tile, x, y, w, h);
- }
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-#endif
-}
+/* -------------------------------------------------------------------- */
+/** \name Delayed GPU texture free
+ *
+ * Image datablocks can be deleted by any thread, but there may not be any active OpenGL context.
+ * In that case we push them into a queue and free the buffers later.
+ * \{ */
-/* Delayed GPU texture free. Image datablocks can be deleted by any thread,
- * but there may not be any active OpenGL context. In that case we push them
- * into a queue and free the buffers later. */
static LinkNode *gpu_texture_free_queue = NULL;
static ThreadMutex gpu_texture_queue_mutex = BLI_MUTEX_INITIALIZER;
@@ -1388,6 +942,12 @@ static void gpu_free_unused_buffers()
BLI_mutex_unlock(&gpu_texture_queue_mutex);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Deletion
+ * \{ */
+
static void gpu_free_image(Image *ima, const bool immediate)
{
for (int eye = 0; eye < 2; eye++) {
@@ -1422,6 +982,27 @@ void GPU_free_image(Image *ima)
gpu_free_image(ima, BLI_thread_is_main());
}
+void GPU_free_texture_movieclip(struct MovieClip *clip)
+{
+ /* number of gpu textures to keep around as cache
+ * We don't want to keep too many GPU textures for
+ * movie clips around, as they can be large.*/
+ const int MOVIECLIP_NUM_GPUTEXTURES = 1;
+
+ while (BLI_listbase_count(&clip->runtime.gputextures) > MOVIECLIP_NUM_GPUTEXTURES) {
+ MovieClip_RuntimeGPUTexture *tex = (MovieClip_RuntimeGPUTexture *)BLI_pophead(
+ &clip->runtime.gputextures);
+ for (int i = 0; i < TEXTARGET_COUNT; i++) {
+ /* free glsl image binding */
+ if (tex->gputexture[i]) {
+ GPU_texture_free(tex->gputexture[i]);
+ tex->gputexture[i] = NULL;
+ }
+ }
+ MEM_freeN(tex);
+ }
+}
+
void GPU_free_images(Main *bmain)
{
if (bmain) {
@@ -1478,3 +1059,5 @@ void GPU_free_images_old(Main *bmain)
}
}
}
+
+/** \} */
diff --git a/source/blender/gpu/intern/gpu_texture_smoke.cc b/source/blender/gpu/intern/gpu_texture_smoke.cc
index 0f5aa361fa7..13273dba444 100644
--- a/source/blender/gpu/intern/gpu_texture_smoke.cc
+++ b/source/blender/gpu/intern/gpu_texture_smoke.cc
@@ -36,7 +36,6 @@
#include "BKE_colorband.h"
#include "GPU_draw.h"
-#include "GPU_glew.h"
#include "GPU_texture.h"
#ifdef WITH_FLUID
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 20357fc1099..7be244d7ddc 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -125,8 +125,8 @@ typedef struct Image {
/** Not written in file. */
struct MovieCache *cache;
- /** Not written in file 4 = TEXTARGET_COUNT, 2 = stereo eyes. */
- struct GPUTexture *gputexture[4][2];
+ /** Not written in file 3 = TEXTARGET_COUNT, 2 = stereo eyes. */
+ struct GPUTexture *gputexture[3][2];
/* sources from: */
ListBase anims;
diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h
index d750a7f3148..063e5d8af09 100644
--- a/source/blender/makesdna/DNA_movieclip_types.h
+++ b/source/blender/makesdna/DNA_movieclip_types.h
@@ -64,8 +64,8 @@ typedef struct MovieClipProxy {
typedef struct MovieClip_RuntimeGPUTexture {
void *next, *prev;
MovieClipUser user;
- /** Not written in file 4 = TEXTARGET_COUNT. */
- struct GPUTexture *gputexture[4];
+ /** Not written in file 3 = TEXTARGET_COUNT. */
+ struct GPUTexture *gputexture[3];
} MovieClip_RuntimeGPUTexture;
typedef struct MovieClip_Runtime {
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index bfc020afb41..b13b9f5c11d 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -190,6 +190,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = {
# include "GPU_draw.h"
# include "GPU_extensions.h"
# include "GPU_select.h"
+# include "GPU_texture.h"
# include "BLF_api.h"
@@ -363,7 +364,8 @@ static void rna_userdef_load_ui_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
static void rna_userdef_anisotropic_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
- GPU_set_anisotropic(U.anisotropic_filter);
+ GPU_samplers_free();
+ GPU_samplers_init();
rna_userdef_update(bmain, scene, ptr);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
index 0cf4b51f307..771b7d5920a 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c
@@ -59,7 +59,8 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat,
NodeTexImage *tex_original = node_original->storage;
ImageUser *iuser = &tex_original->iuser;
eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
- if (GPU_get_mipmap()) {
+ /* TODO(fclem) For now assume mipmap is always enabled. */
+ if (true) {
sampler |= GPU_SAMPLER_MIPMAP;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index cbda72cd228..ff2ecf785d7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -95,7 +95,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
if (tex->interpolation != SHD_INTERP_CLOSEST) {
sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
- sampler_state |= GPU_get_mipmap() ? GPU_SAMPLER_MIPMAP : 0;
+ /* TODO(fclem) For now assume mipmap is always enabled. */
+ sampler_state |= true ? GPU_SAMPLER_MIPMAP : 0;
}
const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 945d5fd42e4..a757b0fabd2 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -171,7 +171,7 @@ void WM_init_state_start_with_console_set(bool value)
*/
static bool opengl_is_init = false;
-void WM_init_opengl(Main *bmain)
+void WM_init_opengl(Main *UNUSED(bmain))
{
/* must be called only once */
BLI_assert(opengl_is_init == false);
@@ -185,9 +185,6 @@ void WM_init_opengl(Main *bmain)
DRW_opengl_context_create();
GPU_init();
- GPU_set_mipmap(bmain, true);
- GPU_set_linear_mipmap(true);
- GPU_set_anisotropic(U.anisotropic_filter);
GPU_pass_cache_init();