Blender  V3.3
draw_texture_pool.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. */
3 
8 #include "BKE_global.h"
9 
10 #include "BLI_vector.hh"
11 
12 #include "draw_texture_pool.h"
13 
14 using namespace blender;
15 
19 };
20 
24  /* Cache last result to avoid linear search each time. */
25  int last_user_id = -1;
26 
30 };
31 
33 {
34  return new DRWTexturePool();
35 }
36 
38 {
39  /* Resetting the pool twice will effectively free all textures. */
42  delete pool;
43 }
44 
46  DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
47 {
48  int user_id = pool->last_user_id;
49  /* Try cached value. */
50  if (user_id != -1) {
51  if (pool->users[user_id] != user) {
52  user_id = -1;
53  }
54  }
55  /* Try to find inside previous users. */
56  if (user_id == -1) {
57  user_id = pool->users.first_index_of_try(user);
58  }
59  /* No chance, needs to add it to the user list. */
60  if (user_id == -1) {
61  user_id = pool->users.size();
62  pool->users.append(user);
63  /* If there is more than 63 users, better refactor this system. */
64  BLI_assert(user_id < 64);
65  }
66  pool->last_user_id = user_id;
67 
68  uint64_t user_bit = 1llu << user_id;
69  for (DRWTexturePoolHandle &handle : pool->handles) {
70  /* Skip if the user is already using this texture. */
71  if (user_bit & handle.users_bits) {
72  continue;
73  }
74  /* If everything matches reuse the texture. */
75  if ((GPU_texture_format(handle.texture) == format) &&
76  (GPU_texture_width(handle.texture) == width) &&
77  (GPU_texture_height(handle.texture) == height)) {
78  handle.users_bits |= user_bit;
79  return handle.texture;
80  }
81  }
82 
83  char name[16] = "DRW_tex_pool";
84  if (G.debug & G_DEBUG_GPU) {
85  int texture_id = pool->handles.size();
86  SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
87  }
88 
89  DRWTexturePoolHandle handle;
90  handle.users_bits = user_bit;
91  handle.texture = GPU_texture_create_2d(name, width, height, 1, format, nullptr);
92  pool->handles.append(handle);
93  /* Doing filtering for depth does not make sense when not doing shadow mapping,
94  * and enabling texture filtering on integer texture make them unreadable. */
95  bool do_filter = !GPU_texture_depth(handle.texture) && !GPU_texture_integer(handle.texture);
96  GPU_texture_filter_mode(handle.texture, do_filter);
97 
98  return handle.texture;
99 }
100 
102  int width,
103  int height,
105 {
106  GPUTexture *tmp_tex = nullptr;
107  int64_t found_index = 0;
108 
109  auto texture_match = [&](GPUTexture *tex) -> bool {
110  /* TODO(@fclem): We could reuse texture using texture views if the formats are compatible. */
111  return (GPU_texture_format(tex) == format) && (GPU_texture_width(tex) == width) &&
113  };
114 
115  /* Search released texture first. */
116  for (auto i : pool->tmp_tex_released.index_range()) {
117  if (texture_match(pool->tmp_tex_released[i])) {
118  tmp_tex = pool->tmp_tex_released[i];
119  found_index = i;
120  break;
121  }
122  }
123 
124  if (tmp_tex) {
125  pool->tmp_tex_released.remove_and_reorder(found_index);
126  }
127  else {
128  /* Then search pruned texture. */
129  for (auto i : pool->tmp_tex_pruned.index_range()) {
130  if (texture_match(pool->tmp_tex_pruned[i])) {
131  tmp_tex = pool->tmp_tex_pruned[i];
132  found_index = i;
133  break;
134  }
135  }
136 
137  if (tmp_tex) {
138  pool->tmp_tex_pruned.remove_and_reorder(found_index);
139  }
140  }
141 
142  if (!tmp_tex) {
143  /* Create a new texture in last resort. */
144  char name[16] = "DRW_tex_pool";
145  if (G.debug & G_DEBUG_GPU) {
146  int texture_id = pool->handles.size();
147  SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
148  }
149  tmp_tex = GPU_texture_create_2d(name, width, height, 1, format, nullptr);
150  }
151 
152  pool->tmp_tex_acquired.append(tmp_tex);
153 
154  return tmp_tex;
155 }
156 
158 {
159  pool->tmp_tex_acquired.remove_first_occurrence_and_reorder(tmp_tex);
160  pool->tmp_tex_released.append(tmp_tex);
161 }
162 
164 {
165  pool->last_user_id = -1;
166 
167  for (auto it = pool->handles.rbegin(); it != pool->handles.rend(); ++it) {
168  DRWTexturePoolHandle &handle = *it;
169  if (handle.users_bits == 0) {
170  if (handle.texture) {
171  GPU_texture_free(handle.texture);
172  handle.texture = nullptr;
173  }
174  }
175  else {
176  handle.users_bits = 0;
177  }
178  }
179 
180  /* Reverse iteration to make sure we only reorder with known good handles. */
181  for (int i = pool->handles.size() - 1; i >= 0; i--) {
182  if (!pool->handles[i].texture) {
183  pool->handles.remove_and_reorder(i);
184  }
185  }
186 
187  BLI_assert(pool->tmp_tex_acquired.is_empty());
188  for (GPUTexture *tmp_tex : pool->tmp_tex_pruned) {
189  GPU_texture_free(tmp_tex);
190  }
191  pool->tmp_tex_pruned = pool->tmp_tex_released;
192  pool->tmp_tex_released.clear();
193 }
@ G_DEBUG_GPU
Definition: BKE_global.h:193
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define SNPRINTF(dst, format,...)
Definition: BLI_string.h:485
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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 width
int GPU_texture_height(const GPUTexture *tex)
Definition: gpu_texture.cc:607
struct GPUTexture GPUTexture
Definition: GPU_texture.h:17
int GPU_texture_width(const GPUTexture *tex)
Definition: gpu_texture.cc:602
bool GPU_texture_integer(const GPUTexture *tex)
Definition: gpu_texture.cc:654
void GPU_texture_free(GPUTexture *tex)
Definition: gpu_texture.cc:564
void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter)
Definition: gpu_texture.cc:518
GPUTexture * GPU_texture_create_2d(const char *name, int w, int h, int mip_len, eGPUTextureFormat format, const float *data)
Definition: gpu_texture.cc:291
eGPUTextureFormat
Definition: GPU_texture.h:83
eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
Definition: gpu_texture.cc:639
bool GPU_texture_depth(const GPUTexture *tex)
Definition: gpu_texture.cc:644
void DRW_texture_pool_free(DRWTexturePool *pool)
GPUTexture * DRW_texture_pool_texture_acquire(DRWTexturePool *pool, int width, int height, eGPUTextureFormat format)
void DRW_texture_pool_reset(DRWTexturePool *pool)
GPUTexture * DRW_texture_pool_query(DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, void *user)
void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex)
DRWTexturePool * DRW_texture_pool_create()
struct DRWTexturePool DRWTexturePool
format
Definition: logImageCore.h:38
#define G(x, y, z)
__int64 int64_t
Definition: stdint.h:89
unsigned __int64 uint64_t
Definition: stdint.h:90
Vector< void *, 16 > users
Vector< DRWTexturePoolHandle > handles
Vector< GPUTexture * > tmp_tex_acquired
Vector< GPUTexture * > tmp_tex_released
Vector< GPUTexture * > tmp_tex_pruned