Unravel Engine C++ Reference
Loading...
Searching...
No Matches
texture.cpp
Go to the documentation of this file.
1#include "texture.h"
2#include "utils/bgfx_utils.h"
3
4#include <string>
5#include <utility>
6
7namespace gfx
8{
9namespace
10{
11
12auto clamp_non_negative(std::int64_t bytes) -> std::uint64_t
13{
14 return static_cast<std::uint64_t>(std::max<std::int64_t>(0, bytes));
15}
16
17void write_formatted(std::uint64_t bytes, char* out, std::size_t out_size, std::uint8_t num_frac)
18{
19 if(out == nullptr || out_size == 0)
20 {
21 return;
22 }
23 if(num_frac == 0)
24 {
25 bx::prettify(out, static_cast<int32_t>(out_size), bytes, bx::Units::KibiByte);
26 return;
27 }
28 const bx::FixedStringT<32> formatted = bx::toHuman<32>(bytes, bx::Units::KibiByte, num_frac);
29 bx::strCopy(out, static_cast<int32_t>(out_size), formatted.getCPtr());
30}
31
32auto format_bytes(std::uint64_t bytes, std::uint8_t num_frac = 2) -> std::string
33{
34 std::array<char, 32> buffer{};
35 write_formatted(bytes, buffer.data(), buffer.size(), num_frac);
36 return buffer.data();
37}
38
39auto format_bytes(std::int64_t bytes, std::uint8_t num_frac = 2) -> std::string
40{
41 return format_bytes(clamp_non_negative(bytes), num_frac);
42}
43
44void format_bytes(std::uint64_t bytes, char* out, std::size_t out_size, std::uint8_t num_frac)
45{
46 write_formatted(bytes, out, out_size, num_frac);
47}
51auto try_make_room_for(std::uint64_t bytes, const char* what, eviction::reclaim_kind kind) -> bool
52{
53 if(bytes == 0 || !eviction::is_supported())
54 {
55 return true;
56 }
58 {
60 {
61 return true;
62 }
63 const std::string msg = std::string("Eviction: Insufficient headroom for ") + what + " (" +
64 format_bytes(bytes) + "); Skipping allocation (fallback texture).";
65 gfx::log("warning", msg, __FILE__, __LINE__);
66 return false;
67 }
68 const auto result = eviction::reclaim_for(bytes, kind);
70 {
71 return true;
72 }
73 const std::string msg = std::string("Eviction: Insufficient headroom for ") + what + " (" +
74 format_bytes(bytes) + "); Allocation may fail.";
75 gfx::log("warning", msg, __FILE__, __LINE__);
76 return true;
77}
78
79auto texture_reclaim_kind(std::uint64_t flags) -> eviction::reclaim_kind
80{
81 const bool gpu_generated = 0 != (flags & (BGFX_TEXTURE_RT_MASK | BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_BLIT_DST));
83}
84
85auto make_load_precreate(std::uint64_t flags, const char* what) -> TexturePreCreateFn
86{
87 const eviction::reclaim_kind kind = texture_reclaim_kind(flags);
88 return [flags, what, kind](const bgfx::TextureInfo& info) -> bool
89 {
90 return try_make_room_for(estimate_texture_gpu_size(info, flags), what, kind);
91 };
92}
93} // namespace
94
95void texture::adopt_loaded_eviction(eviction::backing_buffer backing,
96 std::uint64_t estimated_size,
97 std::uint64_t load_flags,
98 std::uint8_t skip,
99 const char* label)
100{
101 auto restore = [backing, load_flags, skip, label = std::string(label)](texture& self) -> bool
102 {
103 bx::Error e;
104 self.handle_ = loadTexture(backing->data(),
105 static_cast<std::uint32_t>(backing->size()),
106 load_flags,
107 skip,
108 &self.info,
109 nullptr,
110 label.c_str(),
111 &e);
112 return self.is_valid();
113 };
114 if(is_valid())
115 {
116 make_evictable(estimated_size, std::move(restore));
117 }
118 else
119 {
120 make_evictable_deferred(estimated_size, std::move(restore));
121 }
122}
123
124texture::texture(const char* _path,
125 std::uint64_t _flags,
126 std::uint8_t _skip /*= 0 */,
127 texture_info* _info /*= nullptr*/)
128{
129 bx::Error err;
130 std::uint32_t size = 0;
131 void* data = load(bx::FilePath(_path), &size);
132 if(data != nullptr)
133 {
135 {
137 handle_ = loadTexture(data, size, _flags, _skip, &info, nullptr, _path, &err, make_load_precreate(_flags, _path));
138 adopt_loaded_eviction(backing,
140 _flags,
141 _skip,
142 _path);
143 }
144 else
145 {
146 handle_ = loadTexture(data, size, _flags, _skip, &info, nullptr, _path, &err);
147 }
148 unload(data);
149 }
150
151 if(_info != nullptr)
152 {
153 *_info = info;
154 }
155
156 flags = _flags;
157}
158
159texture::texture(const void* _data,
160 std::uint32_t _size,
161 std::uint64_t _flags,
162 std::uint8_t _skip,
163 texture_info* _info,
164 const char* _name)
165{
166 bx::Error err;
167 const char* label = (_name != nullptr) ? _name : "memory texture";
169 {
170 eviction::backing_buffer backing = eviction::make_backing(_data, _size);
171 handle_ = loadTexture(_data, _size, _flags, _skip, &info, nullptr, _name, &err, make_load_precreate(_flags, label));
172 adopt_loaded_eviction(backing, estimate_texture_gpu_size(info, _flags), _flags, _skip, label);
173 }
174 else
175 {
176 handle_ = loadTexture(_data, _size, _flags, _skip, &info, nullptr, _name, &err);
177 }
178
179 if(_info != nullptr)
180 {
181 *_info = info;
182 }
183
184 flags = _flags;
185}
186
187texture::texture(std::uint16_t _width,
188 std::uint16_t _height,
189 bool _hasMips,
190 std::uint16_t _numLayers,
191 texture_format _format,
192 std::uint64_t _flags /*= BGFX_TEXTURE_NONE */,
193 const memory_view* _mem /*= nullptr */)
194 : flags(_flags)
195{
196 calc_texture_size(info, _width, _height, 1, false, _hasMips, _numLayers, _format);
197 const std::uint64_t estimated_size = estimate_texture_gpu_size(info, _flags);
198 const eviction::reclaim_kind kind = texture_reclaim_kind(_flags);
199 const bool can_allocate = try_make_room_for(estimated_size, "2D texture", kind);
200
201 if(can_allocate)
202 {
203 handle_ = create_texture_2d(_width, _height, _hasMips, _numLayers, _format, _flags, _mem);
204 }
205 const bool valid = is_valid();
206 if(valid && is_gpu_generated())
207 {
209 }
210
211 if(_mem != nullptr && gfx::eviction::is_supported())
212 {
213 eviction::backing_buffer backing = eviction::make_backing(_mem->data, _mem->size);
214 auto restore = [backing,
215 width = _width,
216 height = _height,
217 has_mips = _hasMips,
218 layers = _numLayers,
219 format = _format,
220 flags = _flags,
221 estimated_size](texture& self) -> bool
222 {
223 const memory_view* mem = eviction::make_backing_ref(backing);
224 self.handle_ = create_texture_2d(width, height, has_mips, layers, format, flags, mem);
225 return self.is_valid();
226 };
227 if(valid)
228 {
229 make_evictable(estimated_size, std::move(restore));
230 }
231 else
232 {
233 make_evictable_deferred(estimated_size, std::move(restore));
234 }
235 }
236}
237
238texture::texture(std::uint16_t _width,
239 std::uint16_t _height,
240 std::uint16_t _depth,
241 bool _hasMips,
242 texture_format _format,
243 std::uint64_t _flags /*= BGFX_TEXTURE_NONE */,
244 const memory_view* _mem /*= nullptr */)
245 : flags(_flags)
246{
247 calc_texture_size(info, _width, _height, _depth, false, _hasMips, 1, _format);
248 const std::uint64_t estimated_size = estimate_texture_gpu_size(info, _flags);
249 const eviction::reclaim_kind kind = texture_reclaim_kind(_flags);
250 const bool can_allocate = try_make_room_for(estimated_size, "3D texture", kind);
251
252 if(can_allocate)
253 {
254 handle_ = create_texture_3d(_width, _height, _depth, _hasMips, _format, _flags, _mem);
255 }
256
257 const bool valid = is_valid();
258 if(valid && is_gpu_generated())
259 {
261 }
262
263 if(_mem != nullptr && gfx::eviction::is_supported())
264 {
265 eviction::backing_buffer backing = eviction::make_backing(_mem->data, _mem->size);
266 auto restore = [backing,
267 width = _width,
268 height = _height,
269 depth = _depth,
270 has_mips = _hasMips,
271 format = _format,
272 flags = _flags,
273 estimated_size](texture& self) -> bool
274 {
275 const memory_view* mem = eviction::make_backing_ref(backing);
276 self.handle_ = create_texture_3d(width, height, depth, has_mips, format, flags, mem);
277 return self.is_valid();
278 };
279 if(valid)
280 {
281 make_evictable(estimated_size, std::move(restore));
282 }
283 else
284 {
285 make_evictable_deferred(estimated_size, std::move(restore));
286 }
287 }
288}
289
290texture::texture(std::uint16_t _size,
291 bool _hasMips,
292 std::uint16_t _numLayers,
293 texture_format _format,
294 std::uint64_t _flags /*= BGFX_TEXTURE_NONE */,
295 const memory_view* _mem /*= nullptr */)
296 : flags(_flags)
297{
298 calc_texture_size(info, _size, _size, _size, false, _hasMips, _numLayers, _format);
299 const std::uint64_t estimated_size = estimate_texture_gpu_size(info, _flags);
300 const eviction::reclaim_kind kind = texture_reclaim_kind(_flags);
301 const bool can_allocate = try_make_room_for(estimated_size, "cube texture", kind);
302
303 if(can_allocate)
304 {
305 handle_ = create_texture_cube(_size, _hasMips, _numLayers, _format, _flags, _mem);
306 }
307 const bool valid = is_valid();
308 if(valid && is_gpu_generated())
309 {
311 }
312
313 if(_mem != nullptr && gfx::eviction::is_supported())
314 {
315 eviction::backing_buffer backing = eviction::make_backing(_mem->data, _mem->size);
316 auto restore = [backing,
317 size = _size,
318 has_mips = _hasMips,
319 layers = _numLayers,
320 format = _format,
321 flags = _flags,
322 estimated_size](texture& self) -> bool
323 {
324 const memory_view* mem = eviction::make_backing_ref(backing);
325 self.handle_ = create_texture_cube(size, has_mips, layers, format, flags, mem);
326 return self.is_valid();
327 };
328 if(valid)
329 {
330 make_evictable(estimated_size, std::move(restore));
331 }
332 else
333 {
334 make_evictable_deferred(estimated_size, std::move(restore));
335 }
336 }
337}
338
340{
341 return {static_cast<std::uint32_t>(info.width), static_cast<std::uint32_t>(info.height)};
342}
343
344auto texture::is_render_target() const -> bool
345{
346 return 0 != (flags & BGFX_TEXTURE_RT_MASK);
347}
348
349auto texture::is_gpu_generated() const -> bool
350{
351 return 0 != (flags & (BGFX_TEXTURE_RT_MASK | BGFX_TEXTURE_COMPUTE_WRITE | BGFX_TEXTURE_BLIT_DST));
352}
353
355{
356 return gfx::fallback_texture();
357}
358
359auto texture::get_estimated_gpu_size() const -> std::uint64_t
360{
362}
363} // namespace gfx
uint32_t width
uint32_t height
gfx::texture_format format
void * load(bx::FileReaderI *_reader, bx::AllocatorI *_allocator, const bx::FilePath &_filePath, uint32_t *_size)
void unload(void *_ptr)
bgfx::TextureHandle loadTexture(const void *_data, uint32_t _size, uint64_t _flags, uint8_t _skip, bgfx::TextureInfo *_info, bimg::Orientation::Enum *_orientation, const char *_name, bx::Error *_err, const TexturePreCreateFn &_preCreate)
std::function< bool(const bgfx::TextureInfo &_info)> TexturePreCreateFn
Definition bgfx_utils.h:28
void make_evictable(std::uint64_t gpu_bytes, std::function< bool(texture &)> restore_fn, evict_class cls=evict_class::evictable)
void make_evictable_deferred(std::uint64_t gpu_bytes, std::function< bool(texture &)> restore_fn, evict_class cls=evict_class::evictable)
std::uint64_t bytes
Definition eviction.cpp:823
void note_pending_allocation(std::uint64_t bytes)
Definition eviction.cpp:806
auto is_supported() -> bool
Definition eviction.cpp:650
auto make_backing_ref(const backing_buffer &backing) -> const memory_view *
Definition eviction.h:31
std::shared_ptr< std::vector< std::uint8_t > > backing_buffer
Definition eviction.h:18
auto would_allocation_fit(std::uint64_t bytes) -> bool
Definition eviction.cpp:723
auto make_backing(const void *data, std::uint32_t size) -> backing_buffer
Definition eviction.h:20
reclaim_kind
Controls whether reclaim_for pumps the GPU command buffer after evicting.
Definition eviction.h:83
auto reclaim_for(std::uint64_t bytes, reclaim_kind kind) -> reclaim_result
Definition eviction.cpp:737
@ insufficient
Eviction could not free enough room; the allocation may exhaust device memory.
bgfx::TextureFormat::Enum texture_format
Definition format.h:10
texture_handle create_texture_cube(uint16_t _size, bool _hasMips, uint16_t _numLayers, texture_format _format, uint64_t _flags, const memory_view *_mem)
Definition graphics.cpp:709
texture_handle create_texture_3d(uint16_t _width, uint16_t _height, uint16_t _depth, bool _hasMips, texture_format _format, uint64_t _flags, const memory_view *_mem)
Definition graphics.cpp:698
void log(const std::string &category, const std::string &log_msg, const char *_filePath, uint16_t _line)
Definition graphics.cpp:71
bgfx::TextureHandle texture_handle
Definition graphics.h:51
void calc_texture_size(texture_info &_info, uint16_t _width, uint16_t _height, uint16_t _depth, bool _cubeMap, bool _hasMips, uint16_t _numLayers, texture_format _format)
Definition graphics.cpp:661
texture_handle create_texture_2d(uint16_t _width, uint16_t _height, bool _hasMips, uint16_t _numLayers, texture_format _format, uint64_t _flags, const memory_view *_mem)
Definition graphics.cpp:678
auto fallback_texture() -> texture_handle
Definition graphics.cpp:307
bgfx::TextureInfo texture_info
Definition graphics.h:24
uint64_t estimate_texture_gpu_size(const texture_info &_info, uint64_t _flags)
bgfx::Memory memory_view
Definition graphics.h:23
Hash specialization for batch_key to enable use in std::unordered_map.
auto format_bytes(std::uint64_t bytes, std::uint8_t num_frac) -> std::string
auto is_render_target() const -> bool
Definition texture.cpp:344
auto fallback_handle() const -> texture_handle
Definition texture.cpp:354
texture()=default
auto is_gpu_generated() const -> bool
Whether the texture's contents are produced on the GPU (render target or compute-write) rather than u...
Definition texture.cpp:349
std::uint64_t flags
Creation flags.
Definition texture.h:127
auto get_size() const -> usize32_t
Definition texture.cpp:339
texture_info info
Texture detail info.
Definition texture.h:125
auto get_estimated_gpu_size() const -> std::uint64_t
Definition texture.cpp:359