Blender V4.3
draw_texture_pool.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BKE_global.hh"
10
11#include "BLI_string.h"
12#include "BLI_vector.hh"
13
14#include "draw_texture_pool.hh"
15
16using namespace blender;
17
23
25 GPUTexture *texture;
27
28 bool operator==(const ReleasedTexture &other)
29 {
30 return texture == other.texture;
31 }
32};
33
43
48
50{
51 for (DRWTexturePoolHandle &tex : pool->handles) {
53 }
54 for (GPUTexture *tex : pool->tmp_tex_acquired) {
56 }
57 for (ReleasedTexture &tex : pool->tmp_tex_released) {
58 GPU_texture_free(tex.texture);
59 }
60 delete pool;
61}
62
64 int width,
65 int height,
67 eGPUTextureUsage usage,
68 void *user)
69{
70 /* Texture pools have an implicit usage as a texture attachment. */
72 "Pool textures must be of usage type attachment.");
73 usage = usage | GPU_TEXTURE_USAGE_ATTACHMENT;
74
75 int user_id = pool->last_user_id;
76 /* Try cached value. */
77 if (user_id != -1) {
78 if (pool->users[user_id] != user) {
79 user_id = -1;
80 }
81 }
82 /* Try to find inside previous users. */
83 if (user_id == -1) {
84 user_id = pool->users.first_index_of_try(user);
85 }
86 /* No chance, needs to add it to the user list. */
87 if (user_id == -1) {
88 user_id = pool->users.size();
89 pool->users.append(user);
90 /* If there is more than 63 users, better refactor this system. */
91 BLI_assert(user_id < 64);
92 }
93 pool->last_user_id = user_id;
94
95 uint64_t user_bit = 1llu << user_id;
96 for (DRWTexturePoolHandle &handle : pool->handles) {
97 /* Skip if the user is already using this texture. */
98 if (user_bit & handle.users_bits) {
99 continue;
100 }
101 /* If everything matches reuse the texture. */
102 if ((GPU_texture_format(handle.texture) == format) &&
103 (GPU_texture_width(handle.texture) == width) &&
104 (GPU_texture_height(handle.texture) == height) &&
105 (GPU_texture_usage(handle.texture) == usage))
106 {
107 handle.users_bits |= user_bit;
108 return handle.texture;
109 }
110 }
111
112 char name[16] = "DRW_tex_pool";
113 if (G.debug & G_DEBUG_GPU) {
114 int texture_id = pool->handles.size();
115 SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
116 }
117
119 handle.users_bits = user_bit;
120 handle.orphan_cycles = 0;
121 handle.texture = GPU_texture_create_2d(name, width, height, 1, format, usage, nullptr);
122 pool->handles.append(handle);
123 /* Doing filtering for depth does not make sense when not doing shadow mapping,
124 * and enabling texture filtering on integer texture make them unreadable. */
125 bool do_filter = !GPU_texture_has_depth_format(handle.texture) &&
126 !GPU_texture_has_integer_format(handle.texture);
127 GPU_texture_filter_mode(handle.texture, do_filter);
128
129 return handle.texture;
130}
131
133 DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, eGPUTextureUsage usage)
134{
135 GPUTexture *tmp_tex = nullptr;
136 int64_t found_index = 0;
137
138 auto texture_match = [&](GPUTexture *tex) -> bool {
139 /* TODO(@fclem): We could reuse texture using texture views if the formats are compatible. */
140 return (GPU_texture_format(tex) == format) && (GPU_texture_width(tex) == width) &&
141 (GPU_texture_height(tex) == height) && (GPU_texture_usage(tex) == usage);
142 };
143
144 /* Search released texture first. */
145 for (auto i : pool->tmp_tex_released.index_range()) {
146 if (texture_match(pool->tmp_tex_released[i].texture)) {
147 tmp_tex = pool->tmp_tex_released[i].texture;
148 found_index = i;
149 break;
150 }
151 }
152
153 if (tmp_tex) {
154 pool->tmp_tex_released.remove_and_reorder(found_index);
155 }
156 else {
157 /* Create a new texture in last resort. */
158 char name[16] = "DRW_tex_pool";
159 if (G.debug & G_DEBUG_GPU) {
160 int texture_id = pool->handles.size();
161 SNPRINTF(name, "DRW_tex_pool_%d", texture_id);
162 }
163 tmp_tex = GPU_texture_create_2d(name, width, height, 1, format, usage, nullptr);
164 }
165
166 pool->tmp_tex_acquired.append(tmp_tex);
167
168 return tmp_tex;
169}
170
171void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex)
172{
173 pool->tmp_tex_acquired.remove_first_occurrence_and_reorder(tmp_tex);
174 pool->tmp_tex_released.append({tmp_tex, 0});
175}
176
178{
179 pool->tmp_tex_acquired.remove_first_occurrence_and_reorder(tex);
180}
181
183{
184 pool->tmp_tex_acquired.append(tex);
185}
186
188{
191 const int max_orphan_cycles = 8;
192
193 pool->last_user_id = -1;
194
195 for (auto it = pool->handles.rbegin(); it != pool->handles.rend(); ++it) {
196 DRWTexturePoolHandle &handle = *it;
197 if (handle.users_bits == 0) {
198 handle.orphan_cycles++;
199 if (handle.texture && handle.orphan_cycles >= max_orphan_cycles) {
200 GPU_texture_free(handle.texture);
201 handle.texture = nullptr;
202 }
203 }
204 else {
205 handle.users_bits = 0;
206 handle.orphan_cycles = 0;
207 }
208 }
209
210 /* Reverse iteration to make sure we only reorder with known good handles. */
211 for (int i = pool->handles.size() - 1; i >= 0; i--) {
212 if (!pool->handles[i].texture) {
213 pool->handles.remove_and_reorder(i);
214 }
215 }
216
217 BLI_assert_msg(pool->tmp_tex_acquired.is_empty(),
218 "Missing a TextureFromPool.release() before end of draw.");
219
220 for (int i = pool->tmp_tex_released.size() - 1; i >= 0; i--) {
221 ReleasedTexture &tex = pool->tmp_tex_released[i];
222 if (tex.orphan_cycles >= max_orphan_cycles) {
223 GPU_texture_free(tex.texture);
224 pool->tmp_tex_released.remove_and_reorder(i);
225 }
226 else {
227 tex.orphan_cycles++;
228 }
229 }
230}
@ G_DEBUG_GPU
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
int GPU_texture_height(const GPUTexture *texture)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_width(const GPUTexture *texture)
bool GPU_texture_has_integer_format(const GPUTexture *texture)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_ATTACHMENT
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
#define GPU_TEXTURE_FREE_SAFE(texture)
eGPUTextureFormat
eGPUTextureUsage GPU_texture_usage(const GPUTexture *texture)
bool GPU_texture_has_depth_format(const GPUTexture *texture)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
void DRW_texture_pool_free(DRWTexturePool *pool)
GPUTexture * DRW_texture_pool_texture_acquire(DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, eGPUTextureUsage usage)
DRWTexturePool * DRW_texture_pool_create()
GPUTexture * DRW_texture_pool_query(DRWTexturePool *pool, int width, int height, eGPUTextureFormat format, eGPUTextureUsage usage, void *user)
void DRW_texture_pool_reset(DRWTexturePool *pool)
void DRW_texture_pool_texture_release(DRWTexturePool *pool, GPUTexture *tmp_tex)
void DRW_texture_pool_take_texture_ownership(DRWTexturePool *pool, GPUTexture *tex)
void DRW_texture_pool_give_texture_ownership(DRWTexturePool *pool, GPUTexture *tex)
format
#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< ReleasedTexture > tmp_tex_released
Vector< GPUTexture * > tmp_tex_acquired
bool operator==(const ReleasedTexture &other)