Blender  V3.3
mtl_uniform_buffer.mm
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BKE_global.h"
8 
9 #include "BLI_string.h"
10 
11 #include "gpu_backend.hh"
12 #include "gpu_context_private.hh"
13 
14 #include "mtl_backend.hh"
15 #include "mtl_context.hh"
16 #include "mtl_debug.hh"
17 #include "mtl_uniform_buffer.hh"
18 
19 namespace blender::gpu {
20 
21 MTLUniformBuf::MTLUniformBuf(size_t size, const char *name) : UniformBuf(size, name)
22 {
23 }
24 
26 {
27  if (metal_buffer_ != nullptr) {
28  metal_buffer_->free();
29  metal_buffer_ = nullptr;
30  }
31  has_data_ = false;
32 
33  /* Ensure UBO is not bound to active CTX.
34  * UBO bindings are reset upon Context-switch so we do not need
35  * to check deactivated context's. */
36  MTLContext *ctx = MTLContext::get();
37  if (ctx) {
38  for (int i = 0; i < MTL_MAX_UNIFORM_BUFFER_BINDINGS; i++) {
40  if (slot.bound && slot.ubo == this) {
41  slot.bound = false;
42  slot.ubo = nullptr;
43  }
44  }
45  }
46 }
47 
48 void MTLUniformBuf::update(const void *data)
49 {
50  BLI_assert(this);
52 
53  /* Free existing allocation.
54  * The previous UBO resource will be tracked by the memory manager,
55  * in case dependent GPU work is still executing. */
56  if (metal_buffer_ != nullptr) {
57  metal_buffer_->free();
58  metal_buffer_ = nullptr;
59  }
60 
61  /* Allocate MTL buffer */
62  MTLContext *ctx = static_cast<MTLContext *>(unwrap(GPU_context_active_get()));
63  BLI_assert(ctx);
64  BLI_assert(ctx->device);
65  UNUSED_VARS_NDEBUG(ctx);
66 
67  if (data != nullptr) {
69  size_in_bytes_, true, data);
70  has_data_ = true;
71 
72  metal_buffer_->set_label(@"Uniform Buffer");
73  BLI_assert(metal_buffer_ != nullptr);
74  BLI_assert(metal_buffer_->get_metal_buffer() != nil);
75  }
76  else {
77  /* If data is not yet present, no buffer will be allocated and MTLContext will use an empty
78  * null buffer, containing zeroes, if the UBO is bound. */
79  metal_buffer_ = nullptr;
80  has_data_ = false;
81  }
82 }
83 
84 void MTLUniformBuf::bind(int slot)
85 {
86  if (slot < 0) {
87  MTL_LOG_WARNING("Failed to bind UBO %p. uniform location %d invalid.\n", this, slot);
88  return;
89  }
90 
92 
93  /* Bind current UBO to active context. */
94  MTLContext *ctx = MTLContext::get();
95  BLI_assert(ctx);
96 
97  MTLUniformBufferBinding &ctx_ubo_bind_slot = ctx->pipeline_state.ubo_bindings[slot];
98  ctx_ubo_bind_slot.ubo = this;
99  ctx_ubo_bind_slot.bound = true;
100 
101  bind_slot_ = slot;
102  bound_ctx_ = ctx;
103 
104  /* Check if we have any deferred data to upload. */
105  if (data_ != nullptr) {
106  this->update(data_);
108  }
109 
110  /* Ensure there is at least an empty dummy buffer. */
111  if (metal_buffer_ == nullptr) {
112  this->update(nullptr);
113  }
114 }
115 
117 {
118  /* Unbind in debug mode to validate missing binds.
119  * Otherwise, only perform a full unbind upon destruction
120  * to ensure no lingering references. */
121 #ifndef NDEBUG
122  if (true) {
123 #else
124  if (G.debug & G_DEBUG_GPU) {
125 #endif
126  if (bound_ctx_ != nullptr && bind_slot_ > -1) {
127  MTLUniformBufferBinding &ctx_ubo_bind_slot =
128  bound_ctx_->pipeline_state.ubo_bindings[bind_slot_];
129  if (ctx_ubo_bind_slot.bound && ctx_ubo_bind_slot.ubo == this) {
130  ctx_ubo_bind_slot.bound = false;
131  ctx_ubo_bind_slot.ubo = nullptr;
132  }
133  }
134  }
135 
136  /* Reset bind index. */
137  bind_slot_ = -1;
138  bound_ctx_ = nullptr;
139 }
140 
141 id<MTLBuffer> MTLUniformBuf::get_metal_buffer(int *r_offset)
142 {
143  BLI_assert(this);
144  *r_offset = 0;
145  if (metal_buffer_ != nullptr && has_data_) {
146  *r_offset = 0;
147  metal_buffer_->debug_ensure_used();
148  return metal_buffer_->get_metal_buffer();
149  }
150  else {
151  *r_offset = 0;
152  return nil;
153  }
154 }
155 
157 {
158  BLI_assert(this);
159  return size_in_bytes_;
160 }
161 
162 } // blender::gpu
@ G_DEBUG_GPU
Definition: BKE_global.h:193
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define UNUSED_VARS_NDEBUG(...)
GPUContext * GPU_context_active_get(void)
Definition: gpu_context.cc:142
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
gpu::MTLBuffer * allocate_with_data(uint64_t size, bool cpu_visible, const void *data=nullptr)
Definition: mtl_memory.mm:67
id< MTLBuffer > get_metal_buffer() const
Definition: mtl_memory.mm:515
void set_label(NSString *str)
Definition: mtl_memory.mm:543
MTLContextGlobalShaderPipelineState pipeline_state
Definition: mtl_context.hh:600
id< MTLDevice > device
Definition: mtl_context.hh:604
static MTLContext * get()
Definition: mtl_context.hh:629
static MTLBufferPool & get_global_memory_manager()
Definition: mtl_context.hh:713
MTLUniformBuf(size_t size, const char *name)
void bind(int slot) override
void update(const void *data) override
id< MTLBuffer > get_metal_buffer(int *r_offset)
#define G(x, y, z)
#define MTL_MAX_UNIFORM_BUFFER_BINDINGS
#define MTL_LOG_WARNING(info,...)
Definition: mtl_debug.hh:36
static Context * unwrap(GPUContext *ctx)
MTLUniformBufferBinding ubo_bindings[MTL_MAX_UNIFORM_BUFFER_BINDINGS]
Definition: mtl_context.hh:404