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:
authorGermano Cavalcante <germano.costa@ig.com.br>2020-03-24 18:09:39 +0300
committerGermano Cavalcante <germano.costa@ig.com.br>2020-03-24 18:13:26 +0300
commitd626ced6f1fe8284737aecdabe70b48a42563b75 (patch)
treef689357de7747f744e70c9532a6bf05b4affc9d6
parent28c3d952dbde6f1e911360f716cb1cdb65863b5e (diff)
GPU: Estimate a better value for the memory used
This commit adds a `mipmaps` member to the `GPUTexture` struct and also computes to the memory used by these mipmaps and the memory used for textures that are created from an external bindcode. So it solves the following inconsistencies: - The memory value for mipmaps was not being computed. - As `GPU_texture_from_bindcode` didn't call `gpu_texture_memory_footprint_add`, it brought inconsistencies to the value of the used memory, especially when the texture is freed. Differential Revision: https://developer.blender.org/D3554
-rw-r--r--source/blender/gpu/intern/gpu_texture.c254
1 files changed, 200 insertions, 54 deletions
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c
index 088cf912d6a..a2afac0580e 100644
--- a/source/blender/gpu/intern/gpu_texture.c
+++ b/source/blender/gpu/intern/gpu_texture.c
@@ -82,7 +82,7 @@ struct GPUTexture {
eGPUTextureFormat format;
eGPUTextureFormatFlag format_flag;
- uint bytesize; /* number of byte for one pixel */
+ int mipmaps; /* number of mipmaps */
int components; /* number of color/alpha channels */
int samples; /* number of samples for multisamples textures. 0 if not multisample target */
@@ -90,6 +90,8 @@ struct GPUTexture {
GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED];
};
+static uint gpu_get_bytesize(eGPUTextureFormat data_type);
+
/* ------ Memory Management ------- */
/* Records every texture allocation / free
* to estimate the Texture Pool Memory consumption */
@@ -97,23 +99,39 @@ static uint memory_usage;
static uint gpu_texture_memory_footprint_compute(GPUTexture *tex)
{
- int samp = max_ii(tex->samples, 1);
+ uint memsize;
+ const uint bytesize = gpu_get_bytesize(tex->format);
+ const int samp = max_ii(tex->samples, 1);
switch (tex->target_base) {
case GL_TEXTURE_1D:
- return tex->bytesize * tex->w * samp;
+ case GL_TEXTURE_BUFFER:
+ memsize = bytesize * tex->w * samp;
+ break;
case GL_TEXTURE_1D_ARRAY:
case GL_TEXTURE_2D:
- return tex->bytesize * tex->w * tex->h * samp;
+ memsize = bytesize * tex->w * tex->h * samp;
+ break;
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_3D:
- return tex->bytesize * tex->w * tex->h * tex->d * samp;
+ memsize = bytesize * tex->w * tex->h * tex->d * samp;
+ break;
case GL_TEXTURE_CUBE_MAP:
- return tex->bytesize * 6 * tex->w * tex->h * samp;
+ memsize = bytesize * 6 * tex->w * tex->h * samp;
+ break;
case GL_TEXTURE_CUBE_MAP_ARRAY_ARB:
- return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp;
+ memsize = bytesize * 6 * tex->w * tex->h * tex->d * samp;
+ break;
default:
+ BLI_assert(0);
return 0;
}
+ if (tex->mipmaps != 0) {
+ /* Just to get an idea of the memory used here is computed
+ * as if the maximum number of mipmaps was generated. */
+ memsize += memsize / 3;
+ }
+
+ return memsize;
}
static void gpu_texture_memory_footprint_add(GPUTexture *tex)
@@ -362,7 +380,7 @@ static uint gpu_get_bytesize(eGPUTextureFormat data_type)
return 16;
case GPU_RGB16F:
return 12;
- case GPU_DEPTH32F_STENCIL8:
+ case GPU_DEPTH32F_STENCIL8: /* 32-bit depth, 8 bits stencil, and 24 unused bits. */
return 8;
case GPU_RG16F:
case GPU_RG16I:
@@ -396,65 +414,84 @@ static uint gpu_get_bytesize(eGPUTextureFormat data_type)
}
}
-static GLenum gpu_get_gl_internalformat(eGPUTextureFormat format)
+static GLenum gpu_format_to_gl_internalformat(eGPUTextureFormat format)
{
/* You can add any of the available type to this list
* For available types see GPU_texture.h */
switch (format) {
/* Formats texture & renderbuffer */
+ case GPU_RGBA8UI:
+ return GL_RGBA8UI;
+ case GPU_RGBA8I:
+ return GL_RGBA8I;
+ case GPU_RGBA8:
+ return GL_RGBA8;
+ case GPU_RGBA32UI:
+ return GL_RGBA32UI;
+ case GPU_RGBA32I:
+ return GL_RGBA32I;
case GPU_RGBA32F:
return GL_RGBA32F;
+ case GPU_RGBA16UI:
+ return GL_RGBA16UI;
+ case GPU_RGBA16I:
+ return GL_RGBA16I;
case GPU_RGBA16F:
return GL_RGBA16F;
case GPU_RGBA16:
return GL_RGBA16;
+ case GPU_RG8UI:
+ return GL_RG8UI;
+ case GPU_RG8I:
+ return GL_RG8I;
+ case GPU_RG8:
+ return GL_RG8;
+ case GPU_RG32UI:
+ return GL_RG32UI;
+ case GPU_RG32I:
+ return GL_RG32I;
case GPU_RG32F:
return GL_RG32F;
- case GPU_RGB16F:
- return GL_RGB16F;
- case GPU_RG16F:
- return GL_RG16F;
+ case GPU_RG16UI:
+ return GL_RG16UI;
case GPU_RG16I:
return GL_RG16I;
+ case GPU_RG16F:
+ return GL_RGBA32F;
case GPU_RG16:
return GL_RG16;
- case GPU_RGBA8:
- return GL_RGBA8;
- case GPU_RGBA8UI:
- return GL_RGBA8UI;
- case GPU_SRGB8_A8:
- return GL_SRGB8_ALPHA8;
- case GPU_R32F:
- return GL_R32F;
+ case GPU_R8UI:
+ return GL_R8UI;
+ case GPU_R8I:
+ GL_R8I;
+ case GPU_R8:
+ return GL_R8;
case GPU_R32UI:
return GL_R32UI;
case GPU_R32I:
return GL_R32I;
- case GPU_R16F:
- return GL_R16F;
- case GPU_R16I:
- return GL_R16I;
+ case GPU_R32F:
+ return GL_R32F;
case GPU_R16UI:
return GL_R16UI;
- case GPU_RG8:
- return GL_RG8;
- case GPU_RG16UI:
- return GL_RG16UI;
+ case GPU_R16I:
+ return GL_R16I;
+ case GPU_R16F:
+ return GL_R16F;
case GPU_R16:
return GL_R16;
- case GPU_R8:
- return GL_R8;
- case GPU_R8UI:
- return GL_R8UI;
/* Special formats texture & renderbuffer */
case GPU_R11F_G11F_B10F:
return GL_R11F_G11F_B10F;
- case GPU_DEPTH24_STENCIL8:
- return GL_DEPTH24_STENCIL8;
case GPU_DEPTH32F_STENCIL8:
return GL_DEPTH32F_STENCIL8;
+ case GPU_DEPTH24_STENCIL8:
+ return GL_DEPTH24_STENCIL8;
+ case GPU_SRGB8_A8:
+ return GL_SRGB8_ALPHA8;
/* Texture only format */
- /* ** Add Format here */
+ case GPU_RGB16F:
+ return GL_RGB16F;
/* Special formats texture only */
/* ** Add Format here */
/* Depth Formats */
@@ -470,6 +507,99 @@ static GLenum gpu_get_gl_internalformat(eGPUTextureFormat format)
}
}
+static eGPUTextureFormat gl_internalformat_to_gpu_format(const GLenum 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:
+ 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 -1;
+ }
+}
+
static GLenum gpu_get_gl_datatype(eGPUDataFormat format)
{
switch (format) {
@@ -690,7 +820,7 @@ GPUTexture *GPU_texture_create_nD(int w,
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
- tex->bytesize = gpu_get_bytesize(tex_format);
+ tex->mipmaps = 0;
tex->format_flag = 0;
if (n == 2) {
@@ -726,7 +856,7 @@ GPUTexture *GPU_texture_create_nD(int w,
tex->target = GL_TEXTURE_2D_MULTISAMPLE;
}
- GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
@@ -877,7 +1007,7 @@ GPUTexture *GPU_texture_cube_create(int w,
tex->refcount = 1;
tex->format = tex_format;
tex->components = gpu_get_component_count(tex_format);
- tex->bytesize = gpu_get_bytesize(tex_format);
+ tex->mipmaps = 0;
tex->format_flag = GPU_FORMAT_CUBE;
if (d == 0) {
@@ -901,7 +1031,7 @@ GPUTexture *GPU_texture_cube_create(int w,
}
}
- GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
GLenum data_format = gpu_get_gl_dataformat(tex_format, &tex->format_flag);
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
@@ -1008,9 +1138,9 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint
tex->components = gpu_get_component_count(tex_format);
tex->format_flag = 0;
tex->target_base = tex->target = GL_TEXTURE_BUFFER;
- tex->bytesize = gpu_get_bytesize(tex_format);
+ tex->mipmaps = 0;
- GLenum internalformat = gpu_get_gl_internalformat(tex_format);
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex_format);
gpu_get_gl_dataformat(tex_format, &tex->format_flag);
@@ -1043,8 +1173,11 @@ GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat tex_format, const GLuint
glBindTexture(tex->target, tex->bindcode);
glTexBuffer(tex->target, internalformat, buffer);
+ glGetTexLevelParameteriv(tex->target, 0, GL_TEXTURE_WIDTH, &tex->w);
glBindTexture(tex->target, 0);
+ gpu_texture_memory_footprint_add(tex);
+
return tex;
}
@@ -1056,8 +1189,6 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
tex->refcount = 1;
tex->target = textarget;
tex->target_base = textarget;
- tex->format = -1;
- tex->components = -1;
tex->samples = 0;
if (!glIsTexture(tex->bindcode)) {
@@ -1065,18 +1196,23 @@ GPUTexture *GPU_texture_from_bindcode(int textarget, int bindcode)
}
else {
GLint w, h;
-
- GLenum gettarget = textarget;
- if (textarget == GL_TEXTURE_CUBE_MAP) {
- gettarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- }
+ GLenum gettarget, gl_format;
+ 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);
}
return tex;
@@ -1261,10 +1397,11 @@ void GPU_texture_add_mipmap(GPUTexture *tex,
{
BLI_assert((int)tex->format > -1);
BLI_assert(tex->components > -1);
+ BLI_assert(miplvl > tex->mipmaps);
gpu_validate_data_format(tex->format, gpu_data_format);
- GLenum internalformat = gpu_get_gl_internalformat(tex->format);
+ GLenum internalformat = gpu_format_to_gl_internalformat(tex->format);
GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
@@ -1310,6 +1447,7 @@ void GPU_texture_add_mipmap(GPUTexture *tex,
BLI_assert(!"tex->target mode not supported");
}
+ tex->mipmaps = miplvl;
glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, miplvl);
glBindTexture(tex->target, 0);
@@ -1328,12 +1466,13 @@ void GPU_texture_update_sub(GPUTexture *tex,
BLI_assert((int)tex->format > -1);
BLI_assert(tex->components > -1);
+ const uint bytesize = gpu_get_bytesize(tex->format);
GLenum data_format = gpu_get_gl_dataformat(tex->format, &tex->format_flag);
GLenum data_type = gpu_get_gl_datatype(gpu_data_format);
GLint alignment;
/* The default pack size for textures is 4, which won't work for byte based textures */
- if (tex->bytesize == 1) {
+ if (bytesize == 1) {
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
@@ -1367,7 +1506,7 @@ void GPU_texture_update_sub(GPUTexture *tex,
BLI_assert(!"tex->target mode not supported");
}
- if (tex->bytesize == 1) {
+ if (bytesize == 1) {
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
}
@@ -1376,6 +1515,8 @@ void GPU_texture_update_sub(GPUTexture *tex,
void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int miplvl)
{
+ BLI_assert(miplvl <= tex->mipmaps);
+
int size[3] = {0, 0, 0};
GPU_texture_get_mipmap_size(tex, miplvl, size);
@@ -1428,7 +1569,7 @@ void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat gpu_data_format, const vo
size_t buffer_len = gpu_texture_memory_footprint_compute(tex);
unsigned char *pixels = MEM_mallocN(buffer_len, __func__);
if (color) {
- size_t bytesize = tex->bytesize;
+ const size_t bytesize = (size_t)gpu_get_bytesize(tex->format);
for (size_t byte = 0; byte < buffer_len; byte += bytesize) {
memcpy(&pixels[byte], color, bytesize);
}
@@ -1547,6 +1688,9 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
{
WARN_NOT_BOUND(tex);
+ gpu_texture_memory_footprint_remove(tex);
+ int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
+
glActiveTexture(GL_TEXTURE0 + tex->number);
if (GPU_texture_depth(tex)) {
@@ -1554,7 +1698,6 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
* In this case we just create a complete texture with mipmaps manually without down-sampling.
* You must initialize the texture levels using other methods like
* GPU_framebuffer_recursive_downsample(). */
- int levels = 1 + floor(log2(max_ii(tex->w, tex->h)));
eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex->format);
for (int i = 1; i < levels; i++) {
GPU_texture_add_mipmap(tex, data_format, i, NULL);
@@ -1564,6 +1707,9 @@ void GPU_texture_generate_mipmap(GPUTexture *tex)
else {
glGenerateMipmap(tex->target_base);
}
+
+ tex->mipmaps = levels;
+ gpu_texture_memory_footprint_add(tex);
}
void GPU_texture_compare_mode(GPUTexture *tex, bool use_compare)