43# define MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER 0
45# define MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER 1
50#define DEBUG_BIND_NULL_BUFFER_FOR_MISSING_UBO 1
54#define DEBUG_BIND_NULL_BUFFER_FOR_MISSING_SSBO 0
57#if DEBUG_BIND_NULL_BUFFER_FOR_MISSING_UBO == 1
58# define MTL_LOG_UBO_ERROR MTL_LOG_WARNING
60# define MTL_LOG_UBO_ERROR MTL_LOG_ERROR
63#if DEBUG_BIND_NULL_BUFFER_FOR_MISSING_SSBO == 1
64# define MTL_LOG_SSBO_ERROR MTL_LOG_WARNING
66# define MTL_LOG_SSBO_ERROR MTL_LOG_ERROR
85void MTLContext::set_ghost_context(GHOST_ContextHandle ghostCtxHandle)
91 if (default_fbo_mtltexture_) {
92 [default_fbo_mtltexture_ release];
93 default_fbo_mtltexture_ = nil;
103 if (ghost_cgl_ctx !=
NULL) {
107 "Binding GHOST context CGL %p to GPU context %p. (Device: %p, queue: %p, texture: %p)",
112 default_fbo_gputexture_);
115 if (default_fbo_mtltexture_) {
118 if (default_fbo_gputexture_) {
120 default_fbo_gputexture_ =
nullptr;
124 [default_fbo_mtltexture_ retain];
135 this->
label = default_fbo_mtltexture_.label;
141 if (!default_fbo_gputexture_) {
148 "-- Bound context %p for GPU context: %p is offscreen and does not have a default "
153 this->
label =
@"Offscreen Metal Context";
159 " Failed to bind GHOST context to MTLContext -- GHOST_ContextCGL is null "
160 "(GhostContext: %p, GhostContext_CGL: %p)",
167void MTLContext::set_ghost_window(GHOST_WindowHandle ghostWinHandle)
170 this->set_ghost_context((GHOST_ContextHandle)(ghostWin ? ghostWin->
getContext() :
NULL));
181 : memory_manager(*this), main_command_buffer(*this)
196 is_inside_frame_ =
false;
197 current_frame_index_ = 0;
201 null_attribute_buffer_ = nil;
204 default_fbo_mtltexture_ = nil;
205 default_fbo_gputexture_ =
nullptr;
222 [this->queue retain];
225#pragma clang diagnostic push
226#pragma clang diagnostic ignored "-Wobjc-method-access"
230 if (@available(macOS 13.3, *)) {
231 [this->
device setShouldMaximizeConcurrentCompilation:YES];
233#pragma clang diagnostic pop
247 MTLBackend::platform_init(
this);
248 MTLBackend::capabilities_init(
this);
293 if (default_fbo_gputexture_) {
295 default_fbo_gputexture_ =
nullptr;
297 if (default_fbo_mtltexture_) {
298 [default_fbo_mtltexture_ release];
299 default_fbo_mtltexture_ = nil;
315 this->pipeline_state.ubo_bindings[i].ubo !=
nullptr)
317 GPUUniformBuf *ubo =
wrap(
326 this->pipeline_state.ssbo_bindings[i].ssbo !=
nullptr)
339 if (sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] != nil) {
340 [sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] release];
341 sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] = nil;
349 if (custom_sampler_state_cache_[i] != nil) {
350 [custom_sampler_state_cache_[i] release];
351 custom_sampler_state_cache_[i] = nil;
356 for (
auto entry : cached_sampler_buffers_.values()) {
359 cached_sampler_buffers_.clear();
363 [null_buffer_ release];
365 if (null_attribute_buffer_) {
366 [null_attribute_buffer_ release];
374 [this->queue release];
391 is_inside_frame_ =
true;
402 is_inside_frame_ =
false;
421 else if (ghost_context_) {
422 this->set_ghost_context((GHOST_ContextHandle)ghost_context_);
428 this->pipeline_state.ubo_bindings[i].ubo !=
nullptr)
438 this->pipeline_state.ssbo_bindings[i].ssbo !=
nullptr)
500 BLI_assert(
false &&
"No framebuffer is bound!");
515 this->active_fb != this->main_command_buffer.get_active_framebuffer() ||
516 this->main_command_buffer.get_active_framebuffer()->get_dirty() ||
517 this->is_visibility_dirty())
522 MTL_LOG_WARNING(
"Framebuffer validation failed, falling back to default framebuffer");
526 MTL_LOG_ERROR(
"CRITICAL: DEFAULT FRAMEBUFFER FAIL VALIDATION!!");
531 bool new_render_pass =
false;
532 id<MTLRenderCommandEncoder> new_enc =
535 if (new_render_pass) {
563 if (null_buffer_ != nil) {
572 static const int null_buffer_size = 20480;
573 null_buffer_ = [this->
device newBufferWithLength:null_buffer_size
574 options:MTLResourceStorageModeManaged];
575 [null_buffer_ retain];
577 memcpy([null_buffer_ contents], null_data, null_buffer_size);
578 [null_buffer_ didModifyRange:NSMakeRange(0, null_buffer_size)];
587 if (null_attribute_buffer_ != nil) {
588 return null_attribute_buffer_;
593 static const int null_buffer_size = 256;
594 null_attribute_buffer_ = [this->
device newBufferWithLength:null_buffer_size
595 options:MTLResourceStorageModeManaged];
597 [null_attribute_buffer_ retain];
598 float data[4] = {0.0f, 0.0f, 0.0f, 1.0f};
599 memcpy([null_attribute_buffer_ contents], data,
sizeof(
float) * 4);
600 [null_attribute_buffer_ didModifyRange:NSMakeRange(0, null_buffer_size)];
602 return null_attribute_buffer_;
609 gpu::MTLTexture *dummy_tex = dummy_textures_[sampler_format][type - 1];
610 if (dummy_tex !=
nullptr) {
616 switch (sampler_format) {
634 GPUTexture *
tex =
nullptr;
659 if (!dummy_verts_[sampler_format]) {
665 switch (sampler_format) {
684 &dummy_vertformat_[sampler_format],
"dummy", comp_type, 4, fetch_mode);
686 dummy_vertformat_[sampler_format],
697 dummy_textures_[sampler_format][type - 1] = metal_tex;
709 reinterpret_cast<GPUTexture *
>(
static_cast<Texture *
>(dummy_textures_[
format][
tex])));
713 if (dummy_verts_[
format]) {
759 MTLColorWriteMaskBlue | MTLColorWriteMaskAlpha;
810 MTLStencilOperationKeep;
814 MTLStencilOperationKeep;
846 const int(&viewport_info)[4] = viewports[
v];
930 "Bound active shader is not valid (Missing/invalid implementation for Metal).", );
946 if (shader_interface ==
nullptr) {
947 MTL_LOG_WARNING(
"Bound active shader does not have a valid shader interface!", );
957 if (!pipeline_state_instance) {
958 MTL_LOG_ERROR(
"Failed to bake Metal pipeline state for shader: %s",
964 if (pipeline_state_instance->
pso) {
968 id<MTLRenderCommandEncoder> rec =
972 MTL_LOG_ERROR(
"ensure_render_pipeline_state called while render pass is not active.");
979 [rec setRenderPipelineState:pipeline_state_instance->
pso];
996 BLI_assert(mtl_prim_type == MTLPrimitiveTypeLine ||
997 mtl_prim_type == MTLPrimitiveTypeTriangle ||
998 mtl_prim_type == MTLPrimitiveTypePoint);
1004 id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer();
1007 if (tf_buffer_mtl != nil) {
1008 [rec setVertexBuffer:tf_buffer_mtl
1011 MTL_LOG_INFO(
"Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)",
1032 MTL_LOG_INFO(
"Binding null attribute buffer at index: %d",
1046 MTLViewport &viewport = viewports[
v];
1058 MTLViewport viewport;
1065 [rec setViewport:viewport];
1074 MTLScissorRect scissor;
1100 bool is_attachmentless = (default_w == 0) && (default_h == 0);
1103 scissor.width = (is_attachmentless) ? render_fb->
get_width() : default_w;
1104 scissor.height = (is_attachmentless) ? render_fb->
get_height() : default_h;
1110 [rec setScissorRect:scissor];
1114 ~MTL_PIPELINE_STATE_SCISSOR_FLAG);
1122 MTLWindingClockwise :
1123 MTLWindingCounterClockwise;
1124 [rec setFrontFacingWinding:winding];
1126 ~MTL_PIPELINE_STATE_FRONT_FACING_FLAG);
1132 MTLCullMode mode = MTLCullModeNone;
1136 mode = MTLCullModeNone;
1139 mode = MTLCullModeFront;
1142 mode = MTLCullModeBack;
1149 [rec setCullMode:mode];
1151 ~MTL_PIPELINE_STATE_CULLMODE_FLAG);
1163 id<MTLRenderCommandEncoder> ,
1178 if (push_constant_block.
size > 0) {
1220 id<MTLBuffer> ubo_buffer = nil;
1221 size_t ubo_size = 0;
1223 bool bind_dummy_buffer =
false;
1232 if (ubo_buffer == nil) {
1233 bind_dummy_buffer =
true;
1251 if (expected_size == 0) {
1261 "Shader interface expects UBO, but shader reflection data reports that it "
1266 if (ubo_size < expected_size) {
1268 "[UBO] UBO (UBO Name: %s) bound at location: %d (buffer[[%d]]) with size "
1269 "%lu (Expected size "
1270 "%d) (Shader Name: %s) is too small -- binding NULL buffer. This is likely an "
1271 "over-binding, which is not used, but we need this to avoid validation "
1279 bind_dummy_buffer =
true;
1286 "[UBO] Shader '%s' expected UBO '%s' to be bound at buffer slot: %d "
1287 "(buffer[[%d]])-- but "
1288 "nothing was bound -- binding dummy buffer",
1293 bind_dummy_buffer =
true;
1296 if (bind_dummy_buffer) {
1299 ubo_size = [ubo_buffer
length];
1302 if (ubo_buffer != nil) {
1321 "[UBO] Shader '%s' has UBO '%s' bound at buffer index: %d -- but MTLBuffer "
1342 id<MTLBuffer> ssbo_buffer = nil;
1343 size_t ssbo_size = 0;
1358 "[SSBO] Shader '%s' expected SSBO '%s' to be bound at buffer location: %d "
1359 "(buffer[[%d]]) -- "
1361 "nothing was bound.",
1367#if DEBUG_BIND_NULL_BUFFER_FOR_MISSING_SSBO == 1
1369 ssbo_size = [ssbo_buffer
length];
1373 if (ssbo_buffer != nil) {
1391 "[SSBO] Shader '%s' had SSBO '%s' bound at SSBO location: %d "
1393 "%d]]) -- but bound MTLStorageBuf was nil.",
1408 id<MTLComputeCommandEncoder> ,
1417 if (push_constant_block.
size > 0) {
1450 id<MTLBuffer> ubo_buffer = nil;
1451 size_t ubo_size = 0;
1453 bool bind_dummy_buffer =
false;
1463 if (ubo_buffer == nil) {
1464 bind_dummy_buffer =
true;
1473 "[UBO] Shader '%s' expected UBO '%s' to be bound at buffer location: %d "
1474 "(buffer[[%d]]) -- but "
1475 "nothing was bound -- binding dummy buffer",
1480 bind_dummy_buffer =
true;
1483 if (bind_dummy_buffer) {
1486 ubo_size = [ubo_buffer
length];
1489 if (ubo_buffer != nil) {
1501 "[UBO] Compute Shader '%s' has UBO '%s' bound at buffer index: %d -- but MTLBuffer "
1521 id<MTLBuffer> ssbo_buffer = nil;
1537 "[SSBO] Shader '%s' expected SSBO '%s' to be bound at SSBO location: %d "
1540 "nothing was bound.",
1546#if DEBUG_BIND_NULL_BUFFER_FOR_MISSING_SSBO == 1
1548 ssbo_size = [ssbo_buffer
length];
1552 if (ssbo_buffer != nil) {
1564 "[SSBO] Shader '%s' had SSBO '%s' bound at SSBO location: %d "
1566 "%d]]) -- but bound MTLStorageBuf was nil.",
1580 id<MTLRenderCommandEncoder> rec,
1592 int vertex_arg_buffer_bind_index = -1;
1593 int fragment_arg_buffer_bind_index = -1;
1610 if (!shader_texture_info.
used) {
1625 int location = shader_texture_info.
location;
1630 bool bind_dummy_texture =
true;
1631 if (resource_bind_table[location].used) {
1632 gpu::MTLTexture *bound_texture = resource_bind_table[location].texture_resource;
1639 if (shader_texture_info.
type == bound_texture->
type_) {
1642 id<MTLTexture>
tex = bound_texture->get_metal_handle();
1670 bind_dummy_texture =
false;
1677 "(Shader '%s') Texture (%s) %p bound to slot %d is incompatible -- Wrong "
1678 "texture target type. (Expecting type %d, actual type %d) (binding "
1679 "name:'%s')(texture name:'%s')",
1681 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1684 shader_texture_info.
type,
1685 bound_texture->
type_,
1692 "Shader '%s' expected texture (%s) to be bound to location %d (texture[[%d]]) -- No "
1694 "bound. (name:'%s')",
1696 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1705 if (bind_dummy_texture) {
1709 ->get_metal_handle(),
1718 ->get_metal_handle(),
1728 "Shader %p expected texture (%s) to be bound to slot %d -- Slot exceeds the "
1729 "hardware/API limit of '%d'. (name:'%s')",
1731 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1740 if (use_argument_buffer_for_samplers) {
1756 BLI_assert(vertex_arg_buffer_bind_index >= 0 || fragment_arg_buffer_bind_index >= 0);
1757 if (vertex_arg_buffer_bind_index >= 0 || fragment_arg_buffer_bind_index >= 0) {
1763 vertex_arg_buffer_bind_index);
1764 assert(arg_buffer_idx < 32);
1767 if (argument_encoder == nil) {
1768 argument_encoder = [pipeline_state_instance->
vert
1769 newArgumentEncoderWithBufferIndex:arg_buffer_idx];
1782 gpu::MTLBuffer **cached_smp_buffer_search = this->cached_sampler_buffers_.lookup_ptr(
1784 if (cached_smp_buffer_search !=
nullptr) {
1785 encoder_buffer = *cached_smp_buffer_search;
1789 size_t size = [argument_encoder encodedLength];
1790 size_t alignment =
max_uu([argument_encoder alignment], 256);
1791 size_t size_align_delta = (size % alignment);
1792 size_t aligned_alloc_size = ((alignment > 1) && (size_align_delta > 0)) ?
1793 size + (alignment - (size % alignment)) :
1801 [argument_encoder setArgumentBuffer:encoder_buffer->
get_metal_buffer() offset:0];
1805 encoder_buffer->
flush();
1808 this->cached_sampler_buffers_.add_new(this->samplers_, encoder_buffer);
1813 vertex_arg_buffer_bind_index);
1818 if (fragment_arg_buffer_bind_index >= 0) {
1821 fragment_arg_buffer_bind_index);
1832 id<MTLComputeCommandEncoder> rec,
1844 int compute_arg_buffer_bind_index = -1;
1860 if (!shader_texture_info.
used) {
1875 int location = shader_texture_info.
location;
1880 bool bind_dummy_texture =
true;
1881 if (resource_bind_table[location].used) {
1882 gpu::MTLTexture *bound_texture = resource_bind_table[location].texture_resource;
1889 if (shader_texture_info.
type == bound_texture->
type_) {
1892 id<MTLTexture>
tex = bound_texture->get_metal_handle();
1897 tex = bound_texture->get_metal_handle_base();
1921 bind_dummy_texture =
false;
1928 "(Shader '%s') Texture (%s) %p bound to slot %d is incompatible -- Wrong "
1929 "texture target type. (Expecting type %d, actual type %d) (binding "
1930 "name:'%s')(texture name:'%s')",
1932 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1935 shader_texture_info.
type,
1936 bound_texture->
type_,
1943 "Shader '%s' expected texture (%s) to be bound to location %d (texture[[%d]]) -- No "
1945 "bound. (name:'%s')",
1947 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1956 if (bind_dummy_texture) {
1960 ->get_metal_handle(),
1971 "Shader %p expected texture (%s) to be bound to slot %d -- Slot exceeds the "
1972 "hardware/API limit of '%d'. (name:'%s')",
1974 is_resource_sampler ?
"TextureSampler" :
"TextureImage",
1983 if (use_argument_buffer_for_samplers) {
1999 BLI_assert(compute_arg_buffer_bind_index >= 0);
2000 if (compute_arg_buffer_bind_index >= 0) {
2006 compute_arg_buffer_bind_index);
2007 assert(arg_buffer_idx < 32);
2010 if (argument_encoder == nil) {
2011 argument_encoder = [pipeline_state_instance->
compute
2012 newArgumentEncoderWithBufferIndex:arg_buffer_idx];
2025 gpu::MTLBuffer **cached_smp_buffer_search = this->cached_sampler_buffers_.lookup_ptr(
2027 if (cached_smp_buffer_search !=
nullptr) {
2028 encoder_buffer = *cached_smp_buffer_search;
2032 size_t size = [argument_encoder encodedLength];
2033 size_t alignment =
max_uu([argument_encoder alignment], 256);
2034 size_t size_align_delta = (size % alignment);
2035 size_t aligned_alloc_size = ((alignment > 1) && (size_align_delta > 0)) ?
2036 size + (alignment - (size % alignment)) :
2044 [argument_encoder setArgumentBuffer:encoder_buffer->
get_metal_buffer() offset:0];
2048 encoder_buffer->
flush();
2051 this->cached_sampler_buffers_.add_new(this->samplers_, encoder_buffer);
2056 compute_arg_buffer_bind_index);
2080 bool hasDepthTarget =
fb->has_depth_attachment();
2081 bool hasStencilTarget =
fb->has_stencil_attachment();
2083 if (hasDepthTarget || hasStencilTarget) {
2090 id<MTLDepthStencilState> ds_state = nil;
2091 id<MTLDepthStencilState> *depth_stencil_state_lookup =
2095 if (depth_stencil_state_lookup ==
nullptr) {
2097 MTLDepthStencilDescriptor *ds_state_desc = [[[MTLDepthStencilDescriptor alloc]
init]
2100 if (hasDepthTarget) {
2101 ds_state_desc.depthWriteEnabled =
2103 ds_state_desc.depthCompareFunction =
2106 MTLCompareFunctionAlways;
2109 if (hasStencilTarget) {
2110 ds_state_desc.backFaceStencil.readMask =
2112 ds_state_desc.backFaceStencil.writeMask =
2114 ds_state_desc.backFaceStencil.stencilFailureOperation =
2116 ds_state_desc.backFaceStencil.depthFailureOperation =
2118 ds_state_desc.backFaceStencil.depthStencilPassOperation =
2120 ds_state_desc.backFaceStencil.stencilCompareFunction =
2123 MTLCompareFunctionAlways;
2125 ds_state_desc.frontFaceStencil.readMask =
2127 ds_state_desc.frontFaceStencil.writeMask =
2129 ds_state_desc.frontFaceStencil.stencilFailureOperation =
2131 ds_state_desc.frontFaceStencil.depthFailureOperation =
2133 ds_state_desc.frontFaceStencil.depthStencilPassOperation =
2135 ds_state_desc.frontFaceStencil.stencilCompareFunction =
2138 MTLCompareFunctionAlways;
2142 ds_state = [this->
device newDepthStencilStateWithDescriptor:ds_state_desc];
2149 ds_state = *depth_stencil_state_lookup;
2155 if (ds_state != nil) {
2157 [rec setDepthStencilState:ds_state];
2163 if (hasStencilTarget) {
2169 [rec setStencilReferenceValue:stencil_ref_value];
2174 if (hasDepthTarget) {
2175 bool doBias =
false;
2176 switch (prim_type) {
2177 case MTLPrimitiveTypeTriangle:
2178 case MTLPrimitiveTypeTriangleStrip:
2181 case MTLPrimitiveTypeLine:
2182 case MTLPrimitiveTypeLineStrip:
2185 case MTLPrimitiveTypePoint:
2213 "Bound active shader is not valid (Missing/invalid implementation for Metal).", );
2220 if (shader_interface ==
nullptr) {
2221 MTL_LOG_WARNING(
"Bound active shader does not have a valid shader interface!", );
2232 compute_pipeline_descriptor);
2234 if (compute_pso_inst ==
nullptr || compute_pso_inst->
pso == nil) {
2238 return compute_pso_inst;
2246 if (compute_pso_inst ==
nullptr) {
2250#if MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER == 1
2259 id<MTLComputeCommandEncoder> compute_encoder =
2283 [compute_encoder dispatchThreadgroups:MTLSizeMake(
max_ii(groups_x_len, 1),
2289#if MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER == 1
2297#if MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER == 1
2309 id<MTLComputeCommandEncoder> compute_encoder =
2334 if (mtl_indirect_buf == nil) {
2335 MTL_LOG_WARNING(
"Metal Indirect Compute dispatch storage buffer does not exist.");
2343 dispatchThreadgroupsWithIndirectBuffer:mtl_indirect_buf
2344 indirectBufferOffset:0
2348#if MTL_DEBUG_SINGLE_DISPATCH_PER_ENCODER == 1
2365 visibility_is_dirty_ = (buffer != visibility_buffer_) || visibility_is_dirty_;
2366 visibility_buffer_ = buffer;
2372 visibility_is_dirty_ = (visibility_buffer_ !=
nullptr) || visibility_is_dirty_;
2373 visibility_buffer_ =
nullptr;
2379 return visibility_buffer_;
2384 visibility_is_dirty_ =
false;
2389 return visibility_is_dirty_;
2406 MTL_LOG_ERROR(
"Attempting to bind texture '%s' to invalid texture unit %d",
2420 resource_bind_table[texture_unit].used =
true;
2421 mtl_texture->is_bound_ =
true;
2430 MTL_LOG_ERROR(
"Attempting to bind sampler to invalid sampler unit %d", sampler_unit);
2450 if (resource_bind_table[i].texture_resource == mtl_texture) {
2452 resource_bind_table[i].used =
false;
2457 mtl_texture->is_bound_ =
false;
2469 if (resource_bind_table[t].used && resource_bind_table[t].texture_resource) {
2470 resource_bind_table[t].
used =
false;
2471 resource_bind_table[t].texture_resource =
nullptr;
2492 switch (wrap_mode) {
2494 return MTLSamplerAddressModeClampToEdge;
2496 return MTLSamplerAddressModeRepeat;
2498 return MTLSamplerAddressModeMirrorRepeat;
2500 return MTLSamplerAddressModeClampToBorderColor;
2503 return MTLSamplerAddressModeClampToEdge;
2511 const MTLSamplerAddressMode extend_t =
to_mtl_type(extend_yz);
2515 const MTLSamplerAddressMode extend_s =
to_mtl_type(extend_x);
2520 MTLSamplerDescriptor *
descriptor = [[MTLSamplerDescriptor alloc]
init];
2525 descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
2527 MTLSamplerMinMagFilterLinear :
2528 MTLSamplerMinMagFilterNearest;
2530 MTLSamplerMinMagFilterLinear :
2531 MTLSamplerMinMagFilterNearest;
2533 MTLSamplerMipFilterLinear :
2534 MTLSamplerMipFilterNotMipmapped;
2537 float aniso_filter =
max_ff(16,
U.anisotropic_filter);
2539 descriptor.compareFunction = MTLCompareFunctionAlways;
2543 sampler_state_cache_[extend_yz_i][extend_x_i][filtering_i] =
state;
2553 MTLSamplerDescriptor *
descriptor = [[MTLSamplerDescriptor alloc]
init];
2554 descriptor.minFilter = MTLSamplerMinMagFilterLinear;
2555 descriptor.magFilter = MTLSamplerMinMagFilterLinear;
2556 descriptor.compareFunction = MTLCompareFunctionLessEqual;
2561 id<MTLSamplerState> compare_state = [this->
device newSamplerStateWithDescriptor:
descriptor];
2571 MTLSamplerDescriptor *
descriptor = [[MTLSamplerDescriptor alloc]
init];
2572 descriptor.minFilter = MTLSamplerMinMagFilterLinear;
2573 descriptor.magFilter = MTLSamplerMinMagFilterLinear;
2574 descriptor.mipFilter = MTLSamplerMipFilterNearest;
2578 id<MTLSamplerState> icon_state = [this->
device newSamplerStateWithDescriptor:
descriptor];
2588 if (default_sampler_state_ == nil) {
2591 return default_sampler_state_;
2602 if (buffer_clear_pso_ != nil) {
2603 return buffer_clear_pso_;
2614 struct BufferClearParams {\
2617 kernel void compute_buffer_clear(constant BufferClearParams ¶ms [[buffer(0)]],\
2618 device uint32_t* output_data [[buffer(1)]],\
2619 uint position [[thread_position_in_grid]])\
2621 output_data[position] = params.clear_value;\
2623 NSString *compute_buffer_clear_src = [NSString stringWithUTF8String:src];
2626 MTLCompileOptions *
options = [[[MTLCompileOptions alloc]
init] autorelease];
2627 options.languageVersion = MTLLanguageVersion2_2;
2629 NSError *
error =
nullptr;
2630 id<MTLLibrary> temp_lib = [[ctx->
device newLibraryWithSource:compute_buffer_clear_src
2635 if ([[
error localizedDescription] rangeOfString:
@"Compilation succeeded"].location ==
2638 NSLog(
@"Compile Error - Metal Shader Library error %@ ",
error);
2646 id<MTLFunction> temp_compute_function = [[temp_lib newFunctionWithName:
@"compute_buffer_clear"]
2651 buffer_clear_pso_ = [ctx->
device newComputePipelineStateWithFunction:temp_compute_function
2653 if (
error || buffer_clear_pso_ == nil) {
2654 NSLog(
@"Failed to prepare compute_buffer_clear MTLComputePipelineState %@",
error);
2659 [buffer_clear_pso_ retain];
2663 return buffer_clear_pso_;
2672void present(MTLRenderPassDescriptor *blit_descriptor,
2673 id<MTLRenderPipelineState> blit_pso,
2674 id<MTLTexture> swapchain_texture,
2675 id<CAMetalDrawable> drawable)
2695 perf_max_drawables = 1;
2698 perf_max_drawables = 2;
2708 id<MTLCommandBuffer> cmdbuf = [ctx->
queue commandBuffer];
2712 id<MTLRenderCommandEncoder> enc = [cmdbuf renderCommandEncoderWithDescriptor:blit_descriptor];
2713 [enc setRenderPipelineState:blit_pso];
2714 [enc setFragmentTexture:swapchain_texture atIndex:0];
2715 [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
2720 [cmdbuf presentDrawable:drawable];
2729 std::chrono::time_point submission_time = std::chrono::high_resolution_clock::now();
2733 [cmdbuf addCompletedHandler:^(id<MTLCommandBuffer> ) {
2743 std::chrono::time_point completion_time = std::chrono::high_resolution_clock::now();
2744 int64_t microseconds_per_frame = std::chrono::duration_cast<std::chrono::microseconds>(
2745 completion_time - submission_time)
2749 MTL_LOG_INFO(
"Frame Latency: %f ms (Rolling avg: %f ms Drawables: %d)",
2750 ((
float)microseconds_per_frame) / 1000.0f,
2752 perf_max_drawables);
2759 [cmdbuf waitUntilCompleted];
2762 NSLog(
@"%@",
error);
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
void BLI_kdtree_nd_ free(KDTree *tree)
MINLINE uint min_uu(uint a, uint b)
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE uint max_uu(uint a, uint b)
MINLINE int max_ii(int a, int b)
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
#define UNUSED_VARS_NDEBUG(...)
typedef double(DMatrix)[4][4]
bool GPU_use_parallel_compilation()
#define GPU_MAX_VIEWPORTS
void GPU_matrix_bind(GPUShader *shader)
@ GPU_SAMPLER_CUSTOM_ICON
@ GPU_SAMPLER_CUSTOM_COMPARE
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_1d(const char *name, int width, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
@ GPU_SAMPLER_STATE_TYPE_CUSTOM
@ GPU_SAMPLER_STATE_TYPE_INTERNAL
static const int GPU_SAMPLER_FILTERING_TYPES_COUNT
GPUTexture * GPU_texture_create_cube_array(const char *name, int width, int layer_len, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_from_vertbuf(const char *name, blender::gpu::VertBuf *vertex_buf)
@ GPU_TEXTURE_USAGE_GENERAL
@ GPU_TEXTURE_USAGE_ATOMIC
@ GPU_SAMPLER_EXTEND_MODE_MIRRORED_REPEAT
@ GPU_SAMPLER_EXTEND_MODE_REPEAT
@ GPU_SAMPLER_EXTEND_MODE_EXTEND
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
GPUTexture * GPU_texture_create_2d_array(const char *name, int width, int height, int layer_len, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const void *data)
#define GPU_SAMPLER_CUSTOM_TYPES_COUNT
void GPU_texture_unbind_all()
GPUTexture * GPU_texture_create_cube(const char *name, int width, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_1d_array(const char *name, int width, int layer_len, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
@ GPU_SAMPLER_FILTERING_MIPMAP
@ GPU_SAMPLER_FILTERING_LINEAR
#define GPU_SAMPLER_EXTEND_MODES_COUNT
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
struct GPUShader GPUShader
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
void metalRegisterPresentCallback(void(*callback)(MTLRenderPassDescriptor *, id< MTLRenderPipelineState >, id< MTLTexture >, id< CAMetalDrawable >))
id< MTLTexture > metalOverlayTexture()
MTLDevice * metalDevice()
MTLCommandQueue * metalCommandQueue()
GHOST_Context * getContext()
StateManager * state_manager
bool is_active_on_thread()
ShaderCompiler * compiler
static MTLBackend * get()
void init(id< MTLDevice > device)
MTLSafeFreeList * get_current_safe_list()
gpu::MTLBuffer * allocate(uint64_t size, bool cpu_visible)
id< MTLBuffer > get_metal_buffer() const
MTLFrameBuffer * get_active_framebuffer()
bool do_break_submission()
void prepare(bool supports_render=true)
MTLRenderPassState & get_render_pass_state()
id< MTLRenderCommandEncoder > ensure_begin_render_command_encoder(MTLFrameBuffer *ctx_framebuffer, bool force_begin, bool *r_new_pass)
bool is_inside_render_pass()
id< MTLComputeCommandEncoder > ensure_begin_compute_encoder()
static int num_active_cmd_bufs
MTLComputeState & get_compute_state()
id< MTLRenderCommandEncoder > get_active_render_command_encoder()
void bind_compute_bytes(const void *bytes, uint64_t length, uint index)
void bind_compute_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
void bind_compute_texture(id< MTLTexture > tex, uint slot)
void bind_compute_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void bind_pso(id< MTLComputePipelineState > pso)
id< MTLComputePipelineState > get_buffer_clear_pso()
bool ensure_render_pipeline_state(MTLPrimitiveType prim_type)
MTLFrameBuffer * get_current_framebuffer()
MTLFrameBuffer * get_default_framebuffer()
static std::atomic< int64_t > avg_drawable_latency_us
MTLContextComputeUtils & get_compute_utils()
const MTLComputePipelineStateInstance * ensure_compute_pipeline_state()
void clear_visibility_dirty()
id< MTLSamplerState > get_sampler_from_state(MTLSamplerState state)
MTLContext(void *ghost_window, void *ghost_context)
void deactivate() override
static void latency_resolve_average(int64_t frame_latency_us)
gpu::MTLBuffer * get_visibility_buffer() const
void set_visibility_buffer(gpu::MTLBuffer *buffer)
void set_scissor_enabled(bool scissor_enabled)
void framebuffer_bind(MTLFrameBuffer *framebuffer)
id< MTLRenderCommandEncoder > ensure_begin_render_pass()
static MTLContext * get()
id< MTLBuffer > get_null_buffer()
id< MTLBuffer > get_null_attribute_buffer()
static void global_memory_manager_release_ref()
MTLScratchBufferManager memory_manager
void pipeline_state_init()
MTLContextGlobalShaderPipelineState pipeline_state
void ensure_depth_stencil_state(MTLPrimitiveType prim_type)
static MTLBufferPool * global_memory_manager
void end_frame() override
static int global_memory_manager_refcount
MTLShader * get_active_shader()
void set_viewport(int origin_x, int origin_y, int width, int height)
static int64_t frame_latency[MTL_FRAME_AVERAGE_COUNT]
static std::mutex global_memory_manager_reflock
void sampler_bind(MTLSamplerState, uint sampler_unit)
void texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit, bool is_image)
gpu::MTLTexture * get_dummy_texture(eGPUTextureType type, eGPUSamplerFormat sampler_format)
void begin_frame() override
void framebuffer_restore()
void set_viewports(int count, const int(&viewports)[GPU_MAX_VIEWPORTS][4])
void ensure_texture_bindings(id< MTLRenderCommandEncoder > rec, MTLShaderInterface *shader_interface, const MTLRenderPipelineStateInstance *pipeline_state_instance)
void compute_dispatch_indirect(StorageBuf *indirect_buf)
void sampler_state_cache_init()
static void check_error(const char *info)
void texture_unbind(gpu::MTLTexture *mtl_texture, bool is_image)
void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
MTLCommandBufferManager main_command_buffer
id< MTLSamplerState > get_default_sampler_state()
bool is_visibility_dirty() const
void texture_unbind_all(bool is_image)
static void global_memory_manager_acquire_ref()
void memory_statistics_get(int *r_total_mem, int *r_free_mem) override
void free_dummy_resources()
bool ensure_buffer_bindings(id< MTLRenderCommandEncoder > rec, const MTLShaderInterface *shader_interface, const MTLRenderPipelineStateInstance *pipeline_state_instance)
MTLScratchBufferManager & get_scratchbuffer_manager()
id< MTLCommandQueue > queue
void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len)
MTLContextTextureUtils & get_texture_utils()
static MTLBufferPool * get_global_memory_manager()
static std::atomic< int > max_drawables_in_flight
void remove_all_attachments()
bool add_color_attachment(gpu::MTLTexture *texture, uint slot, int miplevel, int layer)
void bind_fragment_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
void bind_fragment_bytes(const void *bytes, uint64_t length, uint index)
void bind_vertex_sampler(MTLSamplerBinding &sampler_binding, bool use_argument_buffer_for_samplers, uint slot)
void bind_vertex_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void bind_vertex_texture(id< MTLTexture > tex, uint slot)
void bind_vertex_bytes(const void *bytes, uint64_t length, uint index)
id< MTLDepthStencilState > bound_ds_state
MTLScissorRect last_scissor_rect
uint last_used_stencil_ref_value
BufferBindingCached cached_fragment_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
id< MTLRenderPipelineState > bound_pso
BufferBindingCached cached_vertex_buffer_bindings[MTL_MAX_BUFFER_BINDINGS]
MTLBoundShaderState last_bound_shader_state
void bind_fragment_texture(id< MTLTexture > tex, uint slot)
void bind_fragment_buffer(id< MTLBuffer > buffer, uint64_t buffer_offset, uint index)
void increment_reference()
void decrement_reference()
const char * get_name() const
const MTLShaderBufferBlock & get_push_constant_block() const
const MTLShaderTexture & get_texture(uint index) const
void insert_argument_encoder(int buffer_index, id encoder)
const MTLShaderBufferBlock & get_uniform_block(uint index) const
uint32_t get_total_textures() const
const char * get_name_at_offset(uint32_t offset) const
bool uses_argument_buffer_for_samplers() const
int get_argument_buffer_bind_index(ShaderStage stage) const
const MTLShaderBufferBlock & get_storage_block(uint index) const
id< MTLArgumentEncoder > find_argument_encoder(int buffer_index) const
uint32_t get_total_uniform_blocks() const
uint32_t get_total_storage_blocks() const
uint32_t get_max_texture_index() const
const MTLComputePipelineStateCommon & get_compute_common_state()
void * get_push_constant_data()
MTLComputePipelineStateInstance * bake_compute_pipeline_state(MTLContext *ctx, MTLComputePipelineStateDescriptor &compute_pipeline_descriptor)
void uniform_int(int location, int comp_len, int array_size, const int *data) override
VertBuf * get_transform_feedback_active_buffer()
MTLShaderInterface * get_interface()
MTLRenderPipelineStateInstance * bake_current_pipeline_state(MTLContext *ctx, MTLPrimitiveTopologyClass prim_type)
bool get_push_constant_is_dirty()
void push_constant_bindstate_mark_dirty(bool is_dirty)
id< MTLBuffer > get_metal_buffer()
void bind(int slot) override
bool has_custom_swizzle()
const int * get_texture_metdata_ptr() const
MTLStorageBuf * get_storagebuf()
struct blender::gpu::Shader::Constants constants
virtual void apply_state()=0
eGPUTextureUsage usage_get() const
CCL_NAMESPACE_BEGIN struct Options options
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
BLI_INLINE float fb(float length, float L)
static void error(const char *str)
#define MTL_MAX_SAMPLER_SLOTS
#define MTL_MAX_BUFFER_BINDINGS
#define MTL_MAX_TEXTURE_SLOTS
#define MTL_MAX_DRAWABLES
#define MTL_FRAME_AVERAGE_COUNT
#define MTL_LOG_SSBO_ERROR
#define MTL_LOG_UBO_ERROR
#define MTL_LOG_INFO(info,...)
#define MTL_LOG_WARNING(info,...)
#define MTL_LOG_ERROR(info,...)
void present(MTLRenderPassDescriptor *blit_descriptor, id< MTLRenderPipelineState > blit_pso, id< MTLTexture > swapchain_texture, id< CAMetalDrawable > drawable)
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
static MTLPrimitiveTopologyClass mtl_prim_type_to_topology_class(MTLPrimitiveType prim_type)
const MTLSamplerState DEFAULT_SAMPLER_STATE
@ MTL_PIPELINE_STATE_CULLMODE_FLAG
@ MTL_PIPELINE_STATE_SCISSOR_FLAG
@ MTL_PIPELINE_STATE_FRONT_FACING_FLAG
@ MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG
@ MTL_PIPELINE_STATE_VIEWPORT_FLAG
@ MTL_PIPELINE_STATE_ALL_FLAG
static MTLSamplerAddressMode to_mtl_type(GPUSamplerExtendMode wrap_mode)
GPUSamplerCustomType custom_type
GPUSamplerExtendMode extend_yz
static constexpr GPUSamplerState default_sampler()
GPUSamplerFiltering filtering
GPUSamplerExtendMode extend_x
void set(MTLShader *shader, uint pso_index)
id< MTLFunction > compute
id< MTLComputePipelineState > pso
int base_uniform_buffer_index
int base_storage_buffer_index
bool depth_bias_enabled_for_lines
MTLCompareFunction depth_function
MTLStencilOperation stencil_op_back_depthstencil_pass
MTLCompareFunction stencil_func
MTLStencilOperation stencil_op_back_stencil_fail
MTLStencilOperation stencil_op_front_stencil_fail
bool depth_bias_enabled_for_tris
MTLStencilOperation stencil_op_front_depthstencil_pass
MTLStencilOperation stencil_op_front_depth_fail
MTLStencilOperation stencil_op_back_depth_fail
bool depth_bias_enabled_for_points
bool stencil_test_enabled
MTLColorWriteMask color_write_mask
MTLBlendFactor src_rgb_blend_factor
MTLStorageBufferBinding ssbo_bindings[MTL_MAX_BUFFER_BINDINGS]
MTLBlendOperation alpha_blend_op
MTLBlendFactor src_alpha_blend_factor
MTLTextureBinding texture_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLShader * active_shader
MTLPipelineStateDirtyFlag dirty_flags
MTLUniformBufferBinding ubo_bindings[MTL_MAX_BUFFER_BINDINGS]
MTLBlendFactor dest_alpha_blend_factor
int viewport_width[GPU_MAX_VIEWPORTS]
MTLContextDepthStencilState depth_stencil_state
int viewport_height[GPU_MAX_VIEWPORTS]
MTLTextureBinding image_bindings[MTL_MAX_TEXTURE_SLOTS]
MTLSamplerBinding sampler_bindings[MTL_MAX_SAMPLER_SLOTS]
int viewport_offset_x[GPU_MAX_VIEWPORTS]
MTLBlendOperation rgb_blend_op
int viewport_offset_y[GPU_MAX_VIEWPORTS]
MTLBlendFactor dest_rgb_blend_factor
eGPUFaceCullTest cull_mode
bool reflection_data_available
int transform_feedback_buffer_index
int null_attribute_buffer_index
id< MTLRenderPipelineState > pso
int base_uniform_buffer_index
int base_storage_buffer_index
blender::Vector< MTLBufferArgumentData > buffer_bindings_reflection_data_frag
uint32_t shader_pso_index
blender::Vector< MTLBufferArgumentData > buffer_bindings_reflection_data_vert
MTLSamplerState mtl_sampler_flags[MTL_MAX_TEXTURE_SLOTS]
id< MTLSamplerState > mtl_sampler[MTL_MAX_TEXTURE_SLOTS]
int texture_buffer_ssbo_location
int buffer_metadata_uniform_loc
eGPUSamplerFormat sampler_format
gpu::MTLTexture * texture_resource
ccl_device_inline int clamp(int a, int mn, int mx)