GPUViewport: Add a Texture Pool to reuse textures across engines.

This commit is contained in:
Clément Foucault 2017-05-16 02:59:25 +02:00
parent dc01586b40
commit 7a029f4e00
4 changed files with 81 additions and 0 deletions

View File

@ -191,6 +191,7 @@ void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int
int GPU_texture_target(const GPUTexture *tex);
int GPU_texture_width(const GPUTexture *tex);
int GPU_texture_height(const GPUTexture *tex);
int GPU_texture_format(const GPUTexture *tex);
bool GPU_texture_depth(const GPUTexture *tex);
bool GPU_texture_stencil(const GPUTexture *tex);
int GPU_texture_opengl_bindcode(const GPUTexture *tex);

View File

@ -101,6 +101,9 @@ void *GPU_viewport_texture_list_get(GPUViewport *viewport);
void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]);
void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]);
/* Texture pool */
GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format);
bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash);
/* debug */

View File

@ -65,6 +65,7 @@ struct GPUTexture {
bool stencil; /* is a stencil texture? */
unsigned int bytesize; /* number of byte for one pixel */
int format; /* GPUTextureFormat */
};
/* ------ Memory Management ------- */
@ -318,6 +319,7 @@ static GPUTexture *GPU_texture_create_nD(
tex->number = -1;
tex->refcount = 1;
tex->fb_attachment = -1;
tex->format = data_type;
if (n == 2) {
if (d == 0)
@ -462,6 +464,7 @@ static GPUTexture *GPU_texture_cube_create(
tex->number = -1;
tex->refcount = 1;
tex->fb_attachment = -1;
tex->format = data_type;
if (d == 0) {
tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP;
@ -551,6 +554,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget
tex->target = textarget;
tex->target_base = textarget;
tex->fromblender = 1;
tex->format = -1;
ima->gputexture[gputt] = tex;
@ -611,6 +615,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
tex->refcount = 1;
tex->target = GL_TEXTURE_2D;
tex->target_base = GL_TEXTURE_2D;
tex->format = -1;
prv->gputexture[0] = tex;
@ -944,6 +949,11 @@ int GPU_texture_height(const GPUTexture *tex)
return tex->h;
}
int GPU_texture_format(const GPUTexture *tex)
{
return tex->format;
}
bool GPU_texture_depth(const GPUTexture *tex)
{
return tex->depth;

View File

@ -54,6 +54,17 @@
static const int default_fbl_len = (sizeof(DefaultFramebufferList)) / sizeof(void *);
static const int default_txl_len = (sizeof(DefaultTextureList)) / sizeof(void *);
/* Maximum number of simultaneous engine enabled at the same time.
* Setting it lower than the real number will do lead to
* higher VRAM usage due to sub-efficient buffer reuse. */
#define MAX_ENGINE_BUFFER_SHARING 5
typedef struct ViewportTempTexture {
struct ViewportTempTexture *next, *prev;
void *user[MAX_ENGINE_BUFFER_SHARING];
GPUTexture *texture;
} ViewportTempTexture;
struct GPUViewport {
float pad[4];
@ -66,11 +77,14 @@ struct GPUViewport {
DefaultFramebufferList *fbl;
DefaultTextureList *txl;
ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */
};
static void gpu_viewport_buffers_free(FramebufferList *fbl, int fbl_len, TextureList *txl, int txl_len);
static void gpu_viewport_storage_free(StorageList *stl, int stl_len);
static void gpu_viewport_passes_free(PassList *psl, int psl_len);
static void gpu_viewport_texture_pool_free(GPUViewport *viewport);
GPUViewport *GPU_viewport_create(void)
{
@ -153,6 +167,8 @@ static void gpu_viewport_engines_data_free(GPUViewport *viewport)
BLI_remlink(&viewport->data, link);
MEM_freeN(link);
}
gpu_viewport_texture_pool_free(viewport);
}
void *GPU_viewport_engine_data_get(GPUViewport *viewport, void *engine_type)
@ -192,6 +208,53 @@ void GPU_viewport_size_set(GPUViewport *viewport, const int size[2])
viewport->size[1] = size[1];
}
/**
* Try to find a texture coresponding to params into the texture pool.
* If no texture was found, create one and add it to the pool.
*/
GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, int width, int height, int channels, int format)
{
GPUTexture *tex;
for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
if ((GPU_texture_width(tmp_tex->texture) == width) &&
(GPU_texture_height(tmp_tex->texture) == height) &&
(GPU_texture_format(tmp_tex->texture) == format))
{
/* Search if the engine is not already using this texture */
for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) {
if (tmp_tex->user[i] == engine) {
break;
}
if (tmp_tex->user[i] == NULL) {
tmp_tex->user[i] = engine;
return tmp_tex->texture;
}
}
}
}
tex = GPU_texture_create_2D_custom(width, height, channels, format, NULL, NULL);
ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture");
tmp_tex->texture = tex;
tmp_tex->user[0] = engine;
BLI_addtail(&viewport->tex_pool, tmp_tex);
return tex;
}
static void gpu_viewport_texture_pool_free(GPUViewport *viewport)
{
for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) {
GPU_texture_free(tmp_tex->texture);
}
BLI_freelistN(&viewport->tex_pool);
}
bool GPU_viewport_cache_validate(GPUViewport *viewport, unsigned int hash)
{
bool dirty = false;
@ -238,6 +301,8 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect)
DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL);
gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len);
}
gpu_viewport_texture_pool_free(viewport);
}
}
@ -408,6 +473,8 @@ void GPU_viewport_free(GPUViewport *viewport)
(FramebufferList *)viewport->fbl, default_fbl_len,
(TextureList *)viewport->txl, default_txl_len);
gpu_viewport_texture_pool_free(viewport);
MEM_freeN(viewport->fbl);
MEM_freeN(viewport->txl);