Blender V5.0
DRW_gpu_wrapper.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
59
60#include "MEM_guardedalloc.h"
61
62#include "BKE_global.hh"
63
64#include "BLI_math_base.h"
66#include "BLI_span.hh"
67#include "BLI_utildefines.h"
68#include "BLI_utility_mixins.hh"
69#include "BLI_vector.hh"
70
71#include "GPU_framebuffer.hh"
72#include "GPU_storage_buffer.hh"
73#include "GPU_texture.hh"
74#include "GPU_texture_pool.hh"
75#include "GPU_uniform_buffer.hh"
76
77namespace blender::draw {
78
79/* -------------------------------------------------------------------- */
82
83namespace detail {
84
85template<
87 typename T,
91 bool device_only>
93 protected:
94 T *data_ = nullptr;
96
97 BLI_STATIC_ASSERT(((sizeof(T) * len) % 16) == 0,
98 "Buffer size need to be aligned to size of float4.");
99
100 public:
105 const T &operator[](int64_t index) const
106 {
107 BLI_STATIC_ASSERT(!device_only, "");
108 BLI_assert(index >= 0);
109 BLI_assert(index < len_);
110 return data_[index];
111 }
112
114 {
115 BLI_STATIC_ASSERT(!device_only, "");
116 BLI_assert(index >= 0);
117 BLI_assert(index < len_);
118 return data_[index];
119 }
120
124 const T *data() const
125 {
126 BLI_STATIC_ASSERT(!device_only, "");
127 return data_;
128 }
130 {
131 BLI_STATIC_ASSERT(!device_only, "");
132 return data_;
133 }
134
138 const T *begin() const
139 {
140 BLI_STATIC_ASSERT(!device_only, "");
141 return data_;
142 }
143 const T *end() const
144 {
145 BLI_STATIC_ASSERT(!device_only, "");
146 return data_ + len_;
147 }
148
150 {
151 BLI_STATIC_ASSERT(!device_only, "");
152 return data_;
153 }
155 {
156 BLI_STATIC_ASSERT(!device_only, "");
157 return data_ + len_;
158 }
159
160 operator Span<T>() const
161 {
162 BLI_STATIC_ASSERT(!device_only, "");
163 return Span<T>(data_, len_);
164 }
165};
166
167template<typename T, int64_t len, bool device_only>
168class UniformCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
169 protected:
171
172#ifndef NDEBUG
173 const char *name_ = typeid(T).name();
174#else
175 const char *name_ = "UniformBuffer";
176#endif
177
178 public:
179 UniformCommon(const char *name = nullptr)
180 {
181 if (name) {
182 name_ = name;
183 }
184 ubo_ = GPU_uniformbuf_create_ex(sizeof(T) * len, nullptr, name_);
185 }
186
191
193 {
194 GPU_uniformbuf_update(ubo_, this->data_);
195 }
196
197 /* To be able to use it with DRW_shgroup_*_ref(). */
198 operator gpu::UniformBuf *() const
199 {
200 return ubo_;
201 }
202
203 /* To be able to use it with DRW_shgroup_*_ref(). */
205 {
206 return &ubo_;
207 }
208};
209
210template<typename T, int64_t len, bool device_only>
211class StorageCommon : public DataBuffer<T, len, false>, NonMovable, NonCopyable {
212 protected:
214
215#ifndef NDEBUG
216 const char *name_ = typeid(T).name();
217#else
218 const char *name_ = "StorageBuffer";
219#endif
220
221 public:
222 StorageCommon(const char *name = nullptr)
223 {
224 if (name) {
225 name_ = name;
226 }
227 this->len_ = len;
228 constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
229 ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
230 }
231
236
238 {
239 BLI_assert(device_only == false);
240 GPU_storagebuf_update(ssbo_, this->data_);
241 }
242
247
252
253 void read()
254 {
255 GPU_storagebuf_read(ssbo_, this->data_);
256 }
257
258 operator gpu::StorageBuf *() const
259 {
260 return ssbo_;
261 }
262 /* To be able to use it with DRW_shgroup_*_ref(). */
264 {
265 return &ssbo_;
266 }
267};
268
269} // namespace detail
270
272
273/* -------------------------------------------------------------------- */
276
277template<
279 typename T,
283 /* TODO(@fclem): Currently unsupported. */
284 /* bool device_only = false */>
285class UniformArrayBuffer : public detail::UniformCommon<T, len, false> {
286 public:
288 {
289 /* TODO(@fclem): We should map memory instead. */
290 this->data_ = (T *)MEM_mallocN_aligned(len * sizeof(T), 16, this->name_);
291 }
293 {
294 MEM_freeN(static_cast<void *>(this->data_));
295 }
296};
297
298template<
300 typename T
302 /* TODO(@fclem): Currently unsupported. */
303 /* bool device_only = false */>
304class UniformBuffer : public T, public detail::UniformCommon<T, 1, false> {
305 public:
306 UniformBuffer(const char *name = nullptr) : T{}, detail::UniformCommon<T, 1, false>(name)
307 {
308 /* TODO(@fclem): How could we map this? */
309 this->data_ = static_cast<T *>(this);
310 }
311
313 {
314 *static_cast<T *>(this) = other;
315 return *this;
316 }
317};
318
320
321/* -------------------------------------------------------------------- */
324
325template<
327 typename T,
329 int64_t len = (512u + (sizeof(T) - 1)) / sizeof(T),
331 bool device_only = false>
332class StorageArrayBuffer : public detail::StorageCommon<T, len, device_only> {
333 public:
334 StorageArrayBuffer(const char *name = nullptr) : detail::StorageCommon<T, len, device_only>(name)
335 {
336 /* TODO(@fclem): We should map memory instead. */
337 this->data_ = (T *)MEM_mallocN_aligned(len * sizeof(T), 16, this->name_);
338 }
340 {
341 /* NOTE: T is not always trivial (e.g. can be #blender::eevee::VelocityIndex), so cannot use
342 * `MEM_freeN` directly on it, without casting it to `void *`. */
343 MEM_freeN(static_cast<void *>(this->data_));
344 }
345
346 /* Resize to \a new_size elements. */
347 void resize(int64_t new_size)
348 {
349 BLI_assert(new_size > 0);
350 if (new_size != this->len_) {
351 /* Manual realloc since MEM_reallocN_aligned does not exists. */
352 T *new_data_ = (T *)MEM_mallocN_aligned(new_size * sizeof(T), 16, this->name_);
353 memcpy(new_data_, this->data_, min_uu(this->len_, new_size) * sizeof(T));
354 MEM_freeN(static_cast<void *>(this->data_));
355 this->data_ = new_data_;
357
358 this->len_ = new_size;
359 constexpr GPUUsageType usage = device_only ? GPU_USAGE_DEVICE_ONLY : GPU_USAGE_DYNAMIC;
360 this->ssbo_ = GPU_storagebuf_create_ex(sizeof(T) * this->len_, nullptr, usage, this->name_);
361 }
362 }
363
364 /* Resize on access. */
366 {
367 BLI_assert(index >= 0);
368 if (index >= this->len_) {
369 size_t size = power_of_2_max_u(index + 1);
370 this->resize(size);
371 }
372 return this->data_[index];
373 }
374
375 /*
376 * Ensure the allocated size is not much larger than the currently required size,
377 * using the same heuristic as `get_or_resize`.
378 */
380 {
381 /* Don't go below the size used at creation. */
382 required_size = std::max(required_size, len);
383 size_t target_size = power_of_2_max_u(required_size);
384 if (this->len_ > target_size) {
385 this->resize(target_size);
386 }
387 }
388
389 int64_t size() const
390 {
391 return this->len_;
392 }
393
395 {
396 return {this->data_, this->len_};
397 }
398
400 {
401 std::swap(a.data_, b.data_);
402 std::swap(a.ssbo_, b.ssbo_);
403 std::swap(a.len_, b.len_);
404 std::swap(a.name_, b.name_);
405 }
406};
407
408template<
410 typename T,
412 int64_t len = (512u + (sizeof(T) - 1)) / sizeof(T)>
413class StorageVectorBuffer : public StorageArrayBuffer<T, len, false> {
414 private:
415 /* Number of items, not the allocated length. */
416 int64_t item_len_ = 0;
417
418 public:
419 StorageVectorBuffer(const char *name = nullptr) : StorageArrayBuffer<T, len, false>(name) {};
421
425 void clear()
426 {
427 item_len_ = 0;
428 }
429
435 {
436 this->trim_to_next_power_of_2(item_len_);
437 clear();
438 }
439
446 void append(const T &value)
447 {
448 this->append_as(value);
449 }
450 void append(T &&value)
451 {
452 this->append_as(std::move(value));
453 }
454 template<typename... ForwardT> void append_as(ForwardT &&...value)
455 {
456 if (item_len_ >= this->len_) {
457 size_t size = power_of_2_max_u(item_len_ + 1);
458 this->resize(size);
459 }
460 T *ptr = &this->data_[item_len_++];
461 new (ptr) T(std::forward<ForwardT>(value)...);
462 }
463
464 void extend(const Span<T> values)
465 {
466 /* TODO(fclem): Optimize to a single memcpy. */
467 for (auto v : values) {
468 this->append(v);
469 }
470 }
471
472 int64_t size() const
473 {
474 return item_len_;
475 }
476
477 bool is_empty() const
478 {
479 return this->size() == 0;
480 }
481
482 /* Avoid confusion with the other clear. */
483 void clear_to_zero() = delete;
484
486 {
488 std::swap(a.item_len_, b.item_len_);
489 }
490};
491
492template<
494 typename T,
496 bool device_only = false>
497class StorageBuffer : public T, public detail::StorageCommon<T, 1, device_only> {
498 public:
499 StorageBuffer(const char *name = nullptr) : T{}, detail::StorageCommon<T, 1, device_only>(name)
500 {
501 /* TODO(@fclem): How could we map this? */
502 this->data_ = static_cast<T *>(this);
503 }
504
506 {
507 *static_cast<T *>(this) = other;
508 return *this;
509 }
510
512 {
513 /* Swap content, but not `data_` pointers since they point to `this`. */
514 SWAP(T, static_cast<T>(a), static_cast<T>(b));
515 std::swap(a.ssbo_, b.ssbo_);
516 }
517};
518
520
521/* -------------------------------------------------------------------- */
524
526 protected:
527 gpu::Texture *tx_ = nullptr;
532 const char *name_;
533
534 public:
535 Texture(const char *name = "gpu::Texture") : name_(name) {}
536
537 Texture(const char *name,
539 eGPUTextureUsage usage,
540 int extent,
541 const float *data = nullptr,
542 bool cubemap = false,
543 int mip_len = 1)
544 : name_(name)
545 {
546 tx_ = create(extent, 0, 0, mip_len, format, usage, data, false, cubemap);
547 }
548
549 Texture(const char *name,
551 eGPUTextureUsage usage,
552 int extent,
553 int layers,
554 const float *data = nullptr,
555 bool cubemap = false,
556 int mip_len = 1)
557 : name_(name)
558 {
559 tx_ = create(extent, layers, 0, mip_len, format, usage, data, true, cubemap);
560 }
561
562 Texture(const char *name,
564 eGPUTextureUsage usage,
565 int2 extent,
566 const float *data = nullptr,
567 int mip_len = 1)
568 : name_(name)
569 {
570 tx_ = create(UNPACK2(extent), 0, mip_len, format, usage, data, false, false);
571 }
572
573 Texture(const char *name,
575 eGPUTextureUsage usage,
576 int2 extent,
577 int layers,
578 const float *data = nullptr,
579 int mip_len = 1)
580 : name_(name)
581 {
582 tx_ = create(UNPACK2(extent), layers, mip_len, format, usage, data, true, false);
583 }
584
585 Texture(const char *name,
587 eGPUTextureUsage usage,
588 int3 extent,
589 const float *data = nullptr,
590 int mip_len = 1)
591 : name_(name)
592 {
593 tx_ = create(UNPACK3(extent), mip_len, format, usage, data, false, false);
594 }
595
596 Texture(Texture &&other) = default;
598 {
599 free();
600 }
601
603 {
604 return tx_;
605 }
606
607 /* To be able to use it with DRW_shgroup_uniform_texture(). */
608 operator gpu::Texture *() const
609 {
610 BLI_assert(tx_ != nullptr);
611 return tx_;
612 }
613
614 /* To be able to use it with DRW_shgroup_uniform_texture_ref(). */
616 {
617 return &tx_;
618 }
619
622 {
623 return this;
624 }
625
627 {
628 if (this != std::addressof(a)) {
629 this->free();
630
631 this->tx_ = a.tx_;
632 this->name_ = a.name_;
633 this->stencil_view_ = a.stencil_view_;
634 this->layer_range_view_ = a.layer_range_view_;
635 this->mip_views_ = std::move(a.mip_views_);
636 this->layer_views_ = std::move(a.layer_views_);
637
638 a.tx_ = nullptr;
639 a.name_ = nullptr;
640 a.stencil_view_ = nullptr;
641 a.layer_range_view_ = nullptr;
642 a.mip_views_.clear();
643 a.layer_views_.clear();
644 }
645 return *this;
646 }
647
653 int extent,
655 const float *data = nullptr,
656 int mip_len = 1)
657 {
658 return ensure_impl(extent, 0, 0, mip_len, format, usage, data, false, false);
659 }
660
666 int extent,
667 int layers,
669 const float *data = nullptr,
670 int mip_len = 1)
671 {
672 BLI_assert(layers > 0);
673 return ensure_impl(extent, layers, 0, mip_len, format, usage, data, true, false);
674 }
675
681 int2 extent,
683 const float *data = nullptr,
684 int mip_len = 1)
685 {
686 return ensure_impl(UNPACK2(extent), 0, mip_len, format, usage, data, false, false);
687 }
688
694 int2 extent,
695 int layers,
697 const float *data = nullptr,
698 int mip_len = 1)
699 {
700 BLI_assert(layers > 0);
701 return ensure_impl(UNPACK2(extent), layers, mip_len, format, usage, data, true, false);
702 }
703
709 int3 extent,
711 const float *data = nullptr,
712 int mip_len = 1)
713 {
714 return ensure_impl(UNPACK3(extent), mip_len, format, usage, data, false, false);
715 }
716
722 int extent,
724 float *data = nullptr,
725 int mip_len = 1)
726 {
727 return ensure_impl(extent, extent, 0, mip_len, format, usage, data, false, true);
728 }
729
735 int extent,
736 int layers,
738 const float *data = nullptr,
739 int mip_len = 1)
740 {
741 return ensure_impl(extent, extent, layers, mip_len, format, usage, data, true, true);
742 }
743
748 bool ensure_mip_views(bool cube_as_array = false)
749 {
750 int mip_len = GPU_texture_mip_count(tx_);
751 if (mip_views_.size() != mip_len) {
752 for (gpu::Texture *&view : mip_views_) {
754 }
756 for (auto i : IndexRange(mip_len)) {
757 mip_views_.append(
758 GPU_texture_create_view(name_, tx_, format, i, 1, 0, 9999, cube_as_array, false));
759 }
760 return true;
761 }
762 return false;
763 }
764
766 {
767 BLI_assert_msg(miplvl < mip_views_.size(),
768 "Incorrect mip level requested. "
769 "Might be missing call to ensure_mip_views().");
770 return mip_views_[miplvl];
771 }
772
773 int mip_count() const
774 {
776 }
777
783 bool ensure_layer_views(bool cube_as_array = false)
784 {
785 int layer_len = GPU_texture_layer_count(tx_);
786 if (layer_views_.size() != layer_len) {
787 for (gpu::Texture *&view : layer_views_) {
789 }
791 for (auto i : IndexRange(layer_len)) {
792 layer_views_.append(
793 GPU_texture_create_view(name_, tx_, format, 0, 9999, i, 1, cube_as_array, false));
794 }
795 return true;
796 }
797 return false;
798 }
799
801 {
802 return layer_views_[layer];
803 }
804
805 gpu::Texture *stencil_view(bool cube_as_array = false)
806 {
807 if (stencil_view_ == nullptr) {
810 name_, tx_, format, 0, 9999, 0, 9999, cube_as_array, true);
811 }
812 return stencil_view_;
813 }
814
824 gpu::Texture *layer_range_view(int layer_start, int layer_len, bool cube_as_array = false)
825 {
826 BLI_assert(this->is_valid());
827 /* Make sure the range is valid as the GPU_texture_layer_count only returns the effective
828 * (clipped) range and not the requested range. */
829 BLI_assert_msg((layer_start + layer_len) <= GPU_texture_layer_count(tx_),
830 "Layer range needs to be valid");
831
832 int view_layer_len = (layer_range_view_) ? GPU_texture_layer_count(layer_range_view_) : -1;
833 if (layer_len != view_layer_len) {
837 name_, tx_, format, 0, 9999, layer_start, layer_len, cube_as_array, false);
838 }
839 return layer_range_view_;
840 }
841
845 bool is_valid() const
846 {
847 return tx_ != nullptr;
848 }
849
850 int width() const
851 {
852 return GPU_texture_width(tx_);
853 }
854
855 int height() const
856 {
857 return GPU_texture_height(tx_);
858 }
859
860 int depth() const
861 {
862 return GPU_texture_depth(tx_);
863 }
864
865 int pixel_count() const
866 {
868 }
869
870 bool is_depth() const
871 {
873 }
874
875 bool is_stencil() const
876 {
878 }
879
880 bool is_integer() const
881 {
883 }
884
885 bool is_cube() const
886 {
887 return GPU_texture_is_cube(tx_);
888 }
889
890 bool is_array() const
891 {
893 }
894
895 int3 size(int miplvl = 0) const
896 {
897 int3 size(1);
899 return size;
900 }
901
905 void clear(float4 values)
906 {
908 }
909
913 void clear(uint4 values)
914 {
915 GPU_texture_clear(tx_, GPU_DATA_UINT, &values[0]);
916 }
917
921 void clear(int4 values)
922 {
923 GPU_texture_clear(tx_, GPU_DATA_INT, &values[0]);
924 }
925
931 {
932 if (GPU_texture_dimensions(this->tx_) == 1) {
933 /* Clearing of 1D texture is currently unsupported. */
934 return;
935 }
936
938 this->clear(float4(NAN_FLT));
939 }
940 else if (GPU_texture_has_integer_format(this->tx_)) {
941 if (GPU_texture_has_signed_format(this->tx_)) {
942 this->clear(int4(0xF0F0F0F0));
943 }
944 else {
945 this->clear(uint4(0xF0F0F0F0));
946 }
947 }
948 }
949
954 template<typename T> T *read(eGPUDataFormat format, int miplvl = 0)
955 {
956 return reinterpret_cast<T *>(GPU_texture_read(tx_, format, miplvl));
957 }
958
959 void filter_mode(bool do_filter)
960 {
961 GPU_texture_filter_mode(tx_, do_filter);
962 }
963
967 void free()
968 {
971 }
972
976 static void swap(Texture &a, Texture &b)
977 {
978 std::swap(a.tx_, b.tx_);
979 std::swap(a.name_, b.name_);
980 std::swap(a.stencil_view_, b.stencil_view_);
981 std::swap(a.layer_range_view_, b.layer_range_view_);
982 std::swap(a.mip_views_, b.mip_views_);
983 std::swap(a.layer_views_, b.layer_views_);
984 }
985
986 protected:
1000
1001 private:
1002 bool ensure_impl(int w,
1003 int h = 0,
1004 int d = 0,
1005 int mip_len = 1,
1006 blender::gpu::TextureFormat format = blender::gpu::TextureFormat::UNORM_8_8_8_8,
1008 const float *data = nullptr,
1009 bool layered = false,
1010 bool cubemap = false)
1011
1012 {
1013 /* TODO(@fclem): In the future, we need to check if mip_count did not change.
1014 * For now it's ok as we always define all MIP level. */
1015 if (tx_) {
1016 int3 size(0);
1018 if (size != int3(w, h, d) || GPU_texture_format(tx_) != format ||
1019 GPU_texture_is_cube(tx_) != cubemap || GPU_texture_is_array(tx_) != layered)
1020 {
1021 free();
1022 }
1023 }
1024 if (tx_ == nullptr) {
1025 tx_ = create(w, h, d, mip_len, format, usage, data, layered, cubemap);
1026 if (is_valid() && data == nullptr && (G.debug & G_DEBUG_GPU)) {
1027 debug_clear();
1028 }
1029 return true;
1030 }
1031 return false;
1032 }
1033
1034 gpu::Texture *create(int w,
1035 int h,
1036 int d,
1037 int mip_len,
1039 eGPUTextureUsage usage,
1040 const float *data,
1041 bool layered,
1042 bool cubemap)
1043 {
1044 if (h == 0) {
1045 return GPU_texture_create_1d(name_, w, mip_len, format, usage, data);
1046 }
1047 if (cubemap) {
1048 if (layered) {
1049 return GPU_texture_create_cube_array(name_, w, d, mip_len, format, usage, data);
1050 }
1051 return GPU_texture_create_cube(name_, w, mip_len, format, usage, data);
1052 }
1053 if (d == 0) {
1054 if (layered) {
1055 return GPU_texture_create_1d_array(name_, w, h, mip_len, format, usage, data);
1056 }
1057 return GPU_texture_create_2d(name_, w, h, mip_len, format, usage, data);
1058 }
1059 if (layered) {
1060 return GPU_texture_create_2d_array(name_, w, h, d, mip_len, format, usage, data);
1061 }
1062 return GPU_texture_create_3d(name_, w, h, d, mip_len, format, usage, data);
1063 }
1064};
1065
1067 public:
1068 TextureFromPool(const char *name = "gpu::Texture") : Texture(name) {};
1069
1070 /* Always use `release()` after rendering. */
1071 void acquire(int2 extent,
1074 {
1075 BLI_assert(this->tx_ == nullptr);
1076
1077 this->tx_ = gpu::TexturePool::get().acquire_texture(UNPACK2(extent), format, usage);
1078
1079 if (G.debug & G_DEBUG_GPU) {
1080 debug_clear();
1081 }
1082 }
1083
1084 void release()
1085 {
1086 /* Allows multiple release. */
1087 if (this->tx_ == nullptr) {
1088 return;
1089 }
1091 this->tx_ = nullptr;
1092 }
1093
1104 static void swap(Texture &a, TextureFromPool &b)
1105 {
1106 swap(b, a);
1107 }
1109 {
1110 Texture::swap(a, b);
1111 }
1112
1115 {
1116 return this;
1117 }
1118
1120 bool ensure_1d(int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *) = delete;
1122 int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *) = delete;
1123 bool ensure_2d(int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, float *) = delete;
1125 int, int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *) = delete;
1127 int, int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *) = delete;
1129 delete;
1131 int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *) = delete;
1132 void filter_mode(bool) = delete;
1133 void free() = delete;
1134 gpu::Texture *mip_view(int) = delete;
1135 gpu::Texture *layer_view(int) = delete;
1137};
1138
1139class TextureRef : public Texture {
1140 public:
1141 TextureRef() = default;
1142
1144 {
1145 this->tx_ = nullptr;
1146 }
1147
1149 {
1150 if (assign_if_different(this->tx_, tex)) {
1152 }
1153 }
1154
1156 bool ensure_1d(int, int, blender::gpu::TextureFormat, const float *) = delete;
1157 bool ensure_1d_array(int, int, int, blender::gpu::TextureFormat, const float *) = delete;
1158 bool ensure_2d(int, int, int, blender::gpu::TextureFormat, const float *) = delete;
1159 bool ensure_2d_array(int, int, int, int, blender::gpu::TextureFormat, const float *) = delete;
1160 bool ensure_3d(int, int, int, int, blender::gpu::TextureFormat, const float *) = delete;
1161 bool ensure_cube(int, int, blender::gpu::TextureFormat, const float *) = delete;
1162 bool ensure_cube_array(int, int, int, blender::gpu::TextureFormat, const float *) = delete;
1163 void filter_mode(bool) = delete;
1164 void free() = delete;
1165 gpu::Texture *mip_view(int) = delete;
1166 gpu::Texture *layer_view(int) = delete;
1168};
1169
1174class Image {};
1175
1176static inline Image *as_image(gpu::Texture *tex)
1177{
1178 return reinterpret_cast<Image *>(tex);
1179}
1180
1181static inline Image **as_image(gpu::Texture **tex)
1182{
1183 return reinterpret_cast<Image **>(tex);
1184}
1185
1186static inline gpu::Texture *as_texture(Image *img)
1187{
1188 return reinterpret_cast<gpu::Texture *>(img);
1189}
1190
1191static inline gpu::Texture **as_texture(Image **img)
1192{
1193 return reinterpret_cast<gpu::Texture **>(img);
1194}
1195
1197
1198/* -------------------------------------------------------------------- */
1201
1203 private:
1204 gpu::FrameBuffer *fb_ = nullptr;
1205 const char *name_;
1206
1207 public:
1208 Framebuffer() : name_("") {};
1209 Framebuffer(const char *name) : name_(name) {};
1210
1212 {
1214 }
1215
1225 {
1226 if (fb_ == nullptr) {
1227 fb_ = GPU_framebuffer_create(name_);
1228 }
1229 GPUAttachment config[] = {
1230 depth, color1, color2, color3, color4, color5, color6, color7, color8};
1231 GPU_framebuffer_config_array(fb_, config, sizeof(config) / sizeof(GPUAttachment));
1232 }
1233
1237 void ensure(int2 target_size)
1238 {
1239 if (fb_ == nullptr) {
1240 fb_ = GPU_framebuffer_create(name_);
1241 }
1242 GPU_framebuffer_default_size(fb_, UNPACK2(target_size));
1243 }
1244
1245 void bind()
1246 {
1248 }
1249
1250 void clear_depth(float depth)
1251 {
1252 GPU_framebuffer_clear_depth(fb_, depth);
1253 }
1254
1256 {
1257 if (*this != a) {
1258 this->fb_ = a.fb_;
1259 this->name_ = a.name_;
1260 a.fb_ = nullptr;
1261 }
1262 return *this;
1263 }
1264
1265 operator gpu::FrameBuffer *() const
1266 {
1267 return fb_;
1268 }
1269
1271 {
1272 return &fb_;
1273 }
1274
1278 static void swap(Framebuffer &a, Framebuffer &b)
1279 {
1280 std::swap(a.fb_, b.fb_);
1281 std::swap(a.name_, b.name_);
1282 }
1283};
1284
1286
1287/* -------------------------------------------------------------------- */
1292
1293template<typename T, int64_t len> class SwapChain {
1294 private:
1295 BLI_STATIC_ASSERT(len > 1, "A swap-chain needs more than 1 unit in length.");
1296 std::array<T, len> chain_;
1297
1298 public:
1299 void swap()
1300 {
1301 for (auto i : IndexRange(len - 1)) {
1302 auto i_next = (i + 1) % len;
1303 if constexpr (std::is_trivial_v<T>) {
1304 std::swap(chain_[i], chain_[i_next]);
1305 }
1306 else {
1307 T::swap(chain_[i], chain_[i_next]);
1308 }
1309 }
1310 }
1311
1312 constexpr int64_t size()
1313 {
1314 return len;
1315 }
1316
1318 {
1319 return chain_[0];
1320 }
1321
1323 {
1324 /* Avoid modulo operation with negative numbers. */
1325 return chain_[(0 + len - 1) % len];
1326 }
1327
1329 {
1330 return chain_[(0 + 1) % len];
1331 }
1332
1333 const T &current() const
1334 {
1335 return chain_[0];
1336 }
1337
1338 const T &previous() const
1339 {
1340 /* Avoid modulo operation with negative numbers. */
1341 return chain_[(0 + len - 1) % len];
1342 }
1343
1344 const T &next() const
1345 {
1346 return chain_[(0 + 1) % len];
1347 }
1348};
1349
1351
1352} // namespace blender::draw
@ G_DEBUG_GPU
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE uint min_uu(uint a, uint b)
MINLINE unsigned int power_of_2_max_u(unsigned int x)
#define NAN_FLT
#define UNPACK2(a)
#define SWAP(type, a, b)
#define UNPACK3(a)
static AppView * view
blender::gpu::FrameBuffer * GPU_framebuffer_create(const char *name)
void GPU_framebuffer_default_size(blender::gpu::FrameBuffer *fb, int width, int height)
#define GPU_FRAMEBUFFER_FREE_SAFE(fb)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_clear_depth(blender::gpu::FrameBuffer *fb, float clear_depth)
void GPU_framebuffer_config_array(blender::gpu::FrameBuffer *fb, const GPUAttachment *config, int config_len)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
void GPU_storagebuf_free(blender::gpu::StorageBuf *ssbo)
blender::gpu::StorageBuf * GPU_storagebuf_create_ex(size_t size, const void *data, GPUUsageType usage, const char *name)
void GPU_storagebuf_clear_to_zero(blender::gpu::StorageBuf *ssbo)
void GPU_storagebuf_update(blender::gpu::StorageBuf *ssbo, const void *data)
void GPU_storagebuf_sync_to_host(blender::gpu::StorageBuf *ssbo)
void GPU_storagebuf_read(blender::gpu::StorageBuf *ssbo, void *data)
int GPU_texture_mip_count(const blender::gpu::Texture *texture)
void GPU_texture_clear(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *data)
blender::gpu::Texture * GPU_texture_create_view(const char *name, blender::gpu::Texture *source_texture, blender::gpu::TextureFormat view_format, int mip_start, int mip_len, int layer_start, int layer_len, bool cube_as_array, bool use_stencil)
blender::gpu::Texture * GPU_texture_create_2d_array(const char *name, int width, int height, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_get_mipmap_size(blender::gpu::Texture *texture, int mip_level, int *r_size)
int GPU_texture_height(const blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_cube(const char *name, int width, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
bool GPU_texture_has_integer_format(const blender::gpu::Texture *texture)
bool GPU_texture_has_depth_format(const blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_1d_array(const char *name, int width, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
blender::gpu::TextureFormat GPU_texture_format(const blender::gpu::Texture *texture)
bool GPU_texture_has_stencil_format(const blender::gpu::Texture *texture)
int GPU_texture_width(const blender::gpu::Texture *texture)
eGPUDataFormat
@ GPU_DATA_INT
@ GPU_DATA_UINT
@ GPU_DATA_FLOAT
bool GPU_texture_has_signed_format(const blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_cube_array(const char *name, int width, int layer_len, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_GENERAL
void * GPU_texture_read(blender::gpu::Texture *texture, eGPUDataFormat data_format, int mip_level)
bool GPU_texture_is_cube(const blender::gpu::Texture *texture)
bool GPU_texture_has_float_format(const blender::gpu::Texture *texture)
#define GPU_TEXTURE_FREE_SAFE(texture)
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
int GPU_texture_dimensions(const blender::gpu::Texture *texture)
void GPU_texture_filter_mode(blender::gpu::Texture *texture, bool use_filter)
int GPU_texture_layer_count(const blender::gpu::Texture *texture)
int GPU_texture_depth(const blender::gpu::Texture *texture)
bool GPU_texture_has_normalized_format(const blender::gpu::Texture *texture)
blender::gpu::Texture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const void *data)
blender::gpu::Texture * GPU_texture_create_1d(const char *name, int width, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
bool GPU_texture_is_array(const blender::gpu::Texture *texture)
void GPU_uniformbuf_free(blender::gpu::UniformBuf *ubo)
blender::gpu::UniformBuf * GPU_uniformbuf_create_ex(size_t size, const void *data, const char *name)
void GPU_uniformbuf_update(blender::gpu::UniformBuf *ubo, const void *data)
@ GPU_USAGE_DYNAMIC
@ GPU_USAGE_DEVICE_ONLY
Read Guarded memory(de)allocation.
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
NonCopyable(const NonCopyable &other)=delete
NonMovable(NonMovable &&other)=delete
static void swap(Framebuffer &a, Framebuffer &b)
void ensure(int2 target_size)
gpu::FrameBuffer ** operator&()
Framebuffer & operator=(Framebuffer &&a)
void ensure(GPUAttachment depth=GPU_ATTACHMENT_NONE, GPUAttachment color1=GPU_ATTACHMENT_NONE, GPUAttachment color2=GPU_ATTACHMENT_NONE, GPUAttachment color3=GPU_ATTACHMENT_NONE, GPUAttachment color4=GPU_ATTACHMENT_NONE, GPUAttachment color5=GPU_ATTACHMENT_NONE, GPUAttachment color6=GPU_ATTACHMENT_NONE, GPUAttachment color7=GPU_ATTACHMENT_NONE, GPUAttachment color8=GPU_ATTACHMENT_NONE)
StorageArrayBuffer(const char *name=nullptr)
static void swap(StorageArrayBuffer &a, StorageArrayBuffer &b)
MutableSpan< T > as_span() const
void trim_to_next_power_of_2(int64_t required_size)
static void swap(StorageBuffer< T > &a, StorageBuffer< T > &b)
StorageBuffer< T > & operator=(const T &other)
StorageBuffer(const char *name=nullptr)
StorageVectorBuffer(const char *name=nullptr)
static void swap(StorageVectorBuffer &a, StorageVectorBuffer &b)
void append_as(ForwardT &&...value)
void extend(const Span< T > values)
bool ensure_1d_array(int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
static void swap(TextureFromPool &a, Texture &b)
void acquire(int2 extent, blender::gpu::TextureFormat format, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL)
gpu::Texture * layer_view(int)=delete
bool ensure_cube(int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
bool ensure_cube_array(int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
gpu::Texture * stencil_view()=delete
static void swap(TextureFromPool &a, TextureFromPool &b)
static void swap(Texture &a, TextureFromPool &b)
bool ensure_3d(int, int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
TextureFromPool(const char *name="gpu::Texture")
bool ensure_2d_array(int, int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
void filter_mode(bool)=delete
gpu::Texture * mip_view(int)=delete
bool ensure_1d(int, int, blender::gpu::TextureFormat, eGPUTextureUsage, const float *)=delete
bool ensure_2d(int, int, int, blender::gpu::TextureFormat, eGPUTextureUsage, float *)=delete
gpu::Texture * layer_view(int)=delete
bool ensure_1d(int, int, blender::gpu::TextureFormat, const float *)=delete
bool ensure_cube(int, int, blender::gpu::TextureFormat, const float *)=delete
gpu::Texture * mip_view(int)=delete
bool ensure_cube_array(int, int, int, blender::gpu::TextureFormat, const float *)=delete
void filter_mode(bool)=delete
gpu::Texture * stencil_view()=delete
bool ensure_2d_array(int, int, int, int, blender::gpu::TextureFormat, const float *)=delete
bool ensure_3d(int, int, int, int, blender::gpu::TextureFormat, const float *)=delete
bool ensure_1d_array(int, int, int, blender::gpu::TextureFormat, const float *)=delete
bool ensure_2d(int, int, int, blender::gpu::TextureFormat, const float *)=delete
void wrap(gpu::Texture *tex)
Texture(const char *name, blender::gpu::TextureFormat format, eGPUTextureUsage usage, int2 extent, const float *data=nullptr, int mip_len=1)
bool ensure_1d(blender::gpu::TextureFormat format, int extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
bool ensure_2d_array(blender::gpu::TextureFormat format, int2 extent, int layers, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
bool ensure_mip_views(bool cube_as_array=false)
static void swap(Texture &a, Texture &b)
gpu::Texture * gpu_texture()
Texture(const char *name, blender::gpu::TextureFormat format, eGPUTextureUsage usage, int2 extent, int layers, const float *data=nullptr, int mip_len=1)
Texture(const char *name="gpu::Texture")
void clear(float4 values)
T * read(eGPUDataFormat format, int miplvl=0)
gpu::Texture ** operator&()
void clear(uint4 values)
bool ensure_1d_array(blender::gpu::TextureFormat format, int extent, int layers, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
Vector< gpu::Texture *, 0 > layer_views_
bool ensure_cube(blender::gpu::TextureFormat format, int extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, float *data=nullptr, int mip_len=1)
void clear(int4 values)
bool ensure_cube_array(blender::gpu::TextureFormat format, int extent, int layers, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void filter_mode(bool do_filter)
Texture(const char *name, blender::gpu::TextureFormat format, eGPUTextureUsage usage, int3 extent, const float *data=nullptr, int mip_len=1)
bool ensure_2d(blender::gpu::TextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
bool ensure_layer_views(bool cube_as_array=false)
gpu::Texture * layer_view(int layer)
Vector< gpu::Texture *, 0 > mip_views_
gpu::Texture * layer_range_view_
Texture(const char *name, blender::gpu::TextureFormat format, eGPUTextureUsage usage, int extent, int layers, const float *data=nullptr, bool cubemap=false, int mip_len=1)
gpu::Texture * layer_range_view(int layer_start, int layer_len, bool cube_as_array=false)
Texture & operator=(Texture &&a)
int3 size(int miplvl=0) const
bool ensure_3d(blender::gpu::TextureFormat format, int3 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
gpu::Texture * mip_view(int miplvl)
Texture(Texture &&other)=default
gpu::Texture * stencil_view(bool cube_as_array=false)
Texture(const char *name, blender::gpu::TextureFormat format, eGPUTextureUsage usage, int extent, const float *data=nullptr, bool cubemap=false, int mip_len=1)
UniformArrayBuffer(const char *name=nullptr)
UniformBuffer< T > & operator=(const T &other)
UniformBuffer(const char *name=nullptr)
BLI_STATIC_ASSERT(((sizeof(T) *len) % 16)==0, "Buffer size need to be aligned to size of float4.")
const T & operator[](int64_t index) const
StorageCommon(const char *name=nullptr)
UniformCommon(const char *name=nullptr)
TextureFromPool(const char *name="gpu::Texture")
Texture(const char *name="gpu::Texture")
blender::gpu::Texture * acquire_texture(int width, int height, blender::gpu::TextureFormat format, eGPUTextureUsage usage)
void give_texture_ownership(blender::gpu::Texture *tex)
void take_texture_ownership(blender::gpu::Texture *tex)
static TexturePool & get()
void release_texture(blender::gpu::Texture *tmp_tex)
char name_[DEBUG_NAME_LEN]
format
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define T
#define G(x, y, z)
static gpu::Texture * as_texture(Image *img)
BLI_STATIC_ASSERT(MBC_BATCH_LEN< 64, "Number of batches exceeded the limit of bit fields")
static Image * as_image(gpu::Texture *tex)
VecBase< int32_t, 4 > int4
VecBase< uint32_t, 4 > uint4
bool assign_if_different(T &old_value, T new_value)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
const char * name
#define swap(a, b)
Definition sort.cc:59
i
Definition text_draw.cc:230
uint len
PointerRNA * ptr
Definition wm_files.cc:4238