Metal: Remove SSBO Vertex Fetch
This API was used as a workaround to the lack of geometry shader. It has been rendered redundant since the introduction of #125782.
This commit is contained in:
@@ -309,14 +309,6 @@ GPUShader *GPU_shader_create_ex(std::optional<blender::StringRefNull> vertcode,
|
||||
bool GPU_shader_transform_feedback_enable(GPUShader *shader, blender::gpu::VertBuf *vertbuf);
|
||||
void GPU_shader_transform_feedback_disable(GPUShader *shader);
|
||||
|
||||
/**
|
||||
* SSBO Vertex-fetch is used as an alternative path to geometry shaders wherein the vertex count is
|
||||
* expanded up-front. This function fetches the number of specified output vertices per input
|
||||
* primitive.
|
||||
*/
|
||||
int GPU_shader_get_ssbo_vertex_fetch_num_verts_per_prim(GPUShader *shader);
|
||||
bool GPU_shader_uses_ssbo_vertex_fetch(GPUShader *shader);
|
||||
|
||||
/**
|
||||
* Shader cache warming.
|
||||
* For each shader, rendering APIs perform a two-step compilation:
|
||||
|
||||
@@ -699,15 +699,6 @@ int GPU_shader_get_program(GPUShader *shader)
|
||||
return unwrap(shader)->program_handle_get();
|
||||
}
|
||||
|
||||
int GPU_shader_get_ssbo_vertex_fetch_num_verts_per_prim(GPUShader *shader)
|
||||
{
|
||||
return unwrap(shader)->get_ssbo_vertex_fetch_output_num_verts();
|
||||
}
|
||||
|
||||
bool GPU_shader_uses_ssbo_vertex_fetch(GPUShader *shader)
|
||||
{
|
||||
return unwrap(shader)->get_uses_ssbo_vertex_fetch();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
@@ -122,10 +122,6 @@ class Shader {
|
||||
/* DEPRECATED: Kept only because of BGL API. */
|
||||
virtual int program_handle_get() const = 0;
|
||||
|
||||
/* Only used by SSBO Vertex fetch. */
|
||||
virtual bool get_uses_ssbo_vertex_fetch() const = 0;
|
||||
virtual int get_ssbo_vertex_fetch_output_num_verts() const = 0;
|
||||
|
||||
inline StringRefNull name_get() const
|
||||
{
|
||||
return name;
|
||||
|
||||
@@ -93,7 +93,7 @@ class MTLBatch : public Batch {
|
||||
|
||||
/* Returns an initialized RenderComandEncoder for drawing if all is good.
|
||||
* Otherwise, nil. */
|
||||
id<MTLRenderCommandEncoder> bind(uint v_count);
|
||||
id<MTLRenderCommandEncoder> bind();
|
||||
void unbind(id<MTLRenderCommandEncoder> rec);
|
||||
|
||||
/* Convenience getters. */
|
||||
|
||||
@@ -128,12 +128,6 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
||||
int buffer_index = -1;
|
||||
int attribute_offset = 0;
|
||||
|
||||
if (!active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
BLI_assert(
|
||||
buffer_stride >= 4 &&
|
||||
"In Metal, Vertex buffer stride should be 4. SSBO Vertex fetch is not affected by this");
|
||||
}
|
||||
|
||||
/* Iterate over VertBuf vertex format and find attributes matching those in the active
|
||||
* shader's interface. */
|
||||
for (uint32_t a_idx = 0; a_idx < format->attr_len; a_idx++) {
|
||||
@@ -211,23 +205,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
||||
"only mat4 attributes currently supported -- Not ready to handle other long "
|
||||
"component length attributes yet");
|
||||
|
||||
/* SSBO Vertex Fetch Attribute safety checks. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
/* When using SSBO vertex fetch, we do not need to expose split attributes,
|
||||
* A matrix can be read directly as a whole block of contiguous data. */
|
||||
MTLSSBOAttribute ssbo_attr(mtl_attr.index,
|
||||
buffer_index,
|
||||
attribute_offset,
|
||||
buffer_stride,
|
||||
GPU_SHADER_ATTR_TYPE_MAT4,
|
||||
instanced);
|
||||
active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr);
|
||||
desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
|
||||
ssbo_attr;
|
||||
desc.vertex_descriptor.num_ssbo_attributes++;
|
||||
}
|
||||
else {
|
||||
|
||||
{
|
||||
/* Handle Mat4 attributes. */
|
||||
if (a->comp_len == 16) {
|
||||
/* Debug safety checks. */
|
||||
@@ -341,26 +319,6 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
||||
(mtl_attr.location) :
|
||||
desc.vertex_descriptor.max_attribute_value;
|
||||
desc.vertex_descriptor.total_attributes++;
|
||||
/* SSBO Vertex Fetch attribute bind. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
BLI_assert_msg(desc.vertex_descriptor.attributes[mtl_attr.location].format ==
|
||||
mtl_attr.format,
|
||||
"SSBO Vertex Fetch does not support attribute conversion.");
|
||||
|
||||
MTLSSBOAttribute ssbo_attr(
|
||||
mtl_attr.index,
|
||||
buffer_index,
|
||||
attribute_offset,
|
||||
buffer_stride,
|
||||
MTLShader::ssbo_vertex_type_to_attr_type(
|
||||
desc.vertex_descriptor.attributes[mtl_attr.location].format),
|
||||
instanced);
|
||||
|
||||
active_shader_->ssbo_vertex_fetch_bind_attribute(ssbo_attr);
|
||||
desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
|
||||
ssbo_attr;
|
||||
desc.vertex_descriptor.num_ssbo_attributes++;
|
||||
}
|
||||
|
||||
/* NOTE: We are setting max_attribute_value to be up to the maximum found index, because
|
||||
* of this, it is possible that we may skip over certain attributes if they were not in
|
||||
@@ -393,7 +351,7 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_count)
|
||||
id<MTLRenderCommandEncoder> MTLBatch::bind()
|
||||
{
|
||||
/* Setup draw call and render pipeline state here. Called by every draw, but setup here so that
|
||||
* MTLDrawList only needs to perform setup a single time. */
|
||||
@@ -417,12 +375,6 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_count)
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* Check if using SSBO Fetch Mode.
|
||||
* This is an alternative drawing mode to geometry shaders, wherein vertex buffers
|
||||
* are bound as readable (random-access) GPU buffers and certain descriptor properties
|
||||
* are passed using Shader uniforms. */
|
||||
bool uses_ssbo_fetch = active_shader_->get_uses_ssbo_vertex_fetch();
|
||||
|
||||
/* Prepare Vertex Descriptor and extract VertexBuffers to bind. */
|
||||
MTLVertBuf *buffers[GPU_BATCH_VBO_MAX_LEN] = {nullptr};
|
||||
int num_buffers = 0;
|
||||
@@ -481,70 +433,6 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_count)
|
||||
|
||||
/*** Bind Vertex Buffers and Index Buffers **/
|
||||
|
||||
/* SSBO Vertex Fetch Buffer bindings. */
|
||||
if (uses_ssbo_fetch) {
|
||||
|
||||
/* SSBO Vertex Fetch - Bind Index Buffer to appropriate slot -- if used. */
|
||||
id<MTLBuffer> idx_buffer = nil;
|
||||
GPUPrimType final_prim_type = this->prim_type;
|
||||
|
||||
if (mtl_elem != nullptr) {
|
||||
|
||||
/* Fetch index buffer. This function can situationally return an optimized
|
||||
* index buffer of a different primitive type. If this is the case, `final_prim_type`
|
||||
* and `v_count` will be updated with the new format.
|
||||
* NOTE: For indexed rendering, v_count represents the number of indices. */
|
||||
idx_buffer = mtl_elem->get_index_buffer(final_prim_type, v_count);
|
||||
BLI_assert(idx_buffer != nil);
|
||||
|
||||
/* Update uniforms for SSBO-vertex-fetch-mode indexed rendering to flag usage. */
|
||||
int &uniform_ssbo_index_mode_u16 = active_shader_->uni_ssbo_uses_index_mode_u16;
|
||||
BLI_assert(uniform_ssbo_index_mode_u16 != -1);
|
||||
int uses_index_mode_u16 = (mtl_elem->index_type_ == GPU_INDEX_U16) ? 1 : 0;
|
||||
active_shader_->uniform_int(uniform_ssbo_index_mode_u16, 1, 1, &uses_index_mode_u16);
|
||||
|
||||
BLI_assert(active_shader_->uni_ssbo_index_base_loc != -1);
|
||||
int index_base = (int)mtl_elem->index_base_;
|
||||
active_shader_->uniform_int(active_shader_->uni_ssbo_index_base_loc, 1, 1, &index_base);
|
||||
}
|
||||
else {
|
||||
idx_buffer = ctx->get_null_buffer();
|
||||
}
|
||||
rps.bind_vertex_buffer(idx_buffer, 0, MTL_SSBO_VERTEX_FETCH_IBO_INDEX);
|
||||
|
||||
/* Ensure all attributes are set. */
|
||||
active_shader_->ssbo_vertex_fetch_bind_attributes_end(rec);
|
||||
|
||||
/* Bind nullptr Buffers for unused vertex data slots. */
|
||||
id<MTLBuffer> null_buffer = ctx->get_null_buffer();
|
||||
BLI_assert(null_buffer != nil);
|
||||
for (int i = num_buffers; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
if (rps.cached_vertex_buffer_bindings[i].metal_buffer == nil) {
|
||||
rps.bind_vertex_buffer(null_buffer, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Flag whether Indexed rendering is used or not. */
|
||||
int &uniform_ssbo_use_indexed = active_shader_->uni_ssbo_uses_indexed_rendering;
|
||||
BLI_assert(uniform_ssbo_use_indexed != -1);
|
||||
int uses_indexed_rendering = (mtl_elem != nullptr) ? 1 : 0;
|
||||
active_shader_->uniform_int(uniform_ssbo_use_indexed, 1, 1, &uses_indexed_rendering);
|
||||
|
||||
/* Set SSBO-fetch-mode status uniforms. */
|
||||
BLI_assert(active_shader_->uni_ssbo_input_prim_type_loc != -1);
|
||||
BLI_assert(active_shader_->uni_ssbo_input_vert_count_loc != -1);
|
||||
GPU_shader_uniform_int_ex(reinterpret_cast<GPUShader *>(wrap(active_shader_)),
|
||||
active_shader_->uni_ssbo_input_prim_type_loc,
|
||||
1,
|
||||
1,
|
||||
(const int *)(&final_prim_type));
|
||||
GPU_shader_uniform_int_ex(reinterpret_cast<GPUShader *>(wrap(active_shader_)),
|
||||
active_shader_->uni_ssbo_input_vert_count_loc,
|
||||
1,
|
||||
1,
|
||||
(const int *)(&v_count));
|
||||
}
|
||||
|
||||
/* Ensure Context Render Pipeline State is fully setup and ready to execute the draw.
|
||||
* This should happen after all other final rendering setup is complete. */
|
||||
MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type);
|
||||
@@ -606,11 +494,6 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings(MTLVertBuf **buffers, int
|
||||
Span<MTLVertBuf *> mtl_inst(reinterpret_cast<MTLVertBuf **>(this->inst),
|
||||
GPU_BATCH_INST_VBO_MAX_LEN);
|
||||
|
||||
/* SSBO Vertex fetch also passes vertex descriptor information into the shader. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
active_shader_->ssbo_vertex_fetch_bind_attributes_begin();
|
||||
}
|
||||
|
||||
/* Resolve Metal vertex buffer bindings. */
|
||||
/* Vertex Descriptors
|
||||
* ------------------
|
||||
@@ -641,15 +524,6 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings(MTLVertBuf **buffers, int
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use cached ssbo attribute binding data. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
BLI_assert(desc.vertex_descriptor.uses_ssbo_vertex_fetch);
|
||||
for (int attr_id = 0; attr_id < desc.vertex_descriptor.num_ssbo_attributes; attr_id++) {
|
||||
active_shader_->ssbo_vertex_fetch_bind_attribute(
|
||||
desc.vertex_descriptor.ssbo_attributes[attr_id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
VertexDescriptorShaderInterfacePair pair{};
|
||||
@@ -699,7 +573,6 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings(MTLVertBuf **buffers, int
|
||||
}
|
||||
|
||||
/* Add to VertexDescriptor cache */
|
||||
desc.vertex_descriptor.uses_ssbo_vertex_fetch = active_shader_->get_uses_ssbo_vertex_fetch();
|
||||
pair.attr_mask = attr_mask;
|
||||
pair.vertex_descriptor = desc.vertex_descriptor;
|
||||
pair.num_buffers = num_buffers;
|
||||
@@ -741,7 +614,7 @@ void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count)
|
||||
|
||||
/* Setup RenderPipelineState for batch. */
|
||||
MTLContext *ctx = MTLContext::get();
|
||||
id<MTLRenderCommandEncoder> rec = this->bind(v_count);
|
||||
id<MTLRenderCommandEncoder> rec = this->bind();
|
||||
if (rec == nil) {
|
||||
/* End of draw. */
|
||||
this->unbind(rec);
|
||||
@@ -752,35 +625,10 @@ void MTLBatch::draw_advanced(int v_first, int v_count, int i_first, int i_count)
|
||||
MTLIndexBuf *mtl_elem = static_cast<MTLIndexBuf *>(reinterpret_cast<IndexBuf *>(this->elem));
|
||||
MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type);
|
||||
|
||||
/* Render using SSBO Vertex Fetch. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch()) {
|
||||
|
||||
/* Submit draw call with modified vertex count, which reflects vertices per primitive defined
|
||||
* in the USE_SSBO_VERTEX_FETCH pragma. */
|
||||
int num_input_primitives = gpu_get_prim_count_from_type(v_count, this->prim_type);
|
||||
int output_num_verts = num_input_primitives *
|
||||
active_shader_->get_ssbo_vertex_fetch_output_num_verts();
|
||||
BLI_assert_msg(
|
||||
mtl_vertex_count_fits_primitive_type(
|
||||
output_num_verts, active_shader_->get_ssbo_vertex_fetch_output_prim_type()),
|
||||
"Output Vertex count is not compatible with the requested output vertex primitive type");
|
||||
|
||||
/* Set depth stencil state (requires knowledge of primitive type). */
|
||||
ctx->ensure_depth_stencil_state(active_shader_->get_ssbo_vertex_fetch_output_prim_type());
|
||||
|
||||
[rec drawPrimitives:active_shader_->get_ssbo_vertex_fetch_output_prim_type()
|
||||
vertexStart:0
|
||||
vertexCount:output_num_verts
|
||||
instanceCount:i_count
|
||||
baseInstance:i_first];
|
||||
ctx->main_command_buffer.register_draw_counters(output_num_verts * i_count);
|
||||
}
|
||||
/* Perform regular draw. */
|
||||
else if (mtl_elem == nullptr) {
|
||||
|
||||
if (mtl_elem == nullptr) {
|
||||
/* Primitive Type toplogy emulation. */
|
||||
if (mtl_needs_topology_emulation(this->prim_type)) {
|
||||
|
||||
/* Generate index buffer for primitive types requiring emulation. */
|
||||
GPUPrimType emulated_prim_type = this->prim_type;
|
||||
uint32_t emulated_v_count = v_count;
|
||||
@@ -883,7 +731,7 @@ void MTLBatch::draw_advanced_indirect(GPUStorageBuf *indirect_buf, intptr_t offs
|
||||
{
|
||||
/* Setup RenderPipelineState for batch. */
|
||||
MTLContext *ctx = MTLContext::get();
|
||||
id<MTLRenderCommandEncoder> rec = this->bind(0);
|
||||
id<MTLRenderCommandEncoder> rec = this->bind();
|
||||
if (rec == nil) {
|
||||
printf("Failed to open Render Command encoder for DRAW INDIRECT\n");
|
||||
|
||||
@@ -904,24 +752,6 @@ void MTLBatch::draw_advanced_indirect(GPUStorageBuf *indirect_buf, intptr_t offs
|
||||
return;
|
||||
}
|
||||
|
||||
/* Indirect SSBO vertex fetch calls require the draw command in the buffer to be mutated at
|
||||
* command encoding time. This takes place within the draw manager when a shader supporting
|
||||
* SSBO Vertex-Fetch is used. */
|
||||
if (active_shader_->get_uses_ssbo_vertex_fetch())
|
||||
{ /* Set depth stencil state (requires knowledge of primitive type). */
|
||||
ctx->ensure_depth_stencil_state(active_shader_->get_ssbo_vertex_fetch_output_prim_type());
|
||||
|
||||
/* Issue draw call. */
|
||||
[rec drawPrimitives:active_shader_->get_ssbo_vertex_fetch_output_prim_type()
|
||||
indirectBuffer:mtl_indirect_buf
|
||||
indirectBufferOffset:offset];
|
||||
ctx->main_command_buffer.register_draw_counters(1);
|
||||
|
||||
/* End of draw. */
|
||||
this->unbind(rec);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unsupported primitive type check. */
|
||||
BLI_assert_msg(this->prim_type != GPU_PRIM_TRI_FAN,
|
||||
"TriangleFan is not supported in Metal for Indirect draws.");
|
||||
|
||||
@@ -84,10 +84,8 @@ void MTLDrawList::init()
|
||||
void MTLDrawList::append(Batch *gpu_batch, int i_first, int i_count)
|
||||
{
|
||||
/* Fallback when MultiDrawIndirect is not supported/enabled. */
|
||||
MTLShader *shader = static_cast<MTLShader *>(unwrap(gpu_batch->shader));
|
||||
bool requires_ssbo = (shader->get_uses_ssbo_vertex_fetch());
|
||||
bool requires_emulation = mtl_needs_topology_emulation(gpu_batch->prim_type);
|
||||
if (MDI_DISABLED || requires_ssbo || requires_emulation) {
|
||||
if (MDI_DISABLED || requires_emulation) {
|
||||
GPU_batch_draw_advanced(gpu_batch, 0, 0, i_first, i_count);
|
||||
return;
|
||||
}
|
||||
@@ -170,13 +168,6 @@ void MTLDrawList::submit()
|
||||
BLI_assert(ctx);
|
||||
|
||||
/* Execute indirect draw calls. */
|
||||
MTLShader *shader = static_cast<MTLShader *>(unwrap(batch_->shader));
|
||||
bool SSBO_MODE = (shader->get_uses_ssbo_vertex_fetch());
|
||||
if (SSBO_MODE) {
|
||||
can_use_MDI = false;
|
||||
BLI_assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Heuristic to determine whether using indirect drawing is more efficient. */
|
||||
size_t command_size = MDI_INDEXED ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) :
|
||||
@@ -186,7 +177,7 @@ void MTLDrawList::submit()
|
||||
|
||||
/* Bind Batch to setup render pipeline state. */
|
||||
BLI_assert(batch_ != nullptr);
|
||||
id<MTLRenderCommandEncoder> rec = batch_->bind(0);
|
||||
id<MTLRenderCommandEncoder> rec = batch_->bind();
|
||||
if (rec == nil) {
|
||||
BLI_assert_msg(false, "A RenderCommandEncoder should always be available!\n");
|
||||
|
||||
|
||||
@@ -115,21 +115,6 @@ void MTLImmediate::end()
|
||||
for (int i = 0; i < desc.vertex_descriptor.total_attributes; i++) {
|
||||
desc.vertex_descriptor.attributes[i].format = MTLVertexFormatInvalid;
|
||||
}
|
||||
desc.vertex_descriptor.uses_ssbo_vertex_fetch =
|
||||
active_mtl_shader->get_uses_ssbo_vertex_fetch();
|
||||
desc.vertex_descriptor.num_ssbo_attributes = 0;
|
||||
|
||||
/* SSBO Vertex Fetch -- Verify Attributes. */
|
||||
if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
|
||||
active_mtl_shader->ssbo_vertex_fetch_bind_attributes_begin();
|
||||
|
||||
/* Disable Indexed rendering in SSBO vertex fetch. */
|
||||
int uniform_ssbo_use_indexed = active_mtl_shader->uni_ssbo_uses_indexed_rendering;
|
||||
BLI_assert_msg(uniform_ssbo_use_indexed != -1,
|
||||
"Expected valid uniform location for ssbo_uses_indexed_rendering.");
|
||||
int uses_indexed_rendering = 0;
|
||||
active_mtl_shader->uniform_int(uniform_ssbo_use_indexed, 1, 1, &uses_indexed_rendering);
|
||||
}
|
||||
|
||||
/* Populate Vertex descriptor and verify attributes.
|
||||
* TODO(Metal): Cache this vertex state based on Vertex format and shaders. */
|
||||
@@ -211,23 +196,6 @@ void MTLImmediate::end()
|
||||
/* Using attribute offset in vertex format, as this will be correct */
|
||||
desc.vertex_descriptor.attributes[i].offset = attr->offset;
|
||||
desc.vertex_descriptor.attributes[i].buffer_index = mtl_shader_attribute.buffer_index;
|
||||
|
||||
/* SSBO Vertex Fetch Attribute bind. */
|
||||
if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
|
||||
BLI_assert_msg(mtl_shader_attribute.buffer_index == 0,
|
||||
"All attributes should be in buffer index zero");
|
||||
MTLSSBOAttribute ssbo_attr(
|
||||
mtl_shader_attribute.index,
|
||||
mtl_shader_attribute.buffer_index,
|
||||
attr->offset,
|
||||
this->vertex_format.stride,
|
||||
MTLShader::ssbo_vertex_type_to_attr_type(desc.vertex_descriptor.attributes[i].format),
|
||||
false);
|
||||
desc.vertex_descriptor.ssbo_attributes[desc.vertex_descriptor.num_ssbo_attributes] =
|
||||
ssbo_attr;
|
||||
desc.vertex_descriptor.num_ssbo_attributes++;
|
||||
active_mtl_shader->ssbo_vertex_fetch_bind_attribute(ssbo_attr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Buffer bindings for singular vertex buffer. */
|
||||
@@ -247,27 +215,6 @@ void MTLImmediate::end()
|
||||
this->prim_type = GPU_PRIM_LINE_STRIP;
|
||||
}
|
||||
|
||||
/* SSBO Vertex Fetch -- Verify Attributes. */
|
||||
if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
|
||||
active_mtl_shader->ssbo_vertex_fetch_bind_attributes_end(rec);
|
||||
|
||||
/* Set Status uniforms. */
|
||||
BLI_assert_msg(active_mtl_shader->uni_ssbo_input_prim_type_loc != -1,
|
||||
"ssbo_input_prim_type uniform location invalid!");
|
||||
BLI_assert_msg(active_mtl_shader->uni_ssbo_input_vert_count_loc != -1,
|
||||
"ssbo_input_vert_count uniform location invalid!");
|
||||
GPU_shader_uniform_int_ex(reinterpret_cast<GPUShader *>(wrap(active_mtl_shader)),
|
||||
active_mtl_shader->uni_ssbo_input_prim_type_loc,
|
||||
1,
|
||||
1,
|
||||
(const int *)(&this->prim_type));
|
||||
GPU_shader_uniform_int_ex(reinterpret_cast<GPUShader *>(wrap(active_mtl_shader)),
|
||||
active_mtl_shader->uni_ssbo_input_vert_count_loc,
|
||||
1,
|
||||
1,
|
||||
(const int *)(&this->vertex_idx));
|
||||
}
|
||||
|
||||
if (unwrap(this->shader)->is_polyline) {
|
||||
context_->get_scratchbuffer_manager().bind_as_ssbo(GPU_SSBO_POLYLINE_POS_BUF_SLOT);
|
||||
context_->get_scratchbuffer_manager().bind_as_ssbo(GPU_SSBO_POLYLINE_COL_BUF_SLOT);
|
||||
@@ -295,13 +242,6 @@ void MTLImmediate::end()
|
||||
/* Emulate Tri-fan. */
|
||||
switch (this->prim_type) {
|
||||
case GPU_PRIM_TRI_FAN: {
|
||||
/* Debug safety check for SSBO FETCH MODE. */
|
||||
if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
|
||||
BLI_assert(
|
||||
false &&
|
||||
"Topology emulation for TriangleFan not supported with SSBO Vertex Fetch mode");
|
||||
}
|
||||
|
||||
/* Prepare Triangle-Fan emulation index buffer on CPU based on number of input
|
||||
* vertices. */
|
||||
uint32_t base_vert_count = this->vertex_idx;
|
||||
@@ -374,44 +314,6 @@ void MTLImmediate::end()
|
||||
if (unwrap(this->shader)->is_polyline) {
|
||||
this->polyline_draw_workaround(current_allocation_.buffer_offset);
|
||||
}
|
||||
else if (active_mtl_shader->get_uses_ssbo_vertex_fetch()) {
|
||||
|
||||
/* Bind Null Buffers for empty/missing bind slots. */
|
||||
id<MTLBuffer> null_buffer = context_->get_null_buffer();
|
||||
BLI_assert(null_buffer != nil);
|
||||
for (int i = 1; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
|
||||
/* We only need to ensure a buffer is bound to the context, its contents do not matter
|
||||
* as it will not be used. */
|
||||
if (rps.cached_vertex_buffer_bindings[i].metal_buffer == nil) {
|
||||
rps.bind_vertex_buffer(null_buffer, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* SSBO vertex fetch - Nullify elements buffer. */
|
||||
if (rps.cached_vertex_buffer_bindings[MTL_SSBO_VERTEX_FETCH_IBO_INDEX].metal_buffer ==
|
||||
nil)
|
||||
{
|
||||
rps.bind_vertex_buffer(null_buffer, 0, MTL_SSBO_VERTEX_FETCH_IBO_INDEX);
|
||||
}
|
||||
|
||||
/* Submit draw call with modified vertex count, which reflects vertices per primitive
|
||||
* defined in the USE_SSBO_VERTEX_FETCH `pragma`. */
|
||||
int num_input_primitives = gpu_get_prim_count_from_type(vertex_count, this->prim_type);
|
||||
int output_num_verts = num_input_primitives *
|
||||
active_mtl_shader->get_ssbo_vertex_fetch_output_num_verts();
|
||||
#ifndef NDEBUG
|
||||
BLI_assert(
|
||||
mtl_vertex_count_fits_primitive_type(
|
||||
output_num_verts, active_mtl_shader->get_ssbo_vertex_fetch_output_prim_type()) &&
|
||||
"Output Vertex count is not compatible with the requested output vertex primitive "
|
||||
"type");
|
||||
#endif
|
||||
[rec drawPrimitives:active_mtl_shader->get_ssbo_vertex_fetch_output_prim_type()
|
||||
vertexStart:0
|
||||
vertexCount:output_num_verts];
|
||||
context_->main_command_buffer.register_draw_counters(output_num_verts);
|
||||
}
|
||||
else {
|
||||
/* Regular draw. */
|
||||
[rec drawPrimitives:primitive_type vertexStart:0 vertexCount:vertex_count];
|
||||
|
||||
@@ -60,7 +60,7 @@ static inline MTLPrimitiveType gpu_prim_type_to_metal(GPUPrimType prim_type)
|
||||
/* Certain primitive types are not supported in Metal, and require emulation.
|
||||
* `GPU_PRIM_LINE_LOOP` and `GPU_PRIM_TRI_FAN` required index buffer patching.
|
||||
* Adjacency types do not need emulation as the input structure is the same,
|
||||
* and access is controlled from the vertex shader through SSBO vertex fetch.
|
||||
* and access is controlled from the vertex shader through SSBO vertex pulling.
|
||||
* -- These Adj cases are only used in geometry shaders in OpenGL. */
|
||||
static inline bool mtl_needs_topology_emulation(GPUPrimType prim_type)
|
||||
{
|
||||
|
||||
@@ -128,13 +128,6 @@ struct MTLVertexDescriptor {
|
||||
int num_vert_buffers;
|
||||
MTLPrimitiveTopologyClass prim_topology_class;
|
||||
|
||||
/* WORKAROUND: SSBO Vertex-fetch attributes -- These follow the same structure
|
||||
* but have slightly different binding rules, passed in via uniform
|
||||
* push constant data block. */
|
||||
bool uses_ssbo_vertex_fetch;
|
||||
MTLSSBOAttribute ssbo_attributes[GPU_VERT_ATTR_MAX_LEN];
|
||||
int num_ssbo_attributes;
|
||||
|
||||
bool operator==(const MTLVertexDescriptor &other) const
|
||||
{
|
||||
if ((this->max_attribute_value != other.max_attribute_value) ||
|
||||
@@ -175,8 +168,6 @@ struct MTLVertexDescriptor {
|
||||
for (const int b : IndexRange(this->num_vert_buffers)) {
|
||||
hash ^= this->buffer_layouts[b].hash() << (b + 10);
|
||||
}
|
||||
|
||||
/* NOTE: SSBO vertex fetch members not hashed as these will match attribute bindings. */
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
@@ -341,8 +332,6 @@ struct MTLRenderPipelineStateDescriptor {
|
||||
for (int i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
|
||||
vertex_descriptor.attributes[i].reset();
|
||||
}
|
||||
vertex_descriptor.uses_ssbo_vertex_fetch = false;
|
||||
vertex_descriptor.num_ssbo_attributes = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -169,14 +169,6 @@ class MTLShader : public Shader {
|
||||
friend shader::ShaderCreateInfo;
|
||||
friend shader::StageInterfaceInfo;
|
||||
|
||||
public:
|
||||
/* Cached SSBO vertex fetch attribute uniform locations. */
|
||||
int uni_ssbo_input_prim_type_loc = -1;
|
||||
int uni_ssbo_input_vert_count_loc = -1;
|
||||
int uni_ssbo_uses_indexed_rendering = -1;
|
||||
int uni_ssbo_uses_index_mode_u16 = -1;
|
||||
int uni_ssbo_index_base_loc = -1;
|
||||
|
||||
private:
|
||||
/* Context Handle. */
|
||||
MTLContext *context_ = nullptr;
|
||||
@@ -224,37 +216,6 @@ class MTLShader : public Shader {
|
||||
/* True to enable multi-viewport rendering support. */
|
||||
bool uses_gpu_viewport_index = false;
|
||||
|
||||
/** SSBO Vertex fetch pragma options. */
|
||||
/* Indicates whether to pass in VertexBuffer's as regular buffer bindings
|
||||
* and perform vertex assembly manually, rather than using Stage-in.
|
||||
* This is used to give a vertex shader full access to all of the
|
||||
* vertex data.
|
||||
* This is primarily used for optimization techniques and
|
||||
* alternative solutions for Geometry-shaders which are unsupported
|
||||
* by Metal. */
|
||||
bool use_ssbo_vertex_fetch_mode_ = false;
|
||||
/* Output primitive type when rendering sing ssbo_vertex_fetch. */
|
||||
MTLPrimitiveType ssbo_vertex_fetch_output_prim_type_;
|
||||
|
||||
/* Output vertices per original vertex shader instance.
|
||||
* This number will be multiplied by the number of input primitives
|
||||
* from the source draw call. */
|
||||
uint32_t ssbo_vertex_fetch_output_num_verts_ = 0;
|
||||
|
||||
bool ssbo_vertex_attribute_bind_active_ = false;
|
||||
int ssbo_vertex_attribute_bind_mask_ = 0;
|
||||
bool ssbo_vbo_slot_used_[MTL_SSBO_VERTEX_FETCH_MAX_VBOS];
|
||||
|
||||
struct ShaderSSBOAttributeBinding {
|
||||
int attribute_index = -1;
|
||||
int uniform_stride;
|
||||
int uniform_offset;
|
||||
int uniform_fetchmode;
|
||||
int uniform_vbo_id;
|
||||
int uniform_attr_type;
|
||||
};
|
||||
ShaderSSBOAttributeBinding cached_ssbo_attribute_bindings_[MTL_MAX_VERTEX_INPUT_ATTRIBUTES] = {};
|
||||
|
||||
/* Metal Shader Uniform data store.
|
||||
* This blocks is used to store current shader push_constant
|
||||
* data before it is submitted to the GPU. This is currently
|
||||
@@ -346,34 +307,12 @@ class MTLShader : public Shader {
|
||||
bool get_push_constant_is_dirty();
|
||||
void push_constant_bindstate_mark_dirty(bool is_dirty);
|
||||
|
||||
/* SSBO vertex fetch draw parameters. */
|
||||
bool get_uses_ssbo_vertex_fetch() const override
|
||||
{
|
||||
return use_ssbo_vertex_fetch_mode_;
|
||||
}
|
||||
int get_ssbo_vertex_fetch_output_num_verts() const override
|
||||
{
|
||||
return ssbo_vertex_fetch_output_num_verts_;
|
||||
}
|
||||
|
||||
/* DEPRECATED: Kept only because of BGL API. (Returning -1 in METAL). */
|
||||
int program_handle_get() const override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
MTLPrimitiveType get_ssbo_vertex_fetch_output_prim_type()
|
||||
{
|
||||
return ssbo_vertex_fetch_output_prim_type_;
|
||||
}
|
||||
static int ssbo_vertex_type_to_attr_type(MTLVertexFormat attribute_type);
|
||||
void prepare_ssbo_vertex_fetch_metadata();
|
||||
|
||||
/* SSBO Vertex Bindings Utility functions. */
|
||||
void ssbo_vertex_fetch_bind_attributes_begin();
|
||||
void ssbo_vertex_fetch_bind_attribute(const MTLSSBOAttribute &ssbo_attr);
|
||||
void ssbo_vertex_fetch_bind_attributes_end(id<MTLRenderCommandEncoder> active_encoder);
|
||||
|
||||
/* Metal shader properties and source mapping. */
|
||||
void set_vertex_function_name(NSString *vetex_function_name);
|
||||
void set_fragment_function_name(NSString *fragment_function_name);
|
||||
|
||||
@@ -988,17 +988,7 @@ MTLRenderPipelineStateInstance *MTLShader::bake_pipeline_state(
|
||||
int null_buffer_index = pipeline_descriptor.vertex_descriptor.num_vert_buffers;
|
||||
bool using_null_buffer = false;
|
||||
|
||||
if (this->get_uses_ssbo_vertex_fetch()) {
|
||||
/* If using SSBO Vertex fetch mode, no vertex descriptor is required
|
||||
* as we wont be using stage-in. */
|
||||
desc.vertexDescriptor = nil;
|
||||
desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassUnspecified;
|
||||
|
||||
/* We want to offset the uniform buffer base to allow for sufficient VBO binding slots - We
|
||||
* also require +1 slot for the Index buffer. */
|
||||
MTL_uniform_buffer_base_index = MTL_SSBO_VERTEX_FETCH_IBO_INDEX + 1;
|
||||
}
|
||||
else {
|
||||
{
|
||||
for (const uint i :
|
||||
IndexRange(pipeline_descriptor.vertex_descriptor.max_attribute_value + 1))
|
||||
{
|
||||
@@ -1626,162 +1616,6 @@ MTLComputePipelineStateInstance *MTLShader::bake_compute_pipeline_state(
|
||||
/** \name SSBO-vertex-fetch-mode attribute control.
|
||||
* \{ */
|
||||
|
||||
int MTLShader::ssbo_vertex_type_to_attr_type(MTLVertexFormat attribute_type)
|
||||
{
|
||||
switch (attribute_type) {
|
||||
case MTLVertexFormatFloat:
|
||||
return GPU_SHADER_ATTR_TYPE_FLOAT;
|
||||
case MTLVertexFormatInt:
|
||||
return GPU_SHADER_ATTR_TYPE_INT;
|
||||
case MTLVertexFormatUInt:
|
||||
return GPU_SHADER_ATTR_TYPE_UINT;
|
||||
case MTLVertexFormatShort:
|
||||
return GPU_SHADER_ATTR_TYPE_SHORT;
|
||||
case MTLVertexFormatUChar:
|
||||
return GPU_SHADER_ATTR_TYPE_CHAR;
|
||||
case MTLVertexFormatUChar2:
|
||||
return GPU_SHADER_ATTR_TYPE_CHAR2;
|
||||
case MTLVertexFormatUChar3:
|
||||
return GPU_SHADER_ATTR_TYPE_CHAR3;
|
||||
case MTLVertexFormatUChar4:
|
||||
return GPU_SHADER_ATTR_TYPE_CHAR4;
|
||||
case MTLVertexFormatFloat2:
|
||||
return GPU_SHADER_ATTR_TYPE_VEC2;
|
||||
case MTLVertexFormatFloat3:
|
||||
return GPU_SHADER_ATTR_TYPE_VEC3;
|
||||
case MTLVertexFormatFloat4:
|
||||
return GPU_SHADER_ATTR_TYPE_VEC4;
|
||||
case MTLVertexFormatUInt2:
|
||||
return GPU_SHADER_ATTR_TYPE_UVEC2;
|
||||
case MTLVertexFormatUInt3:
|
||||
return GPU_SHADER_ATTR_TYPE_UVEC3;
|
||||
case MTLVertexFormatUInt4:
|
||||
return GPU_SHADER_ATTR_TYPE_UVEC4;
|
||||
case MTLVertexFormatInt2:
|
||||
return GPU_SHADER_ATTR_TYPE_IVEC2;
|
||||
case MTLVertexFormatInt3:
|
||||
return GPU_SHADER_ATTR_TYPE_IVEC3;
|
||||
case MTLVertexFormatInt4:
|
||||
return GPU_SHADER_ATTR_TYPE_IVEC4;
|
||||
case MTLVertexFormatUCharNormalized:
|
||||
return GPU_SHADER_ATTR_TYPE_UCHAR_NORM;
|
||||
case MTLVertexFormatUChar2Normalized:
|
||||
return GPU_SHADER_ATTR_TYPE_UCHAR2_NORM;
|
||||
case MTLVertexFormatUChar3Normalized:
|
||||
return GPU_SHADER_ATTR_TYPE_UCHAR3_NORM;
|
||||
case MTLVertexFormatUChar4Normalized:
|
||||
return GPU_SHADER_ATTR_TYPE_UCHAR4_NORM;
|
||||
case MTLVertexFormatInt1010102Normalized:
|
||||
return GPU_SHADER_ATTR_TYPE_INT1010102_NORM;
|
||||
case MTLVertexFormatShort3Normalized:
|
||||
return GPU_SHADER_ATTR_TYPE_SHORT3_NORM;
|
||||
default:
|
||||
BLI_assert_msg(false,
|
||||
"Not yet supported attribute type for SSBO vertex fetch -- Add entry "
|
||||
"GPU_SHADER_ATTR_TYPE_** to shader defines, and in this table");
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MTLShader::ssbo_vertex_fetch_bind_attributes_begin()
|
||||
{
|
||||
MTLShaderInterface *mtl_interface = this->get_interface();
|
||||
ssbo_vertex_attribute_bind_active_ = true;
|
||||
ssbo_vertex_attribute_bind_mask_ = (1 << mtl_interface->get_total_attributes()) - 1;
|
||||
|
||||
/* Reset tracking of actively used VBO bind slots for SSBO vertex fetch mode. */
|
||||
for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
ssbo_vbo_slot_used_[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void MTLShader::ssbo_vertex_fetch_bind_attribute(const MTLSSBOAttribute &ssbo_attr)
|
||||
{
|
||||
/* Fetch attribute. */
|
||||
MTLShaderInterface *mtl_interface = this->get_interface();
|
||||
BLI_assert(ssbo_attr.mtl_attribute_index >= 0 &&
|
||||
ssbo_attr.mtl_attribute_index < mtl_interface->get_total_attributes());
|
||||
UNUSED_VARS_NDEBUG(mtl_interface);
|
||||
|
||||
/* Update bind-mask to verify this attribute has been used. */
|
||||
BLI_assert((ssbo_vertex_attribute_bind_mask_ & (1 << ssbo_attr.mtl_attribute_index)) ==
|
||||
(1 << ssbo_attr.mtl_attribute_index) &&
|
||||
"Attribute has already been bound");
|
||||
ssbo_vertex_attribute_bind_mask_ &= ~(1 << ssbo_attr.mtl_attribute_index);
|
||||
|
||||
/* Fetch attribute uniform addresses from cache. */
|
||||
ShaderSSBOAttributeBinding &cached_ssbo_attribute =
|
||||
cached_ssbo_attribute_bindings_[ssbo_attr.mtl_attribute_index];
|
||||
BLI_assert(cached_ssbo_attribute.attribute_index >= 0);
|
||||
|
||||
/* Write attribute descriptor properties to shader uniforms. */
|
||||
this->uniform_int(cached_ssbo_attribute.uniform_offset, 1, 1, &ssbo_attr.attribute_offset);
|
||||
this->uniform_int(cached_ssbo_attribute.uniform_stride, 1, 1, &ssbo_attr.per_vertex_stride);
|
||||
int inst_val = (ssbo_attr.is_instance ? 1 : 0);
|
||||
this->uniform_int(cached_ssbo_attribute.uniform_fetchmode, 1, 1, &inst_val);
|
||||
this->uniform_int(cached_ssbo_attribute.uniform_vbo_id, 1, 1, &ssbo_attr.vbo_id);
|
||||
BLI_assert(ssbo_attr.attribute_format >= 0);
|
||||
this->uniform_int(cached_ssbo_attribute.uniform_attr_type, 1, 1, &ssbo_attr.attribute_format);
|
||||
ssbo_vbo_slot_used_[ssbo_attr.vbo_id] = true;
|
||||
}
|
||||
|
||||
void MTLShader::ssbo_vertex_fetch_bind_attributes_end(
|
||||
id<MTLRenderCommandEncoder> /*active_encoder*/)
|
||||
{
|
||||
ssbo_vertex_attribute_bind_active_ = false;
|
||||
|
||||
/* If our mask is non-zero, we have unassigned attributes. */
|
||||
if (ssbo_vertex_attribute_bind_mask_ != 0) {
|
||||
MTLShaderInterface *mtl_interface = this->get_interface();
|
||||
|
||||
/* Determine if there is a free slot we can bind the null buffer to -- We should have at
|
||||
* least ONE free slot in this instance. */
|
||||
int null_attr_buffer_slot = -1;
|
||||
for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
if (!ssbo_vbo_slot_used_[i]) {
|
||||
null_attr_buffer_slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BLI_assert_msg(null_attr_buffer_slot >= 0,
|
||||
"No suitable bind location for a NULL buffer was found");
|
||||
|
||||
for (int i = 0; i < mtl_interface->get_total_attributes(); i++) {
|
||||
if (ssbo_vertex_attribute_bind_mask_ & (1 << i)) {
|
||||
const MTLShaderInputAttribute *mtl_shader_attribute = &mtl_interface->get_attribute(i);
|
||||
#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
|
||||
MTL_LOG_WARNING(
|
||||
"SSBO Vertex Fetch missing attribute with index: %d. Shader: %s, Attr "
|
||||
"Name: "
|
||||
"%s - Null buffer bound",
|
||||
i,
|
||||
this->name_get(),
|
||||
mtl_shader_attribute->name);
|
||||
#endif
|
||||
/* Bind Attribute with NULL buffer index and stride zero (for constant access). */
|
||||
MTLSSBOAttribute ssbo_attr(
|
||||
i, null_attr_buffer_slot, 0, 0, GPU_SHADER_ATTR_TYPE_FLOAT, false);
|
||||
ssbo_vertex_fetch_bind_attribute(ssbo_attr);
|
||||
MTL_LOG_WARNING(
|
||||
"Unassigned Shader attribute: %s, Attr Name: %s -- Binding NULL BUFFER to "
|
||||
"slot %d",
|
||||
this->name_get().c_str(),
|
||||
mtl_interface->get_name_at_offset(mtl_shader_attribute->name_offset),
|
||||
null_attr_buffer_slot);
|
||||
}
|
||||
}
|
||||
|
||||
/* Bind NULL buffer to given VBO slot. */
|
||||
MTLContext *ctx = MTLContext::get();
|
||||
id<MTLBuffer> null_buf = ctx->get_null_attribute_buffer();
|
||||
BLI_assert(null_buf);
|
||||
|
||||
MTLRenderPassState &rps = ctx->main_command_buffer.get_render_pass_state();
|
||||
rps.bind_vertex_buffer(null_buf, 0, null_attr_buffer_slot);
|
||||
}
|
||||
}
|
||||
|
||||
blender::gpu::VertBuf *MTLShader::get_transform_feedback_active_buffer()
|
||||
{
|
||||
if (transform_feedback_type_ == GPU_SHADER_TFB_NONE || !transform_feedback_active_) {
|
||||
|
||||
@@ -124,80 +124,8 @@
|
||||
* Transform feedback buffer <-- MTL_transform_feedback_buffer_index ~last_buffer+2
|
||||
*
|
||||
* Up to a maximum of 31 bindings.
|
||||
*
|
||||
* -- SSBO-vertex-fetchmode --
|
||||
*
|
||||
* SSBO-vertex-fetchmode is a special option wherein vertex buffers are bound directly
|
||||
* as buffers in the shader, rather than using the VertexDescriptor and [[stage_in]] vertex
|
||||
* assembly.
|
||||
*
|
||||
* The purpose of this mode is to enable random-access reading of all vertex data. This is
|
||||
* particularly useful for efficiently converting geometry shaders to Metal shading language,
|
||||
* as these techniques are not supported natively in Metal.
|
||||
*
|
||||
* Geometry shaders can be re-created by firing off a vertex shader with the desired number of
|
||||
* total output vertices. Each vertex can then read whichever input attributes it needs to
|
||||
* achieve the output result.
|
||||
* This manual reading is also used to provide support for GPU_provoking_vertex, wherein the
|
||||
* output vertex for flat shading needs to change. In these cases, the manual vertex assembly
|
||||
* can flip which vertices are read within the primitive.
|
||||
*
|
||||
* From an efficiency perspective, this is more GPU-friendly than geometry shading, due to improved
|
||||
* parallelism throughout the whole pipe, and for Apple hardware specifically, there is no
|
||||
* significant performance loss from manual vertex assembly vs under-the-hood assembly.
|
||||
*
|
||||
* This mode works by passing the required vertex descriptor information into the shader
|
||||
* as uniform data, describing the type, stride, offset, step-mode and buffer index of each
|
||||
* attribute, such that the shader SSBO-vertex-fetch utility functions know how to extract data.
|
||||
*
|
||||
* This also works with indexed rendering,
|
||||
* by similarly binding the index buffer as a manual buffer.
|
||||
*
|
||||
* When this mode is used, the code generation and shader interface generation varies to
|
||||
* accommodate the required features.
|
||||
*
|
||||
* This mode can be enabled in a shader with:
|
||||
*
|
||||
* `#pragma USE_SSBO_VERTEX_FETCH(TriangleList/LineList, output_vertex_count_per_input_primitive)`
|
||||
*
|
||||
* This mirrors the geometry shader interface `layout(triangle_strip, max_vertices = 3) out;`
|
||||
*/
|
||||
|
||||
/* SSBO vertex fetch attribute uniform parameter names.
|
||||
* These uniforms are used to pass the information
|
||||
* required to perform manual vertex assembly within
|
||||
* the vertex shader.
|
||||
* Each vertex attribute requires a number of properties
|
||||
* in order to correctly extract data from the bound vertex
|
||||
* buffers. */
|
||||
#ifndef NDEBUG
|
||||
/* Global. */
|
||||
# define UNIFORM_SSBO_USES_INDEXED_RENDERING_STR "uniform_ssbo_uses_indexed_rendering"
|
||||
# define UNIFORM_SSBO_INDEX_MODE_U16_STR "uniform_ssbo_index_mode_u16"
|
||||
# define UNIFORM_SSBO_INPUT_PRIM_TYPE_STR "uniform_ssbo_input_prim_type"
|
||||
# define UNIFORM_SSBO_INPUT_VERT_COUNT_STR "uniform_ssbo_input_vert_count"
|
||||
# define UNIFORM_SSBO_INDEX_BASE_STR "uniform_ssbo_index_base_"
|
||||
/* Per-attribute. */
|
||||
# define UNIFORM_SSBO_OFFSET_STR "uniform_ssbo_offset_"
|
||||
# define UNIFORM_SSBO_STRIDE_STR "uniform_ssbo_stride_"
|
||||
# define UNIFORM_SSBO_FETCHMODE_STR "uniform_ssbo_fetchmode_"
|
||||
# define UNIFORM_SSBO_VBO_ID_STR "uniform_ssbo_vbo_id_"
|
||||
# define UNIFORM_SSBO_TYPE_STR "uniform_ssbo_type_"
|
||||
#else
|
||||
/* Global. */
|
||||
# define UNIFORM_SSBO_USES_INDEXED_RENDERING_STR "_ir"
|
||||
# define UNIFORM_SSBO_INDEX_MODE_U16_STR "_mu"
|
||||
# define UNIFORM_SSBO_INPUT_PRIM_TYPE_STR "_pt"
|
||||
# define UNIFORM_SSBO_INPUT_VERT_COUNT_STR "_vc"
|
||||
# define UNIFORM_SSBO_INDEX_BASE_STR "_ib"
|
||||
/* Per-attribute. */
|
||||
# define UNIFORM_SSBO_OFFSET_STR "_so"
|
||||
# define UNIFORM_SSBO_STRIDE_STR "_ss"
|
||||
# define UNIFORM_SSBO_FETCHMODE_STR "_sf"
|
||||
# define UNIFORM_SSBO_VBO_ID_STR "_sv"
|
||||
# define UNIFORM_SSBO_TYPE_STR "_st"
|
||||
#endif
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
struct MSLUniform {
|
||||
@@ -473,11 +401,6 @@ class MSLGeneratorInterface {
|
||||
* NOTE: Compute stage will re-use index 0. */
|
||||
int sampler_argument_buffer_bind_index[3] = {-1, -1, -1};
|
||||
|
||||
/*** SSBO Vertex fetch mode. ***/
|
||||
/* Indicates whether to pass in Vertex Buffer's as a regular buffers instead of using vertex
|
||||
* assembly in the PSO descriptor. Enabled with special pragma. */
|
||||
bool uses_ssbo_vertex_fetch_mode;
|
||||
|
||||
private:
|
||||
/* Parent shader instance. */
|
||||
MTLShader &parent_shader_;
|
||||
@@ -491,22 +414,6 @@ class MSLGeneratorInterface {
|
||||
/** Prepare MSLGeneratorInterface from create-info. **/
|
||||
void prepare_from_createinfo(const shader::ShaderCreateInfo *info);
|
||||
|
||||
/* When SSBO Vertex Fetch mode is used, uniforms are used to pass on the required information
|
||||
* about vertex attribute bindings, in order to perform manual vertex assembly and random-access
|
||||
* vertex lookup throughout the bound VBOs.
|
||||
*
|
||||
* Some parameters are global for the shader, others change with the currently bound
|
||||
* VertexBuffers, and their format, as they do with regular gpu::Batch's.
|
||||
*
|
||||
* (Where ##attr is the attributes name)
|
||||
* uniform_ssbo_stride_##attr -- Representing the stride between elements of attribute(attr)
|
||||
* uniform_ssbo_offset_##attr -- Representing the base offset within the vertex
|
||||
* uniform_ssbo_fetchmode_##attr -- Whether using per-vertex fetch or per-instance fetch
|
||||
* (0=vert, 1=inst) uniform_ssbo_vbo_id_##attr -- index of the vertex buffer within which the
|
||||
* data for this attribute is contained uniform_ssbo_type_##attr - The type of data in the
|
||||
* currently bound buffer -- Could be a mismatch with the Officially reported type. */
|
||||
void prepare_ssbo_vertex_fetch_uniforms();
|
||||
|
||||
/* Samplers. */
|
||||
bool use_argument_buffer_for_samplers() const;
|
||||
uint32_t num_samplers_for_stage(ShaderStage stage) const;
|
||||
|
||||
@@ -170,66 +170,6 @@ static void extract_and_replace_clipping_distances(std::string &vertex_source,
|
||||
}
|
||||
}
|
||||
|
||||
static bool extract_ssbo_pragma_info(const MTLShader *shader,
|
||||
const MSLGeneratorInterface & /*msl_iface*/,
|
||||
const std::string &in_vertex_src,
|
||||
MTLPrimitiveType &out_prim_tye,
|
||||
uint32_t &out_num_output_verts)
|
||||
{
|
||||
/* SSBO Vertex-fetch parameter extraction. */
|
||||
static std::regex use_ssbo_fetch_mode_find(
|
||||
"#pragma "
|
||||
"USE_SSBO_VERTEX_FETCH\\(\\s*(TriangleList|LineList|TriangleStrip|\\w+)\\s*,\\s*([0-9]+)\\s*"
|
||||
"\\)");
|
||||
|
||||
/* Perform regex search if pragma string found. */
|
||||
std::smatch vertex_shader_ssbo_flags;
|
||||
bool uses_ssbo_fetch = false;
|
||||
if (in_vertex_src.find("#pragma USE_SSBO_VERTEX_FETCH") != std::string::npos) {
|
||||
uses_ssbo_fetch = std::regex_search(
|
||||
in_vertex_src, vertex_shader_ssbo_flags, use_ssbo_fetch_mode_find);
|
||||
}
|
||||
if (uses_ssbo_fetch) {
|
||||
/* Extract Expected output primitive type:
|
||||
* #pragma USE_SSBO_VERTEX_FETCH(Output Prim Type, num output vertices per input primitive)
|
||||
*
|
||||
* Supported Primitive Types (Others can be added if needed, but List types for efficiency):
|
||||
* - TriangleList
|
||||
* - LineList
|
||||
* - TriangleStrip (To be used with caution).
|
||||
*
|
||||
* Output vertex count is determined by calculating the number of input primitives, and
|
||||
* multiplying that by the number of output vertices specified. */
|
||||
std::string str_output_primitive_type = vertex_shader_ssbo_flags[1].str();
|
||||
std::string str_output_prim_count_per_vertex = vertex_shader_ssbo_flags[2].str();
|
||||
|
||||
/* Ensure output primitive type is valid. */
|
||||
if (str_output_primitive_type == "TriangleList") {
|
||||
out_prim_tye = MTLPrimitiveTypeTriangle;
|
||||
}
|
||||
else if (str_output_primitive_type == "LineList") {
|
||||
out_prim_tye = MTLPrimitiveTypeLine;
|
||||
}
|
||||
else if (str_output_primitive_type == "TriangleStrip") {
|
||||
out_prim_tye = MTLPrimitiveTypeTriangleStrip;
|
||||
}
|
||||
else {
|
||||
MTL_LOG_ERROR("Unsupported output primitive type for SSBO VERTEX FETCH MODE. Shader: %s",
|
||||
shader->name_get().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Assign output num vertices per primitive. */
|
||||
out_num_output_verts = std::stoi(
|
||||
std::regex_replace(str_output_prim_count_per_vertex, remove_non_numeric_characters, ""));
|
||||
BLI_assert(out_num_output_verts > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* SSBO Vertex fetchmode not used. */
|
||||
return false;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -476,31 +416,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
shd_builder_->glsl_fragment_source_ = msl_defines_string + shd_builder_->glsl_fragment_source_;
|
||||
}
|
||||
|
||||
/* Extract SSBO usage information from shader pragma:
|
||||
*
|
||||
* #pragma USE_SSBO_VERTEX_FETCH(Output Prim Type, num output vertices per input primitive)
|
||||
*
|
||||
* This will determine whether SSBO-vertex-fetch
|
||||
* mode is used for this shader. Returns true if used, and populates output reference
|
||||
* values with the output prim type and output number of vertices. */
|
||||
MTLPrimitiveType vertex_fetch_ssbo_output_prim_type = MTLPrimitiveTypeTriangle;
|
||||
uint32_t vertex_fetch_ssbo_num_output_verts = 0;
|
||||
msl_iface.uses_ssbo_vertex_fetch_mode = extract_ssbo_pragma_info(
|
||||
this,
|
||||
msl_iface,
|
||||
shd_builder_->glsl_vertex_source_,
|
||||
vertex_fetch_ssbo_output_prim_type,
|
||||
vertex_fetch_ssbo_num_output_verts);
|
||||
|
||||
if (msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
shader_debug_printf(
|
||||
"[Shader] SSBO VERTEX FETCH Enabled for Shader '%s' With Output primitive type: %s, "
|
||||
"vertex count: %u\n",
|
||||
this->name_get(),
|
||||
output_primitive_type.c_str(),
|
||||
vertex_fetch_ssbo_num_output_verts);
|
||||
}
|
||||
|
||||
/**** Extract usage of GL globals. ****/
|
||||
/* NOTE(METAL): Currently still performing fallback string scan, as info->builtins_ does
|
||||
* not always contain the usage flag. This can be removed once all appropriate create-info's
|
||||
@@ -516,8 +431,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
shd_builder_->glsl_vertex_source_.find("gl_InstanceID") !=
|
||||
std::string::npos ||
|
||||
shd_builder_->glsl_vertex_source_.find("gpu_InstanceIndex") !=
|
||||
std::string::npos ||
|
||||
msl_iface.uses_ssbo_vertex_fetch_mode;
|
||||
std::string::npos;
|
||||
|
||||
/* instance ID in GL is `[0, instance_count]` in metal it is
|
||||
* `[base_instance, base_instance + instance_count]`,
|
||||
@@ -570,11 +484,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
msl_iface.uses_early_fragment_test = info->early_fragment_test_;
|
||||
}
|
||||
|
||||
/* Generate SSBO vertex fetch mode uniform data hooks. */
|
||||
if (msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
msl_iface.prepare_ssbo_vertex_fetch_uniforms();
|
||||
}
|
||||
|
||||
/* Extract gl_ClipDistances. */
|
||||
extract_and_replace_clipping_distances(shd_builder_->glsl_vertex_source_, msl_iface);
|
||||
|
||||
@@ -603,34 +512,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
ss_vertex << "#define ARGUMENT_BUFFER_NUM_SAMPLERS "
|
||||
<< msl_iface.max_sampler_index_for_stage(ShaderStage::VERTEX) + 1 << std::endl;
|
||||
}
|
||||
if (msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
ss_vertex << "#define MTL_SSBO_VERTEX_FETCH 1" << std::endl;
|
||||
for (const MSLVertexInputAttribute &attr : msl_iface.vertex_input_attributes) {
|
||||
ss_vertex << "#define SSBO_ATTR_TYPE_" << attr.name << " " << attr.type << std::endl;
|
||||
}
|
||||
|
||||
/* Macro's */
|
||||
ss_vertex << "#define "
|
||||
"UNIFORM_SSBO_USES_INDEXED_RENDERING_STR " UNIFORM_SSBO_USES_INDEXED_RENDERING_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_INDEX_MODE_U16_STR " UNIFORM_SSBO_INDEX_MODE_U16_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_INPUT_PRIM_TYPE_STR " UNIFORM_SSBO_INPUT_PRIM_TYPE_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_INPUT_VERT_COUNT_STR " UNIFORM_SSBO_INPUT_VERT_COUNT_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_INDEX_BASE_STR " UNIFORM_SSBO_INDEX_BASE_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_OFFSET_STR " UNIFORM_SSBO_OFFSET_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_STRIDE_STR " UNIFORM_SSBO_STRIDE_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_FETCHMODE_STR " UNIFORM_SSBO_FETCHMODE_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_VBO_ID_STR " UNIFORM_SSBO_VBO_ID_STR
|
||||
"\n"
|
||||
"#define UNIFORM_SSBO_TYPE_STR " UNIFORM_SSBO_TYPE_STR "\n";
|
||||
}
|
||||
|
||||
/* Inject common Metal header. */
|
||||
ss_vertex << msl_iface.msl_patch_default_get() << std::endl << std::endl;
|
||||
@@ -710,9 +591,7 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
|
||||
/** Generate structs from MSL Interface. **/
|
||||
/* Generate VertexIn struct. */
|
||||
if (!msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
ss_vertex << msl_iface.generate_msl_vertex_in_struct();
|
||||
}
|
||||
ss_vertex << msl_iface.generate_msl_vertex_in_struct();
|
||||
/* Generate Uniform data structs. */
|
||||
ss_vertex << msl_iface.generate_msl_uniform_structs(ShaderStage::VERTEX);
|
||||
|
||||
@@ -744,16 +623,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
ss_vertex << "int gpu_ViewportIndex = 0;" << std::endl;
|
||||
}
|
||||
|
||||
/* Global vertex data pointers when using SSBO vertex fetch mode.
|
||||
* Bound vertex buffers passed in via the entry point function
|
||||
* are assigned to these pointers to be globally accessible
|
||||
* from any function within the GLSL source shader. */
|
||||
if (msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
ss_vertex << "constant uchar** MTL_VERTEX_DATA;" << std::endl;
|
||||
ss_vertex << "constant ushort* MTL_INDEX_DATA_U16 = nullptr;" << std::endl;
|
||||
ss_vertex << "constant uint32_t* MTL_INDEX_DATA_U32 = nullptr;" << std::endl;
|
||||
}
|
||||
|
||||
/* Add Texture members.
|
||||
* These members pack both a texture and a sampler into a single
|
||||
* struct, as both are needed within texture functions.
|
||||
@@ -955,12 +824,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
||||
/* Update other shader properties. */
|
||||
uses_gpu_layer = msl_iface.uses_gpu_layer;
|
||||
uses_gpu_viewport_index = msl_iface.uses_gpu_viewport_index;
|
||||
use_ssbo_vertex_fetch_mode_ = msl_iface.uses_ssbo_vertex_fetch_mode;
|
||||
if (msl_iface.uses_ssbo_vertex_fetch_mode) {
|
||||
ssbo_vertex_fetch_output_prim_type_ = vertex_fetch_ssbo_output_prim_type;
|
||||
ssbo_vertex_fetch_output_num_verts_ = vertex_fetch_ssbo_num_output_verts;
|
||||
this->prepare_ssbo_vertex_fetch_metadata();
|
||||
}
|
||||
|
||||
/* Successfully completed GLSL to MSL translation. */
|
||||
return true;
|
||||
@@ -1167,111 +1030,6 @@ constexpr size_t const_strlen(const char *str)
|
||||
return (*str == '\0') ? 0 : const_strlen(str + 1) + 1;
|
||||
}
|
||||
|
||||
void MTLShader::prepare_ssbo_vertex_fetch_metadata()
|
||||
{
|
||||
BLI_assert(use_ssbo_vertex_fetch_mode_);
|
||||
|
||||
/* Cache global SSBO-vertex-fetch uniforms locations. */
|
||||
const ShaderInput *inp_prim_type = interface->uniform_get(UNIFORM_SSBO_INPUT_PRIM_TYPE_STR);
|
||||
const ShaderInput *inp_vert_count = interface->uniform_get(UNIFORM_SSBO_INPUT_VERT_COUNT_STR);
|
||||
const ShaderInput *inp_uses_indexed_rendering = interface->uniform_get(
|
||||
UNIFORM_SSBO_USES_INDEXED_RENDERING_STR);
|
||||
const ShaderInput *inp_uses_index_mode_u16 = interface->uniform_get(
|
||||
UNIFORM_SSBO_INDEX_MODE_U16_STR);
|
||||
const ShaderInput *inp_index_base = interface->uniform_get(UNIFORM_SSBO_INDEX_BASE_STR);
|
||||
|
||||
this->uni_ssbo_input_prim_type_loc = (inp_prim_type != nullptr) ? inp_prim_type->location : -1;
|
||||
this->uni_ssbo_input_vert_count_loc = (inp_vert_count != nullptr) ? inp_vert_count->location :
|
||||
-1;
|
||||
this->uni_ssbo_index_base_loc = (inp_index_base != nullptr) ? inp_index_base->location : -1;
|
||||
|
||||
this->uni_ssbo_uses_indexed_rendering = (inp_uses_indexed_rendering != nullptr) ?
|
||||
inp_uses_indexed_rendering->location :
|
||||
-1;
|
||||
this->uni_ssbo_uses_index_mode_u16 = (inp_uses_index_mode_u16 != nullptr) ?
|
||||
inp_uses_index_mode_u16->location :
|
||||
-1;
|
||||
|
||||
BLI_assert_msg(this->uni_ssbo_input_prim_type_loc != -1,
|
||||
"uni_ssbo_input_prim_type_loc uniform location invalid!");
|
||||
BLI_assert_msg(this->uni_ssbo_input_vert_count_loc != -1,
|
||||
"uni_ssbo_input_vert_count_loc uniform location invalid!");
|
||||
BLI_assert_msg(this->uni_ssbo_uses_indexed_rendering != -1,
|
||||
"uni_ssbo_uses_indexed_rendering uniform location invalid!");
|
||||
BLI_assert_msg(this->uni_ssbo_uses_index_mode_u16 != -1,
|
||||
"uni_ssbo_uses_index_mode_u16 uniform location invalid!");
|
||||
BLI_assert_msg(this->uni_ssbo_index_base_loc != -1,
|
||||
"uni_ssbo_index_base_loc uniform location invalid!");
|
||||
|
||||
/* Prepare SSBO-vertex-fetch attribute uniform location cache. */
|
||||
MTLShaderInterface *mtl_interface = this->get_interface();
|
||||
for (int i = 0; i < mtl_interface->get_total_attributes(); i++) {
|
||||
const MTLShaderInputAttribute &mtl_shader_attribute = mtl_interface->get_attribute(i);
|
||||
const char *attr_name = mtl_interface->get_name_at_offset(mtl_shader_attribute.name_offset);
|
||||
|
||||
/* SSBO-vertex-fetch Attribute data is passed via uniforms. here we need to extract the uniform
|
||||
* address for each attribute, and we can cache it for later use. */
|
||||
ShaderSSBOAttributeBinding &cached_ssbo_attr = cached_ssbo_attribute_bindings_[i];
|
||||
cached_ssbo_attr.attribute_index = i;
|
||||
|
||||
constexpr int len_UNIFORM_SSBO_STRIDE_STR = const_strlen(UNIFORM_SSBO_STRIDE_STR);
|
||||
constexpr int len_UNIFORM_SSBO_OFFSET_STR = const_strlen(UNIFORM_SSBO_OFFSET_STR);
|
||||
constexpr int len_UNIFORM_SSBO_FETCHMODE_STR = const_strlen(UNIFORM_SSBO_FETCHMODE_STR);
|
||||
constexpr int len_UNIFORM_SSBO_VBO_ID_STR = const_strlen(UNIFORM_SSBO_VBO_ID_STR);
|
||||
constexpr int len_UNIFORM_SSBO_TYPE_STR = const_strlen(UNIFORM_SSBO_TYPE_STR);
|
||||
|
||||
char strattr_buf_stride[GPU_VERT_ATTR_MAX_LEN + len_UNIFORM_SSBO_STRIDE_STR + 1] =
|
||||
UNIFORM_SSBO_STRIDE_STR;
|
||||
char strattr_buf_offset[GPU_VERT_ATTR_MAX_LEN + len_UNIFORM_SSBO_OFFSET_STR + 1] =
|
||||
UNIFORM_SSBO_OFFSET_STR;
|
||||
char strattr_buf_fetchmode[GPU_VERT_ATTR_MAX_LEN + len_UNIFORM_SSBO_FETCHMODE_STR + 1] =
|
||||
UNIFORM_SSBO_FETCHMODE_STR;
|
||||
char strattr_buf_vbo_id[GPU_VERT_ATTR_MAX_LEN + len_UNIFORM_SSBO_VBO_ID_STR + 1] =
|
||||
UNIFORM_SSBO_VBO_ID_STR;
|
||||
char strattr_buf_type[GPU_VERT_ATTR_MAX_LEN + len_UNIFORM_SSBO_TYPE_STR + 1] =
|
||||
UNIFORM_SSBO_TYPE_STR;
|
||||
|
||||
BLI_strncpy(
|
||||
&strattr_buf_stride[len_UNIFORM_SSBO_STRIDE_STR], attr_name, GPU_VERT_ATTR_MAX_LEN);
|
||||
BLI_strncpy(
|
||||
&strattr_buf_offset[len_UNIFORM_SSBO_OFFSET_STR], attr_name, GPU_VERT_ATTR_MAX_LEN);
|
||||
BLI_strncpy(
|
||||
&strattr_buf_fetchmode[len_UNIFORM_SSBO_FETCHMODE_STR], attr_name, GPU_VERT_ATTR_MAX_LEN);
|
||||
BLI_strncpy(
|
||||
&strattr_buf_vbo_id[len_UNIFORM_SSBO_VBO_ID_STR], attr_name, GPU_VERT_ATTR_MAX_LEN);
|
||||
BLI_strncpy(&strattr_buf_type[len_UNIFORM_SSBO_TYPE_STR], attr_name, GPU_VERT_ATTR_MAX_LEN);
|
||||
|
||||
/* Fetch uniform locations and cache for fast access. */
|
||||
const ShaderInput *inp_unf_stride = mtl_interface->uniform_get(strattr_buf_stride);
|
||||
const ShaderInput *inp_unf_offset = mtl_interface->uniform_get(strattr_buf_offset);
|
||||
const ShaderInput *inp_unf_fetchmode = mtl_interface->uniform_get(strattr_buf_fetchmode);
|
||||
const ShaderInput *inp_unf_vbo_id = mtl_interface->uniform_get(strattr_buf_vbo_id);
|
||||
const ShaderInput *inp_unf_attr_type = mtl_interface->uniform_get(strattr_buf_type);
|
||||
|
||||
BLI_assert(inp_unf_stride != nullptr);
|
||||
BLI_assert(inp_unf_offset != nullptr);
|
||||
BLI_assert(inp_unf_fetchmode != nullptr);
|
||||
BLI_assert(inp_unf_vbo_id != nullptr);
|
||||
BLI_assert(inp_unf_attr_type != nullptr);
|
||||
|
||||
cached_ssbo_attr.uniform_stride = (inp_unf_stride != nullptr) ? inp_unf_stride->location : -1;
|
||||
cached_ssbo_attr.uniform_offset = (inp_unf_offset != nullptr) ? inp_unf_offset->location : -1;
|
||||
cached_ssbo_attr.uniform_fetchmode = (inp_unf_fetchmode != nullptr) ?
|
||||
inp_unf_fetchmode->location :
|
||||
-1;
|
||||
cached_ssbo_attr.uniform_vbo_id = (inp_unf_vbo_id != nullptr) ? inp_unf_vbo_id->location : -1;
|
||||
cached_ssbo_attr.uniform_attr_type = (inp_unf_attr_type != nullptr) ?
|
||||
inp_unf_attr_type->location :
|
||||
-1;
|
||||
|
||||
BLI_assert(cached_ssbo_attr.uniform_offset != -1);
|
||||
BLI_assert(cached_ssbo_attr.uniform_stride != -1);
|
||||
BLI_assert(cached_ssbo_attr.uniform_fetchmode != -1);
|
||||
BLI_assert(cached_ssbo_attr.uniform_vbo_id != -1);
|
||||
BLI_assert(cached_ssbo_attr.uniform_attr_type != -1);
|
||||
}
|
||||
}
|
||||
|
||||
void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateInfo *info)
|
||||
{
|
||||
/** Assign info. */
|
||||
@@ -1673,27 +1431,6 @@ uint32_t MSLGeneratorInterface::get_sampler_argument_buffer_bind_index(ShaderSta
|
||||
return sampler_argument_buffer_bind_index[get_shader_stage_index(stage)];
|
||||
}
|
||||
|
||||
void MSLGeneratorInterface::prepare_ssbo_vertex_fetch_uniforms()
|
||||
{
|
||||
BLI_assert(this->uses_ssbo_vertex_fetch_mode);
|
||||
|
||||
/* Add Special Uniforms for SSBO vertex fetch mode. */
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_INPUT_PRIM_TYPE_STR, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_INPUT_VERT_COUNT_STR, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_USES_INDEXED_RENDERING_STR, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_INDEX_MODE_U16_STR, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_INDEX_BASE_STR, false));
|
||||
|
||||
for (const MSLVertexInputAttribute &attr : this->vertex_input_attributes) {
|
||||
const std::string &uname = attr.name;
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_STRIDE_STR + uname, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_OFFSET_STR + uname, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_FETCHMODE_STR + uname, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_VBO_ID_STR + uname, false));
|
||||
this->uniforms.append(MSLUniform(Type::INT, UNIFORM_SSBO_TYPE_STR + uname, false));
|
||||
}
|
||||
}
|
||||
|
||||
std::string MSLGeneratorInterface::generate_msl_vertex_entry_stub()
|
||||
{
|
||||
static const char *shader_stage_inst_name = get_shader_stage_instance_name(ShaderStage::VERTEX);
|
||||
@@ -2029,21 +1766,10 @@ std::string MSLGeneratorInterface::generate_msl_vertex_inputs_string()
|
||||
std::stringstream out;
|
||||
bool is_first_parameter = true;
|
||||
|
||||
if (this->uses_ssbo_vertex_fetch_mode) {
|
||||
/* Vertex Buffers bound as raw buffers. */
|
||||
for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
out << parameter_delimiter(is_first_parameter) << "\tconstant uchar* MTL_VERTEX_DATA_" << i
|
||||
<< " [[buffer(" << i << ")]]\n";
|
||||
}
|
||||
out << parameter_delimiter(is_first_parameter)
|
||||
<< "\tconstant ushort* MTL_INDEX_DATA[[buffer(MTL_SSBO_VERTEX_FETCH_IBO_INDEX)]]";
|
||||
}
|
||||
else {
|
||||
if (this->vertex_input_attributes.is_empty() == false) {
|
||||
/* Vertex Buffers use input assembly. */
|
||||
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]]";
|
||||
is_first_parameter = false;
|
||||
}
|
||||
if (this->vertex_input_attributes.is_empty() == false) {
|
||||
/* Vertex Buffers use input assembly. */
|
||||
out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]]";
|
||||
is_first_parameter = false;
|
||||
}
|
||||
|
||||
if (this->uniforms.is_empty() == false) {
|
||||
@@ -2248,7 +1974,7 @@ std::string MSLGeneratorInterface::generate_msl_vertex_in_struct()
|
||||
* float4 __internal_modelmatrix_2 [[attribute(2)]];
|
||||
* float4 __internal_modelmatrix_3 [[attribute(3)]];
|
||||
*/
|
||||
if (is_matrix_type(in_attr.type) && !this->uses_ssbo_vertex_fetch_mode) {
|
||||
if (is_matrix_type(in_attr.type)) {
|
||||
for (int elem = 0; elem < get_matrix_location_count(in_attr.type); elem++) {
|
||||
out << "\t" << get_matrix_subtype(in_attr.type) << " __internal_" << in_attr.name << elem
|
||||
<< " [[attribute(" << (in_attr.layout_location + elem) << ")]];" << std::endl;
|
||||
@@ -2629,27 +2355,6 @@ std::string MSLGeneratorInterface::generate_msl_vertex_attribute_input_populatio
|
||||
{
|
||||
static const char *shader_stage_inst_name = get_shader_stage_instance_name(ShaderStage::VERTEX);
|
||||
|
||||
/* SSBO Vertex Fetch mode does not require local attribute population,
|
||||
* we only need to pass over the buffer pointer references. */
|
||||
if (this->uses_ssbo_vertex_fetch_mode) {
|
||||
std::stringstream out;
|
||||
out << "const constant uchar* GLOBAL_MTL_VERTEX_DATA[MTL_SSBO_VERTEX_FETCH_MAX_VBOS] = {"
|
||||
<< std::endl;
|
||||
for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) {
|
||||
char delimiter = (i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS - 1) ? ',' : ' ';
|
||||
out << "\t\tMTL_VERTEX_DATA_" << i << delimiter << std::endl;
|
||||
}
|
||||
out << "};" << std::endl;
|
||||
out << "\t" << shader_stage_inst_name << ".MTL_VERTEX_DATA = GLOBAL_MTL_VERTEX_DATA;"
|
||||
<< std::endl;
|
||||
out << "\t" << shader_stage_inst_name << ".MTL_INDEX_DATA_U16 = MTL_INDEX_DATA;" << std::endl;
|
||||
out << "\t" << shader_stage_inst_name
|
||||
<< ".MTL_INDEX_DATA_U32 = reinterpret_cast<constant "
|
||||
"uint32_t*>(MTL_INDEX_DATA);"
|
||||
<< std::endl;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
/* Populate local attribute variables. */
|
||||
std::stringstream out;
|
||||
out << "\t/* Copy Vertex Stage-in attributes into local variables */" << std::endl;
|
||||
@@ -3210,24 +2915,19 @@ MTLShaderInterface *MSLGeneratorInterface::bake_shader_interface(
|
||||
this->vertex_input_attributes[attribute].name +
|
||||
std::to_string(elem);
|
||||
|
||||
/* IF Using SSBO vertex Fetch, we do not need to expose other dummy attributes in the
|
||||
* shader interface, only the first one for the whole matrix, as we can pass whatever data
|
||||
* we want in this mode, and do not need to split attributes. */
|
||||
if (elem == 0 || !this->uses_ssbo_vertex_fetch_mode) {
|
||||
interface->add_input_attribute(
|
||||
name_buffer_copystr(&interface->name_buffer_,
|
||||
_internal_name.c_str(),
|
||||
name_buffer_size,
|
||||
name_buffer_offset),
|
||||
this->vertex_input_attributes[attribute].layout_location + elem,
|
||||
mtl_datatype_to_vertex_type(mtl_type),
|
||||
0,
|
||||
size,
|
||||
c_offset,
|
||||
(elem == 0) ?
|
||||
get_matrix_location_count(this->vertex_input_attributes[attribute].type) :
|
||||
0);
|
||||
}
|
||||
interface->add_input_attribute(
|
||||
name_buffer_copystr(&interface->name_buffer_,
|
||||
_internal_name.c_str(),
|
||||
name_buffer_size,
|
||||
name_buffer_offset),
|
||||
this->vertex_input_attributes[attribute].layout_location + elem,
|
||||
mtl_datatype_to_vertex_type(mtl_type),
|
||||
0,
|
||||
size,
|
||||
c_offset,
|
||||
(elem == 0) ?
|
||||
get_matrix_location_count(this->vertex_input_attributes[attribute].type) :
|
||||
0);
|
||||
c_offset += size;
|
||||
}
|
||||
shader_debug_printf(
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Global parameters. */
|
||||
#define MTL_SSBO_VERTEX_FETCH_MAX_VBOS 6 /* buffer bind 0..5 */
|
||||
#define MTL_SSBO_VERTEX_FETCH_IBO_INDEX MTL_SSBO_VERTEX_FETCH_MAX_VBOS
|
||||
|
||||
/* Add Types as needed (Also need to be added to mtl_shader.h). */
|
||||
#define GPU_SHADER_ATTR_TYPE_FLOAT 0
|
||||
#define GPU_SHADER_ATTR_TYPE_INT 1
|
||||
|
||||
@@ -407,7 +407,7 @@ void MTLStateManager::set_provoking_vert(const eGPUProvokingVertex /*vert*/)
|
||||
/* NOTE(Metal): Provoking vertex is not a feature in the Metal API.
|
||||
* Shaders are handled on a case-by-case basis using a modified vertex shader.
|
||||
* For example, wireframe rendering and edit-mesh shaders utilize an SSBO-based
|
||||
* vertex fetching mechanism which considers the inverse convention for flat
|
||||
* vertex pulling mechanism which considers the inverse convention for flat
|
||||
* shading, to ensure consistent results with OpenGL. */
|
||||
}
|
||||
|
||||
|
||||
@@ -187,15 +187,6 @@ class GLShader : public Shader {
|
||||
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
|
||||
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
|
||||
|
||||
/* Unused: SSBO vertex fetch draw parameters. */
|
||||
bool get_uses_ssbo_vertex_fetch() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int get_ssbo_vertex_fetch_output_num_verts() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** DEPRECATED: Kept only because of BGL API. */
|
||||
int program_handle_get() const override;
|
||||
|
||||
@@ -827,77 +827,6 @@ template<int N, int M> inline matrix<float, N, M> operator-(matrix<float, N, M>
|
||||
return a * -1.0;
|
||||
}
|
||||
|
||||
/* SSBO Vertex Fetch Mode. */
|
||||
#ifdef MTL_SSBO_VERTEX_FETCH
|
||||
/**
|
||||
* Enabled when geometry is passed via raw buffer bindings, rather than using
|
||||
* vertex assembly in the vertex-descriptor.
|
||||
*
|
||||
* To describe the layout of input attribute data, we will generate uniforms (defaulting to 0)
|
||||
* with the names per unique input attribute with name `attr`:
|
||||
*
|
||||
* - uniform_ssbo_stride_##attr -- Representing the stride between element.
|
||||
* - uniform_ssbo_offset_##attr -- Representing the base offset within the vertex.
|
||||
* - uniform_ssbo_fetchmode_##attr - Whether using per-vertex (=0) or per-instance fetch (=1).
|
||||
* - uniform_ssbo_vbo_id_##attr - buffer binding index for VBO with data for this attribute.
|
||||
* - uniform_ssbo_type_##attr - The type of data in the currently bound buffer.
|
||||
*
|
||||
* If the uniform_ssbo_type_* does not match with the desired type, then it is the responsibility
|
||||
* of the shader to perform the conversion. Types should always be read as the raw attribute type,
|
||||
* and then converted. e.g. If the uniform_ssbo_type_* is `int`, but we want to read it to be
|
||||
* normalized to a float.
|
||||
* The implementation should query the attribute type using vertex_fetch_get_attr_type(attr_name):
|
||||
*
|
||||
* \code{.cc}
|
||||
* float fweight = 0.0;
|
||||
* if(vertex_fetch_get_attr_type(in_weight) == GPU_SHADER_ATTR_TYPE_INT) {
|
||||
* int iweight = vertex_fetch_attribute(gl_VertexID, in_weight, int);
|
||||
* fweight = (float)iweight/(float)INT32_MAX;
|
||||
* } else {
|
||||
* fweight = = vertex_fetch_attribute(gl_VertexID, in_weight, float);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Note: These uniforms are generated as part of the same data block used for regular uniforms
|
||||
* and attribute data is written prior to each draw call, depending on the configuration of
|
||||
* the vertex descriptor for an MTLBatch or MTLImmedaite call. */
|
||||
# define PPCAT_NX(A, B) A##B
|
||||
# define PPCAT(A, B) PPCAT_NX(A, B)
|
||||
|
||||
# define RESOLVE_VERTEX(v_id) \
|
||||
((UNIFORM_SSBO_USES_INDEXED_RENDERING_STR > 0) ? \
|
||||
(((UNIFORM_SSBO_INDEX_MODE_U16_STR > 0) ? MTL_INDEX_DATA_U16[v_id] : \
|
||||
MTL_INDEX_DATA_U32[v_id]) + \
|
||||
UNIFORM_SSBO_INDEX_BASE_STR) : \
|
||||
v_id)
|
||||
# define ATTR_TYPE(attr) PPCAT(SSBO_ATTR_TYPE_, attr)
|
||||
# define vertex_fetch_attribute_raw(n, attr, type) \
|
||||
(reinterpret_cast<constant type *>( \
|
||||
&MTL_VERTEX_DATA[PPCAT(UNIFORM_SSBO_VBO_ID_STR, attr)] \
|
||||
[(PPCAT(UNIFORM_SSBO_STRIDE_STR, attr) * \
|
||||
((PPCAT(UNIFORM_SSBO_FETCHMODE_STR, attr)) ? gl_InstanceID : n)) + \
|
||||
PPCAT(UNIFORM_SSBO_OFFSET_STR, attr)]))[0]
|
||||
# define vertex_fetch_attribute(n, attr, type) \
|
||||
vertex_fetch_attribute_raw(RESOLVE_VERTEX(n), attr, type)
|
||||
# define vertex_id_from_index_id(n) RESOLVE_VERTEX(n)
|
||||
# define vertex_fetch_get_input_prim_type() UNIFORM_SSBO_INPUT_PRIM_TYPE_STR
|
||||
# define vertex_fetch_get_input_vert_count() UNIFORM_SSBO_INPUT_VERT_COUNT_STR
|
||||
# define vertex_fetch_get_attr_type(attr) PPCAT(UNIFORM_SSBO_TYPE_STR, attr)
|
||||
# define vertex_fetch_get_index_base() UNIFORM_SSBO_INDEX_BASE_STR
|
||||
|
||||
/* Must mirror GPU_primitive.hh. */
|
||||
# define GPU_PRIM_POINTS 0
|
||||
# define GPU_PRIM_LINES 1
|
||||
# define GPU_PRIM_TRIS 2
|
||||
# define GPU_PRIM_LINE_STRIP 3
|
||||
# define GPU_PRIM_LINE_LOOP 4
|
||||
# define GPU_PRIM_TRI_STRIP 5
|
||||
# define GPU_PRIM_TRI_FAN 6
|
||||
# define GPU_PRIM_LINES_ADJ 7
|
||||
# define GPU_PRIM_TRIS_ADJ 8
|
||||
# define GPU_PRIM_LINE_STRIP_ADJ 9
|
||||
#endif
|
||||
|
||||
/* Common Functions. */
|
||||
#define dFdx(x) dfdx(x)
|
||||
#define dFdy(x) dfdy(x)
|
||||
|
||||
@@ -94,16 +94,6 @@ class VKShader : public Shader {
|
||||
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
|
||||
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
|
||||
|
||||
/* Unused: SSBO vertex fetch draw parameters. */
|
||||
bool get_uses_ssbo_vertex_fetch() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int get_ssbo_vertex_fetch_output_num_verts() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DEPRECATED: Kept only because of BGL API. */
|
||||
int program_handle_get() const override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user