Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/metal/mtl_context.mm
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| /** \file | /** \file | ||||
| * \ingroup gpu | * \ingroup gpu | ||||
| */ | */ | ||||
| #include "mtl_context.hh" | #include "mtl_context.hh" | ||||
| #include "mtl_debug.hh" | #include "mtl_debug.hh" | ||||
| #include "mtl_framebuffer.hh" | #include "mtl_framebuffer.hh" | ||||
| #include "mtl_immediate.hh" | #include "mtl_immediate.hh" | ||||
| #include "mtl_memory.hh" | #include "mtl_memory.hh" | ||||
| #include "mtl_primitive.hh" | #include "mtl_primitive.hh" | ||||
| #include "mtl_shader.hh" | #include "mtl_shader.hh" | ||||
| #include "mtl_shader_interface.hh" | #include "mtl_shader_interface.hh" | ||||
| #include "mtl_state.hh" | #include "mtl_state.hh" | ||||
| #include "mtl_uniform_buffer.hh" | #include "mtl_uniform_buffer.hh" | ||||
| #include "mtl_vertex_buffer.hh" | |||||
| #include "DNA_userdef_types.h" | #include "DNA_userdef_types.h" | ||||
| #include "GPU_capabilities.h" | #include "GPU_capabilities.h" | ||||
| #include "GPU_matrix.h" | #include "GPU_matrix.h" | ||||
| #include "GPU_shader.h" | #include "GPU_shader.h" | ||||
| #include "GPU_texture.h" | #include "GPU_texture.h" | ||||
| #include "GPU_uniform_buffer.h" | #include "GPU_uniform_buffer.h" | ||||
| ▲ Show 20 Lines • Show All 483 Lines • ▼ Show 20 Lines | id<MTLBuffer> MTLContext::get_null_attribute_buffer() | ||||
| [null_attribute_buffer_ retain]; | [null_attribute_buffer_ retain]; | ||||
| float data[4] = {0.0f, 0.0f, 0.0f, 1.0f}; | float data[4] = {0.0f, 0.0f, 0.0f, 1.0f}; | ||||
| memcpy([null_attribute_buffer_ contents], data, sizeof(float) * 4); | memcpy([null_attribute_buffer_ contents], data, sizeof(float) * 4); | ||||
| [null_attribute_buffer_ didModifyRange:NSMakeRange(0, null_buffer_size)]; | [null_attribute_buffer_ didModifyRange:NSMakeRange(0, null_buffer_size)]; | ||||
| return null_attribute_buffer_; | return null_attribute_buffer_; | ||||
| } | } | ||||
| gpu::MTLTexture *MTLContext::get_dummy_texture(eGPUTextureType type) | gpu::MTLTexture *MTLContext::get_dummy_texture(eGPUTextureType type, | ||||
| eGPUSamplerFormat sampler_format) | |||||
| { | { | ||||
| /* Decrement 1 from texture type as they start from 1 and go to 32 (inclusive). Remap to 0..31 */ | /* Decrement 1 from texture type as they start from 1 and go to 32 (inclusive). Remap to 0..31 */ | ||||
| gpu::MTLTexture *dummy_tex = dummy_textures_[type - 1]; | gpu::MTLTexture *dummy_tex = dummy_textures_[sampler_format][type - 1]; | ||||
| if (dummy_tex != nullptr) { | if (dummy_tex != nullptr) { | ||||
| return dummy_tex; | return dummy_tex; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Determine format for dummy texture. */ | |||||
| eGPUTextureFormat format = GPU_RGBA8; | |||||
| switch (sampler_format) { | |||||
| case GPU_SAMPLER_TYPE_FLOAT: | |||||
| format = GPU_RGBA8; | |||||
| break; | |||||
| case GPU_SAMPLER_TYPE_INT: | |||||
| format = GPU_RGBA8I; | |||||
| break; | |||||
| case GPU_SAMPLER_TYPE_UINT: | |||||
| format = GPU_RGBA8UI; | |||||
| break; | |||||
| case GPU_SAMPLER_TYPE_DEPTH: | |||||
| format = GPU_DEPTH32F_STENCIL8; | |||||
| break; | |||||
| default: | |||||
| BLI_assert_unreachable(); | |||||
| } | |||||
| /* Create dummy texture based on desired type. */ | |||||
| GPUTexture *tex = nullptr; | GPUTexture *tex = nullptr; | ||||
| switch (type) { | switch (type) { | ||||
| case GPU_TEXTURE_1D: | case GPU_TEXTURE_1D: | ||||
| tex = GPU_texture_create_1d("Dummy 1D", 128, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_1d("Dummy 1D", 128, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_1D_ARRAY: | case GPU_TEXTURE_1D_ARRAY: | ||||
| tex = GPU_texture_create_1d_array("Dummy 1DArray", 128, 1, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_1d_array("Dummy 1DArray", 128, 1, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_2D: | case GPU_TEXTURE_2D: | ||||
| tex = GPU_texture_create_2d("Dummy 2D", 128, 128, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_2d("Dummy 2D", 128, 128, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_2D_ARRAY: | case GPU_TEXTURE_2D_ARRAY: | ||||
| tex = GPU_texture_create_2d_array("Dummy 2DArray", 128, 128, 1, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_2d_array("Dummy 2DArray", 128, 128, 1, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_3D: | case GPU_TEXTURE_3D: | ||||
| tex = GPU_texture_create_3d( | tex = GPU_texture_create_3d("Dummy 3D", 128, 128, 1, 1, format, GPU_DATA_UBYTE, nullptr); | ||||
| "Dummy 3D", 128, 128, 1, 1, GPU_RGBA8, GPU_DATA_UBYTE, nullptr); | |||||
| break; | break; | ||||
| case GPU_TEXTURE_CUBE: | case GPU_TEXTURE_CUBE: | ||||
| tex = GPU_texture_create_cube("Dummy Cube", 128, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_cube("Dummy Cube", 128, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_CUBE_ARRAY: | case GPU_TEXTURE_CUBE_ARRAY: | ||||
| tex = GPU_texture_create_cube_array("Dummy CubeArray", 128, 1, 1, GPU_RGBA8, nullptr); | tex = GPU_texture_create_cube_array("Dummy CubeArray", 128, 1, 1, format, nullptr); | ||||
| break; | break; | ||||
| case GPU_TEXTURE_BUFFER: | case GPU_TEXTURE_BUFFER: | ||||
| if (!dummy_verts_) { | if (!dummy_verts_[sampler_format]) { | ||||
| GPU_vertformat_clear(&dummy_vertformat_); | GPU_vertformat_clear(&dummy_vertformat_[sampler_format]); | ||||
| GPU_vertformat_attr_add(&dummy_vertformat_, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | |||||
| dummy_verts_ = GPU_vertbuf_create_with_format_ex(&dummy_vertformat_, GPU_USAGE_STATIC); | GPUVertCompType comp_type = GPU_COMP_F32; | ||||
| GPU_vertbuf_data_alloc(dummy_verts_, 64); | GPUVertFetchMode fetch_mode = GPU_FETCH_FLOAT; | ||||
| switch (sampler_format) { | |||||
| case GPU_SAMPLER_TYPE_FLOAT: | |||||
| case GPU_SAMPLER_TYPE_DEPTH: | |||||
| comp_type = GPU_COMP_F32; | |||||
| fetch_mode = GPU_FETCH_FLOAT; | |||||
| break; | |||||
| case GPU_SAMPLER_TYPE_INT: | |||||
| comp_type = GPU_COMP_I32; | |||||
| fetch_mode = GPU_FETCH_INT; | |||||
| break; | |||||
| case GPU_SAMPLER_TYPE_UINT: | |||||
| comp_type = GPU_COMP_U32; | |||||
| fetch_mode = GPU_FETCH_INT; | |||||
| break; | |||||
| default: | |||||
| BLI_assert_unreachable(); | |||||
| } | } | ||||
| tex = GPU_texture_create_from_vertbuf("Dummy TextureBuffer", dummy_verts_); | |||||
| GPU_vertformat_attr_add( | |||||
| &dummy_vertformat_[sampler_format], "dummy", comp_type, 4, fetch_mode); | |||||
| dummy_verts_[sampler_format] = GPU_vertbuf_create_with_format_ex( | |||||
| &dummy_vertformat_[sampler_format], | |||||
| GPU_USAGE_STATIC | GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY); | |||||
| GPU_vertbuf_data_alloc(dummy_verts_[sampler_format], 64); | |||||
| } | |||||
| tex = GPU_texture_create_from_vertbuf("Dummy TextureBuffer", dummy_verts_[sampler_format]); | |||||
| break; | break; | ||||
| default: | default: | ||||
| BLI_assert_msg(false, "Unrecognised texture type"); | BLI_assert_msg(false, "Unrecognised texture type"); | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| gpu::MTLTexture *metal_tex = static_cast<gpu::MTLTexture *>(reinterpret_cast<Texture *>(tex)); | gpu::MTLTexture *metal_tex = static_cast<gpu::MTLTexture *>(reinterpret_cast<Texture *>(tex)); | ||||
| dummy_textures_[type - 1] = metal_tex; | dummy_textures_[sampler_format][type - 1] = metal_tex; | ||||
| return metal_tex; | return metal_tex; | ||||
| } | } | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| void MTLContext::free_dummy_resources() | void MTLContext::free_dummy_resources() | ||||
| { | { | ||||
| for (int format = 0; format < GPU_SAMPLER_TYPE_MAX; format++) { | |||||
| for (int tex = 0; tex < GPU_TEXTURE_BUFFER; tex++) { | for (int tex = 0; tex < GPU_TEXTURE_BUFFER; tex++) { | ||||
| if (dummy_textures_[tex]) { | if (dummy_textures_[format][tex]) { | ||||
| GPU_texture_free( | GPU_texture_free( | ||||
| reinterpret_cast<GPUTexture *>(static_cast<Texture *>(dummy_textures_[tex]))); | reinterpret_cast<GPUTexture *>(static_cast<Texture *>(dummy_textures_[format][tex]))); | ||||
| dummy_textures_[tex] = nullptr; | dummy_textures_[format][tex] = nullptr; | ||||
| } | |||||
| } | } | ||||
| if (dummy_verts_[format]) { | |||||
| GPU_vertbuf_discard(dummy_verts_[format]); | |||||
| } | } | ||||
| if (dummy_verts_) { | |||||
| GPU_vertbuf_discard(dummy_verts_); | |||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Global Context State | /** \name Global Context State | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | if (pipeline_state_instance->pso) { | ||||
| /* Texture Bindings. */ | /* Texture Bindings. */ | ||||
| /* We will iterate through all texture bindings on the context and determine if any of the | /* We will iterate through all texture bindings on the context and determine if any of the | ||||
| * active slots match those in our shader interface. If so, textures will be bound. */ | * active slots match those in our shader interface. If so, textures will be bound. */ | ||||
| if (shader_interface->get_total_textures() > 0) { | if (shader_interface->get_total_textures() > 0) { | ||||
| this->ensure_texture_bindings(rec, shader_interface, pipeline_state_instance); | this->ensure_texture_bindings(rec, shader_interface, pipeline_state_instance); | ||||
| } | } | ||||
| /* Transform feedback buffer binding. */ | /* Transform feedback buffer binding. */ | ||||
| /* TOOD(Metal): Include this code once MTLVertBuf is merged. We bind the vertex buffer to which | GPUVertBuf *tf_vbo = | ||||
| * transform feedback data will be written. */ | this->pipeline_state.active_shader->get_transform_feedback_active_buffer(); | ||||
| // GPUVertBuf *tf_vbo = | if (tf_vbo != nullptr && pipeline_state_instance->transform_feedback_buffer_index >= 0) { | ||||
| // this->pipeline_state.active_shader->get_transform_feedback_active_buffer(); | |||||
| // if (tf_vbo != nullptr && pipeline_state_instance->transform_feedback_buffer_index >= 0) { | /* Ensure primitive type is either GPU_LINES, GPU_TRIANGLES or GPU_POINT */ | ||||
| BLI_assert(mtl_prim_type == MTLPrimitiveTypeLine || | |||||
| // /* Ensure primitive type is either GPU_LINES, GPU_TRIANGLES or GPU_POINT */ | mtl_prim_type == MTLPrimitiveTypeTriangle || | ||||
| // BLI_assert(mtl_prim_type == MTLPrimitiveTypeLine || | mtl_prim_type == MTLPrimitiveTypePoint); | ||||
| // mtl_prim_type == MTLPrimitiveTypeTriangle || | |||||
| // mtl_prim_type == MTLPrimitiveTypePoint); | /* Fetch active transform feedback buffer from vertbuf */ | ||||
| MTLVertBuf *tf_vbo_mtl = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(tf_vbo)); | |||||
| // /* Fetch active transform feedback buffer from vertbuf */ | /* Ensure TF buffer is ready. */ | ||||
| // MTLVertBuf *tf_vbo_mtl = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(tf_vbo)); | tf_vbo_mtl->bind(); | ||||
| // int tf_buffer_offset = 0; | id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer(); | ||||
| // id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer(&tf_buffer_offset); | BLI_assert(tf_buffer_mtl != nil); | ||||
| // if (tf_buffer_mtl != nil && tf_buffer_offset >= 0) { | if (tf_buffer_mtl != nil) { | ||||
| // [rec setVertexBuffer:tf_buffer_mtl | [rec setVertexBuffer:tf_buffer_mtl | ||||
| // offset:tf_buffer_offset | offset:0 | ||||
| // atIndex:pipeline_state_instance->transform_feedback_buffer_index]; | atIndex:pipeline_state_instance->transform_feedback_buffer_index]; | ||||
| // printf("Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)\n", | MTL_LOG_INFO("Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)\n", | ||||
| // tf_vbo_mtl, | tf_vbo_mtl, | ||||
| // tf_buffer_mtl); | tf_buffer_mtl); | ||||
| // } | } | ||||
| // } | } | ||||
| /* Matrix Bindings. */ | /* Matrix Bindings. */ | ||||
| /* This is now called upon shader bind. We may need to re-evaluate this though, | /* This is now called upon shader bind. We may need to re-evaluate this though, | ||||
| * as was done here to ensure uniform changes between draws were tracked. | * as was done here to ensure uniform changes between draws were tracked. | ||||
| * NOTE(Metal): We may be able to remove this. */ | * NOTE(Metal): We may be able to remove this. */ | ||||
| GPU_matrix_bind(reinterpret_cast<struct GPUShader *>( | GPU_matrix_bind(reinterpret_cast<struct GPUShader *>( | ||||
| static_cast<Shader *>(this->pipeline_state.active_shader))); | static_cast<Shader *>(this->pipeline_state.active_shader))); | ||||
| ▲ Show 20 Lines • Show All 371 Lines • ▼ Show 20 Lines | for (const uint t : IndexRange(shader_interface->get_max_texture_index() + 1)) { | ||||
| } | } | ||||
| /* Bind Dummy texture -- will temporarily resolve validation issues while incorrect formats | /* Bind Dummy texture -- will temporarily resolve validation issues while incorrect formats | ||||
| * are provided -- as certain configurations may not need any binding. These issues should | * are provided -- as certain configurations may not need any binding. These issues should | ||||
| * be fixed in the high-level, if problems crop up. */ | * be fixed in the high-level, if problems crop up. */ | ||||
| if (bind_dummy_texture) { | if (bind_dummy_texture) { | ||||
| if (bool(shader_texture_info.stage_mask & ShaderStage::VERTEX)) { | if (bool(shader_texture_info.stage_mask & ShaderStage::VERTEX)) { | ||||
| rps.bind_vertex_texture( | rps.bind_vertex_texture( | ||||
| get_dummy_texture(shader_texture_info.type)->get_metal_handle(), slot); | get_dummy_texture(shader_texture_info.type, shader_texture_info.sampler_format) | ||||
| ->get_metal_handle(), | |||||
| slot); | |||||
| /* Bind default sampler state. */ | /* Bind default sampler state. */ | ||||
| MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE}; | MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE}; | ||||
| rps.bind_vertex_sampler(default_binding, use_argument_buffer_for_samplers, slot); | rps.bind_vertex_sampler(default_binding, use_argument_buffer_for_samplers, slot); | ||||
| } | } | ||||
| if (bool(shader_texture_info.stage_mask & ShaderStage::FRAGMENT)) { | if (bool(shader_texture_info.stage_mask & ShaderStage::FRAGMENT)) { | ||||
| rps.bind_fragment_texture( | rps.bind_fragment_texture( | ||||
| get_dummy_texture(shader_texture_info.type)->get_metal_handle(), slot); | get_dummy_texture(shader_texture_info.type, shader_texture_info.sampler_format) | ||||
| ->get_metal_handle(), | |||||
| slot); | |||||
| /* Bind default sampler state. */ | /* Bind default sampler state. */ | ||||
| MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE}; | MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE}; | ||||
| rps.bind_fragment_sampler(default_binding, use_argument_buffer_for_samplers, slot); | rps.bind_fragment_sampler(default_binding, use_argument_buffer_for_samplers, slot); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 548 Lines • Show Last 20 Lines | |||||