Metal: Addressing a number of small outstanding issues across Metal backend.
- Support for non-contiguous shader resource bindings for all cases required by create-info - Implement missing geometry shader alternative path for edit curve handle. - Add support for non-float dummy textures to address all cases where default bindings may be required. Authored by Apple: Michael Parkin-White Ref T96261 Depends on D16721 Reviewed By: fclem Differential Revision: https://developer.blender.org/D16777
This commit is contained in:
parent
844b6e3982
commit
2712265598
Notes:
blender-bot
2023-02-14 09:24:53 +01:00
Referenced by issue #96261, Metal Viewport
|
@ -397,8 +397,8 @@ GPU_SHADER_CREATE_INFO(overlay_edit_curve_handle_no_geom)
|
|||
/* NOTE: Color already in Linear space. Which is what we want. */
|
||||
.define("srgbTarget", "false")
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.vertex_in(1, Type::UINT, "data")
|
||||
.vertex_out(overlay_edit_curve_handle_iface)
|
||||
.vertex_in(1, Type::UCHAR, "data")
|
||||
.vertex_out(overlay_edit_smooth_color_iface)
|
||||
.push_constant(Type::BOOL, "showCurveHandles")
|
||||
.push_constant(Type::INT, "curveHandleDisplay")
|
||||
.fragment_out(0, Type::VEC4, "fragColor")
|
||||
|
|
|
@ -1,16 +1,166 @@
|
|||
/* TODO(Metal): Implement correct SSBO implementation for geom shader workaround.
|
||||
* Currently included as placeholder to unblock failing compilation in Metal. */
|
||||
|
||||
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
|
||||
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
|
||||
#pragma USE_SSBO_VERTEX_FETCH(TriangleStrip, 10)
|
||||
|
||||
#define DISCARD_VERTEX \
|
||||
gl_Position = vec4(0.0); \
|
||||
finalColor = vec4(0.0); \
|
||||
return;
|
||||
|
||||
void output_line(vec2 offset, vec4 color, vec3 out_world_pos, vec4 out_ndc_pos)
|
||||
{
|
||||
finalColor = color;
|
||||
gl_Position = out_ndc_pos;
|
||||
gl_Position.xy += offset * out_ndc_pos.w;
|
||||
view_clipping_distances(out_world_pos);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
GPU_INTEL_VERTEX_SHADER_WORKAROUND
|
||||
|
||||
vec3 world_pos = point_object_to_world(pos);
|
||||
gl_Position = point_world_to_ndc(world_pos);
|
||||
vert.flag = data;
|
||||
/* Perform vertex shader for each input primitive. */
|
||||
vec3 in_pos[2];
|
||||
vec3 world_pos[2];
|
||||
vec4 ndc_pos[2];
|
||||
uint vert_flag[2];
|
||||
|
||||
view_clipping_distances(world_pos);
|
||||
/* Input prim is LineList. */
|
||||
/* Index of the input line primitive. */
|
||||
int input_line_id = gl_VertexID / 10;
|
||||
/* Index of output vertex set. Grouped into pairs as outputted by original "output_line" function
|
||||
* in overlay_edit_curve_handle_geom.glsl. */
|
||||
int output_prim_id = (gl_VertexID / 2) % 5;
|
||||
/* ID of vertex within line primitive (0 or 1) for current vertex. */
|
||||
int output_prim_vert_id = gl_VertexID % 2;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
in_pos[i] = vertex_fetch_attribute((input_line_id * 2) + i, pos, vec3).xyz;
|
||||
vert_flag[i] = (uint)vertex_fetch_attribute((input_line_id * 2) + i, data, uchar);
|
||||
world_pos[i] = point_object_to_world(in_pos[i]);
|
||||
ndc_pos[i] = point_world_to_ndc(world_pos[i]);
|
||||
}
|
||||
|
||||
/* Perform Geometry shader equivalent calculation. */
|
||||
uint is_active_nurb = (vert_flag[1] & ACTIVE_NURB);
|
||||
uint color_id = (vert_flag[1] >> COLOR_SHIFT);
|
||||
|
||||
/* Don't output any edges if we don't show handles */
|
||||
if (!showCurveHandles && (color_id < 5)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool edge_selected = (((vert_flag[1] | vert_flag[0]) & VERT_SELECTED) != 0u);
|
||||
bool handle_selected = (showCurveHandles &&
|
||||
(((vert_flag[1] | vert_flag[0]) & VERT_SELECTED_BEZT_HANDLE) != 0u));
|
||||
|
||||
bool is_gpencil = ((vert_flag[1] & VERT_GPENCIL_BEZT_HANDLE) != 0u);
|
||||
|
||||
/* If handle type is only selected and the edge is not selected, don't show. */
|
||||
if ((curveHandleDisplay != CURVE_HANDLE_ALL) && (!handle_selected)) {
|
||||
/* Nurbs must show the handles always. */
|
||||
bool is_u_segment = (((vert_flag[1] ^ vert_flag[0]) & EVEN_U_BIT) != 0u);
|
||||
if ((!is_u_segment) && (color_id <= 4)) {
|
||||
return;
|
||||
}
|
||||
if (is_gpencil) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 inner_color;
|
||||
if (color_id == 0) {
|
||||
inner_color = (edge_selected) ? colorHandleSelFree : colorHandleFree;
|
||||
}
|
||||
else if (color_id == 1) {
|
||||
inner_color = (edge_selected) ? colorHandleSelAuto : colorHandleAuto;
|
||||
}
|
||||
else if (color_id == 2) {
|
||||
inner_color = (edge_selected) ? colorHandleSelVect : colorHandleVect;
|
||||
}
|
||||
else if (color_id == 3) {
|
||||
inner_color = (edge_selected) ? colorHandleSelAlign : colorHandleAlign;
|
||||
}
|
||||
else if (color_id == 4) {
|
||||
inner_color = (edge_selected) ? colorHandleSelAutoclamp : colorHandleAutoclamp;
|
||||
}
|
||||
else {
|
||||
bool is_selected = (((vert_flag[1] & vert_flag[0]) & VERT_SELECTED) != 0);
|
||||
bool is_u_segment = (((vert_flag[1] ^ vert_flag[0]) & EVEN_U_BIT) != 0);
|
||||
if (is_u_segment) {
|
||||
inner_color = (is_selected) ? colorNurbSelUline : colorNurbUline;
|
||||
}
|
||||
else {
|
||||
inner_color = (is_selected) ? colorNurbSelVline : colorNurbVline;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 outer_color = (is_active_nurb != 0) ?
|
||||
mix(colorActiveSpline,
|
||||
inner_color,
|
||||
0.25) /* Minimize active color bleeding on inner_color. */
|
||||
:
|
||||
vec4(inner_color.rgb, 0.0);
|
||||
|
||||
vec2 v1_2 = (ndc_pos[1].xy / ndc_pos[1].w - ndc_pos[0].xy / ndc_pos[0].w);
|
||||
vec2 offset = sizeEdge * 4.0 * sizeViewportInv; /* 4.0 is eyeballed */
|
||||
|
||||
if (abs(v1_2.x * sizeViewport.x) < abs(v1_2.y * sizeViewport.y)) {
|
||||
offset.y = 0.0;
|
||||
}
|
||||
else {
|
||||
offset.x = 0.0;
|
||||
}
|
||||
|
||||
/* Output geometry based on output line ID. */
|
||||
switch (output_prim_id) {
|
||||
case 0: {
|
||||
/* draw the transparent border (AA). */
|
||||
if (is_active_nurb != 0u) {
|
||||
offset *= 0.75; /* Don't make the active "halo" appear very thick. */
|
||||
output_line(offset * 2.0,
|
||||
vec4(colorActiveSpline.rgb, 0.0),
|
||||
world_pos[output_prim_vert_id],
|
||||
ndc_pos[output_prim_vert_id]);
|
||||
}
|
||||
else {
|
||||
DISCARD_VERTEX
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
/* draw the outline. */
|
||||
output_line(
|
||||
offset, outer_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
/* draw the core of the line. */
|
||||
output_line(
|
||||
vec2(0.0), inner_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
/* draw the outline. */
|
||||
output_line(
|
||||
-offset, outer_color, world_pos[output_prim_vert_id], ndc_pos[output_prim_vert_id]);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
/* draw the transparent border (AA). */
|
||||
if (is_active_nurb != 0u) {
|
||||
output_line(offset * -2.0,
|
||||
vec4(colorActiveSpline.rgb, 0.0),
|
||||
world_pos[output_prim_vert_id],
|
||||
ndc_pos[output_prim_vert_id]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
DISCARD_VERTEX
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -334,6 +334,8 @@ void gpu_shader_create_info_init()
|
|||
overlay_edit_mesh_edge_flat = overlay_edit_mesh_edge_flat_no_geom;
|
||||
overlay_edit_mesh_edge_clipped = overlay_edit_mesh_edge_clipped_no_geom;
|
||||
overlay_edit_mesh_edge_flat_clipped = overlay_edit_mesh_edge_flat_clipped_no_geom;
|
||||
overlay_edit_curve_handle = overlay_edit_curve_handle_no_geom;
|
||||
overlay_edit_curve_handle_clipped = overlay_edit_curve_handle_clipped_no_geom;
|
||||
|
||||
/* Overlay Armature Shape outline. */
|
||||
overlay_armature_shape_outline = overlay_armature_shape_outline_no_geom;
|
||||
|
|
|
@ -43,6 +43,19 @@ typedef enum eGPUTextureType {
|
|||
|
||||
ENUM_OPERATORS(eGPUTextureType, GPU_TEXTURE_CUBE_ARRAY)
|
||||
|
||||
/* Format types for samplers within the shader.
|
||||
* This covers the sampler format type permutations within GLSL/MSL.*/
|
||||
typedef enum eGPUSamplerFormat {
|
||||
GPU_SAMPLER_TYPE_FLOAT = 0,
|
||||
GPU_SAMPLER_TYPE_INT = 1,
|
||||
GPU_SAMPLER_TYPE_UINT = 2,
|
||||
/* Special case for depth, as these require differing dummy formats. */
|
||||
GPU_SAMPLER_TYPE_DEPTH = 3,
|
||||
GPU_SAMPLER_TYPE_MAX = 4
|
||||
} eGPUSamplerFormat;
|
||||
|
||||
ENUM_OPERATORS(eGPUSamplerFormat, GPU_SAMPLER_TYPE_UINT)
|
||||
|
||||
#ifdef DEBUG
|
||||
# define DEBUG_NAME_LEN 64
|
||||
#else
|
||||
|
|
|
@ -154,11 +154,13 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Fetch metal attribute information. */
|
||||
const MTLShaderInputAttribute &mtl_attr = interface->get_attribute(input->location);
|
||||
/* Fetch metal attribute information (ShaderInput->binding is used to fetch the corresponding
|
||||
* slot. */
|
||||
const MTLShaderInputAttribute &mtl_attr = interface->get_attribute(input->binding);
|
||||
BLI_assert(mtl_attr.location >= 0);
|
||||
/* Verify that the attribute location from the shader interface
|
||||
* matches the attribute location returned. */
|
||||
* matches the attribute location returned in the input table. These should always be the
|
||||
* same. */
|
||||
BLI_assert(mtl_attr.location == input->location);
|
||||
|
||||
/* Check if attribute is already present in the given slot. */
|
||||
|
@ -247,12 +249,16 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
|||
buffer_index;
|
||||
|
||||
/* Update total attribute account. */
|
||||
desc.vertex_descriptor.num_attributes = max_ii(
|
||||
mtl_attr.location + i + 1, desc.vertex_descriptor.num_attributes);
|
||||
desc.vertex_descriptor.total_attributes++;
|
||||
desc.vertex_descriptor.max_attribute_value = max_ii(
|
||||
mtl_attr.location + i, desc.vertex_descriptor.max_attribute_value);
|
||||
MTL_LOG_INFO("-- Sub-Attrib Location: %d, offset: %d, buffer index: %d\n",
|
||||
mtl_attr.location + i,
|
||||
attribute_offset + i * 16,
|
||||
buffer_index);
|
||||
|
||||
/* Update attribute used-slot mask for array elements. */
|
||||
attr_mask &= ~(1 << (mtl_attr.location + i));
|
||||
}
|
||||
MTL_LOG_INFO(
|
||||
"Float4x4 attribute type added for '%s' at attribute locations: %d to %d\n",
|
||||
|
@ -262,7 +268,8 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
|||
}
|
||||
|
||||
/* Ensure we are not exceeding the attribute limit. */
|
||||
BLI_assert(desc.vertex_descriptor.num_attributes <= MTL_MAX_VERTEX_INPUT_ATTRIBUTES);
|
||||
BLI_assert(desc.vertex_descriptor.max_attribute_value <
|
||||
MTL_MAX_VERTEX_INPUT_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -330,11 +337,11 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
|||
}
|
||||
desc.vertex_descriptor.attributes[mtl_attr.location].offset = attribute_offset;
|
||||
desc.vertex_descriptor.attributes[mtl_attr.location].buffer_index = buffer_index;
|
||||
desc.vertex_descriptor.num_attributes = ((mtl_attr.location + 1) >
|
||||
desc.vertex_descriptor.num_attributes) ?
|
||||
(mtl_attr.location + 1) :
|
||||
desc.vertex_descriptor.num_attributes;
|
||||
|
||||
desc.vertex_descriptor.max_attribute_value =
|
||||
((mtl_attr.location) > desc.vertex_descriptor.max_attribute_value) ?
|
||||
(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 ==
|
||||
|
@ -356,9 +363,9 @@ int MTLBatch::prepare_vertex_binding(MTLVertBuf *verts,
|
|||
desc.vertex_descriptor.num_ssbo_attributes++;
|
||||
}
|
||||
|
||||
/* NOTE: We are setting num_attributes 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 the
|
||||
* source GPUVertFormat. */
|
||||
/* 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
|
||||
* the source GPUVertFormat. */
|
||||
MTL_LOG_INFO(
|
||||
" -- Batch Attribute(%d): ORIG Shader Format: %d, ORIG Vert format: %d, Vert "
|
||||
"components: %d, Fetch Mode %d --> FINAL FORMAT: %d\n",
|
||||
|
@ -472,6 +479,9 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi
|
|||
this->elem ? @"(indexed)" : @"",
|
||||
active_shader_->get_interface()->get_name()]];
|
||||
}
|
||||
|
||||
/*** Bind Vertex Buffers and Index Buffers **/
|
||||
|
||||
/* SSBO Vertex Fetch Buffer bindings. */
|
||||
if (uses_ssbo_fetch) {
|
||||
|
||||
|
@ -536,7 +546,7 @@ id<MTLRenderCommandEncoder> MTLBatch::bind(uint v_first, uint v_count, uint i_fi
|
|||
* This should happen after all other final rendering setup is complete. */
|
||||
MTLPrimitiveType mtl_prim_type = gpu_prim_type_to_metal(this->prim_type);
|
||||
if (!ctx->ensure_render_pipeline_state(mtl_prim_type)) {
|
||||
printf("FAILED TO ENSURE RENDER PIPELINE STATE");
|
||||
MTL_LOG_ERROR("Failed to prepare and apply render pipeline state.\n");
|
||||
BLI_assert(false);
|
||||
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
|
@ -705,18 +715,22 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings(
|
|||
/* DEBUG: verify if our attribute bindings have been fully provided as expected. */
|
||||
#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
|
||||
if (attr_mask != 0) {
|
||||
for (uint16_t mask = 1, a = 0; a < 16; a++, mask <<= 1) {
|
||||
if (attr_mask & mask) {
|
||||
/* Fallback for setting default attributes, for missed slots. Attributes flagged with
|
||||
* 'MTLVertexFormatInvalid' in the vertex descriptor are bound to a NULL buffer during PSO
|
||||
* creation. */
|
||||
MTL_LOG_WARNING("MTLBatch: Missing expected attribute '%s' at index '%d' for shader: %s\n",
|
||||
this->active_shader->interface->attributes[a].name,
|
||||
a,
|
||||
interface->name);
|
||||
/* Ensure any assigned attribute has not been given an invalid format. This should not
|
||||
* occur and may be the result of an unsupported attribute type conversion. */
|
||||
BLI_assert(desc.attributes[a].format == MTLVertexFormatInvalid);
|
||||
/* Attributes are not necessarily contiguous. */
|
||||
for (int i = 0; i < active_shader_->get_interface()->get_total_attributes(); i++) {
|
||||
const MTLShaderInputAttribute &attr = active_shader_->get_interface()->get_attribute(i);
|
||||
if (attr_mask & (1 << attr.location)) {
|
||||
MTL_LOG_WARNING(
|
||||
"Warning: Missing expected attribute '%s' with location: %u in shader %s (attr "
|
||||
"number: %u)\n",
|
||||
active_shader_->get_interface()->get_name_at_offset(attr.name_offset),
|
||||
attr.location,
|
||||
active_shader_->name_get(),
|
||||
i);
|
||||
|
||||
/* If an attribute is not included, then format in vertex descriptor should be invalid due
|
||||
* to nil assignment. */
|
||||
BLI_assert(desc.vertex_descriptor.attributes[attr.location].format ==
|
||||
MTLVertexFormatInvalid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -655,9 +655,9 @@ class MTLContext : public Context {
|
|||
|
||||
/** Dummy Resources */
|
||||
/* Maximum of 32 texture types. Though most combinations invalid. */
|
||||
gpu::MTLTexture *dummy_textures_[GPU_TEXTURE_BUFFER] = {nullptr};
|
||||
GPUVertFormat dummy_vertformat_;
|
||||
GPUVertBuf *dummy_verts_ = nullptr;
|
||||
gpu::MTLTexture *dummy_textures_[GPU_SAMPLER_TYPE_MAX][GPU_TEXTURE_BUFFER] = {nullptr};
|
||||
GPUVertFormat dummy_vertformat_[GPU_SAMPLER_TYPE_MAX];
|
||||
GPUVertBuf *dummy_verts_[GPU_SAMPLER_TYPE_MAX] = {nullptr};
|
||||
|
||||
public:
|
||||
/* GPUContext interface. */
|
||||
|
@ -743,7 +743,7 @@ class MTLContext : public Context {
|
|||
|
||||
id<MTLBuffer> get_null_buffer();
|
||||
id<MTLBuffer> get_null_attribute_buffer();
|
||||
gpu::MTLTexture *get_dummy_texture(eGPUTextureType type);
|
||||
gpu::MTLTexture *get_dummy_texture(eGPUTextureType type, eGPUSamplerFormat sampler_format);
|
||||
void free_dummy_resources();
|
||||
|
||||
/* State assignment. */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mtl_shader_interface.hh"
|
||||
#include "mtl_state.hh"
|
||||
#include "mtl_uniform_buffer.hh"
|
||||
#include "mtl_vertex_buffer.hh"
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
|
@ -512,53 +513,98 @@ id<MTLBuffer> MTLContext::get_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 */
|
||||
gpu::MTLTexture *dummy_tex = dummy_textures_[type - 1];
|
||||
gpu::MTLTexture *dummy_tex = dummy_textures_[sampler_format][type - 1];
|
||||
if (dummy_tex != nullptr) {
|
||||
return dummy_tex;
|
||||
}
|
||||
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;
|
||||
switch (type) {
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
case GPU_TEXTURE_3D:
|
||||
tex = GPU_texture_create_3d(
|
||||
"Dummy 3D", 128, 128, 1, 1, GPU_RGBA8, GPU_DATA_UBYTE, nullptr);
|
||||
tex = GPU_texture_create_3d("Dummy 3D", 128, 128, 1, 1, format, GPU_DATA_UBYTE, nullptr);
|
||||
break;
|
||||
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;
|
||||
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;
|
||||
case GPU_TEXTURE_BUFFER:
|
||||
if (!dummy_verts_) {
|
||||
GPU_vertformat_clear(&dummy_vertformat_);
|
||||
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);
|
||||
GPU_vertbuf_data_alloc(dummy_verts_, 64);
|
||||
if (!dummy_verts_[sampler_format]) {
|
||||
GPU_vertformat_clear(&dummy_vertformat_[sampler_format]);
|
||||
|
||||
GPUVertCompType comp_type = GPU_COMP_F32;
|
||||
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();
|
||||
}
|
||||
|
||||
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_);
|
||||
tex = GPU_texture_create_from_vertbuf("Dummy TextureBuffer", dummy_verts_[sampler_format]);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_msg(false, "Unrecognised texture type");
|
||||
return nullptr;
|
||||
}
|
||||
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 nullptr;
|
||||
|
@ -566,15 +612,17 @@ gpu::MTLTexture *MTLContext::get_dummy_texture(eGPUTextureType type)
|
|||
|
||||
void MTLContext::free_dummy_resources()
|
||||
{
|
||||
for (int tex = 0; tex < GPU_TEXTURE_BUFFER; tex++) {
|
||||
if (dummy_textures_[tex]) {
|
||||
GPU_texture_free(
|
||||
reinterpret_cast<GPUTexture *>(static_cast<Texture *>(dummy_textures_[tex])));
|
||||
dummy_textures_[tex] = nullptr;
|
||||
for (int format = 0; format < GPU_SAMPLER_TYPE_MAX; format++) {
|
||||
for (int tex = 0; tex < GPU_TEXTURE_BUFFER; tex++) {
|
||||
if (dummy_textures_[format][tex]) {
|
||||
GPU_texture_free(
|
||||
reinterpret_cast<GPUTexture *>(static_cast<Texture *>(dummy_textures_[format][tex])));
|
||||
dummy_textures_[format][tex] = nullptr;
|
||||
}
|
||||
}
|
||||
if (dummy_verts_[format]) {
|
||||
GPU_vertbuf_discard(dummy_verts_[format]);
|
||||
}
|
||||
}
|
||||
if (dummy_verts_) {
|
||||
GPU_vertbuf_discard(dummy_verts_);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,31 +857,31 @@ bool MTLContext::ensure_render_pipeline_state(MTLPrimitiveType mtl_prim_type)
|
|||
}
|
||||
|
||||
/* Transform feedback buffer binding. */
|
||||
/* TOOD(Metal): Include this code once MTLVertBuf is merged. We bind the vertex buffer to which
|
||||
* transform feedback data will be written. */
|
||||
// GPUVertBuf *tf_vbo =
|
||||
// this->pipeline_state.active_shader->get_transform_feedback_active_buffer();
|
||||
// if (tf_vbo != nullptr && pipeline_state_instance->transform_feedback_buffer_index >= 0) {
|
||||
GPUVertBuf *tf_vbo =
|
||||
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 ||
|
||||
// mtl_prim_type == MTLPrimitiveTypeTriangle ||
|
||||
// mtl_prim_type == MTLPrimitiveTypePoint);
|
||||
/* Ensure primitive type is either GPU_LINES, GPU_TRIANGLES or GPU_POINT */
|
||||
BLI_assert(mtl_prim_type == MTLPrimitiveTypeLine ||
|
||||
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));
|
||||
// int tf_buffer_offset = 0;
|
||||
// id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer(&tf_buffer_offset);
|
||||
/* Fetch active transform feedback buffer from vertbuf */
|
||||
MTLVertBuf *tf_vbo_mtl = static_cast<MTLVertBuf *>(reinterpret_cast<VertBuf *>(tf_vbo));
|
||||
/* Ensure TF buffer is ready. */
|
||||
tf_vbo_mtl->bind();
|
||||
id<MTLBuffer> tf_buffer_mtl = tf_vbo_mtl->get_metal_buffer();
|
||||
BLI_assert(tf_buffer_mtl != nil);
|
||||
|
||||
// if (tf_buffer_mtl != nil && tf_buffer_offset >= 0) {
|
||||
// [rec setVertexBuffer:tf_buffer_mtl
|
||||
// offset:tf_buffer_offset
|
||||
// atIndex:pipeline_state_instance->transform_feedback_buffer_index];
|
||||
// printf("Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)\n",
|
||||
// tf_vbo_mtl,
|
||||
// tf_buffer_mtl);
|
||||
// }
|
||||
// }
|
||||
if (tf_buffer_mtl != nil) {
|
||||
[rec setVertexBuffer:tf_buffer_mtl
|
||||
offset:0
|
||||
atIndex:pipeline_state_instance->transform_feedback_buffer_index];
|
||||
MTL_LOG_INFO("Successfully bound VBO: %p for transform feedback (MTL Buffer: %p)\n",
|
||||
tf_vbo_mtl,
|
||||
tf_buffer_mtl);
|
||||
}
|
||||
}
|
||||
|
||||
/* Matrix Bindings. */
|
||||
/* This is now called upon shader bind. We may need to re-evaluate this though,
|
||||
|
@ -1221,7 +1269,9 @@ void MTLContext::ensure_texture_bindings(
|
|||
if (bind_dummy_texture) {
|
||||
if (bool(shader_texture_info.stage_mask & ShaderStage::VERTEX)) {
|
||||
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. */
|
||||
MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE};
|
||||
|
@ -1229,7 +1279,9 @@ void MTLContext::ensure_texture_bindings(
|
|||
}
|
||||
if (bool(shader_texture_info.stage_mask & ShaderStage::FRAGMENT)) {
|
||||
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. */
|
||||
MTLSamplerBinding default_binding = {true, DEFAULT_SAMPLER_STATE};
|
||||
|
|
|
@ -185,8 +185,9 @@ void MTLDrawList::submit()
|
|||
can_use_MDI = can_use_MDI && (is_finishing_a_buffer || command_len_ > 2);
|
||||
|
||||
/* Bind Batch to setup render pipeline state. */
|
||||
BLI_assert(batch_ != nullptr);
|
||||
id<MTLRenderCommandEncoder> rec = batch_->bind(0, 0, 0, 0);
|
||||
if (!rec) {
|
||||
if (rec == nil) {
|
||||
BLI_assert_msg(false, "A RenderCommandEncoder should always be available!\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ void MTLFrameBuffer::bind(bool enabled_srgb)
|
|||
|
||||
/* Verify Context is valid. */
|
||||
if (context_ != static_cast<MTLContext *>(unwrap(GPU_context_active_get()))) {
|
||||
BLI_assert(false && "Trying to use the same frame-buffer in multiple context's.");
|
||||
BLI_assert_msg(false, "Trying to use the same frame-buffer in multiple context's.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -986,7 +986,7 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
|
|||
if (layer == -1) {
|
||||
mtl_depth_attachment_.slice = 0;
|
||||
mtl_depth_attachment_.depth_plane = 0;
|
||||
mtl_depth_attachment_.render_target_array_length = 1;
|
||||
mtl_depth_attachment_.render_target_array_length = 6;
|
||||
use_multilayered_rendering_ = true;
|
||||
}
|
||||
break;
|
||||
|
@ -1007,7 +1007,7 @@ bool MTLFrameBuffer::add_depth_attachment(gpu::MTLTexture *texture, int miplevel
|
|||
mtl_depth_attachment_.depth_plane = 0;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(false && "Unrecognized texture type");
|
||||
BLI_assert_msg(false, "Unrecognized texture type");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1108,7 +1108,7 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
|
|||
if (layer == -1) {
|
||||
mtl_stencil_attachment_.slice = 0;
|
||||
mtl_stencil_attachment_.depth_plane = 0;
|
||||
mtl_stencil_attachment_.render_target_array_length = 1;
|
||||
mtl_stencil_attachment_.render_target_array_length = 6;
|
||||
use_multilayered_rendering_ = true;
|
||||
}
|
||||
break;
|
||||
|
@ -1129,7 +1129,7 @@ bool MTLFrameBuffer::add_stencil_attachment(gpu::MTLTexture *texture, int miplev
|
|||
mtl_stencil_attachment_.depth_plane = 0;
|
||||
break;
|
||||
default:
|
||||
BLI_assert(false && "Unrecognized texture type");
|
||||
BLI_assert_msg(false, "Unrecognized texture type");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,11 +101,11 @@ void MTLImmediate::end()
|
|||
|
||||
/* Reset vertex descriptor to default state. */
|
||||
desc.reset_vertex_descriptor();
|
||||
|
||||
desc.vertex_descriptor.num_attributes = interface->get_total_attributes();
|
||||
desc.vertex_descriptor.total_attributes = interface->get_total_attributes();
|
||||
desc.vertex_descriptor.max_attribute_value = interface->get_total_attributes() - 1;
|
||||
desc.vertex_descriptor.num_vert_buffers = 1;
|
||||
|
||||
for (int i = 0; i < desc.vertex_descriptor.num_attributes; i++) {
|
||||
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 =
|
||||
|
|
|
@ -84,7 +84,8 @@ struct MTLVertexDescriptor {
|
|||
MTLVertexAttributeDescriptorPSO attributes[GPU_VERT_ATTR_MAX_LEN];
|
||||
MTLVertexBufferLayoutDescriptorPSO
|
||||
buffer_layouts[GPU_BATCH_VBO_MAX_LEN + GPU_BATCH_INST_VBO_MAX_LEN];
|
||||
int num_attributes;
|
||||
int max_attribute_value;
|
||||
int total_attributes;
|
||||
int num_vert_buffers;
|
||||
MTLPrimitiveTopologyClass prim_topology_class;
|
||||
|
||||
|
@ -97,7 +98,8 @@ struct MTLVertexDescriptor {
|
|||
|
||||
bool operator==(const MTLVertexDescriptor &other) const
|
||||
{
|
||||
if ((this->num_attributes != other.num_attributes) ||
|
||||
if ((this->max_attribute_value != other.max_attribute_value) ||
|
||||
(this->total_attributes != other.total_attributes) ||
|
||||
(this->num_vert_buffers != other.num_vert_buffers)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -105,7 +107,7 @@ struct MTLVertexDescriptor {
|
|||
return false;
|
||||
};
|
||||
|
||||
for (const int a : IndexRange(this->num_attributes)) {
|
||||
for (const int a : IndexRange(this->max_attribute_value + 1)) {
|
||||
if (!(this->attributes[a] == other.attributes[a])) {
|
||||
return false;
|
||||
}
|
||||
|
@ -125,8 +127,8 @@ struct MTLVertexDescriptor {
|
|||
|
||||
uint64_t hash() const
|
||||
{
|
||||
uint64_t hash = (uint64_t)(this->num_attributes ^ this->num_vert_buffers);
|
||||
for (const int a : IndexRange(this->num_attributes)) {
|
||||
uint64_t hash = (uint64_t)(this->max_attribute_value ^ this->num_vert_buffers);
|
||||
for (const int a : IndexRange(this->max_attribute_value + 1)) {
|
||||
hash ^= this->attributes[a].hash() << a;
|
||||
}
|
||||
|
||||
|
@ -247,7 +249,8 @@ struct MTLRenderPipelineStateDescriptor {
|
|||
/* Reset the Vertex Descriptor to default. */
|
||||
void reset_vertex_descriptor()
|
||||
{
|
||||
vertex_descriptor.num_attributes = 0;
|
||||
vertex_descriptor.total_attributes = 0;
|
||||
vertex_descriptor.max_attribute_value = 0;
|
||||
vertex_descriptor.num_vert_buffers = 0;
|
||||
for (int i = 0; i < GPU_VERT_ATTR_MAX_LEN; i++) {
|
||||
vertex_descriptor.attributes[i].format = MTLVertexFormatInvalid;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "mtl_shader_generator.hh"
|
||||
#include "mtl_shader_interface.hh"
|
||||
#include "mtl_texture.hh"
|
||||
#include "mtl_vertex_buffer.hh"
|
||||
|
||||
extern char datatoc_mtl_shader_common_msl[];
|
||||
|
||||
|
@ -347,9 +348,8 @@ bool MTLShader::transform_feedback_enable(GPUVertBuf *buf)
|
|||
BLI_assert(buf);
|
||||
transform_feedback_active_ = true;
|
||||
transform_feedback_vertbuf_ = buf;
|
||||
/* TODO(Metal): Enable this assertion once #MTLVertBuf lands. */
|
||||
// BLI_assert(static_cast<MTLVertBuf *>(unwrap(transform_feedback_vertbuf_))->get_usage_type() ==
|
||||
// GPU_USAGE_DEVICE_ONLY);
|
||||
BLI_assert(static_cast<MTLVertBuf *>(unwrap(transform_feedback_vertbuf_))->get_usage_type() ==
|
||||
GPU_USAGE_DEVICE_ONLY);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -568,6 +568,7 @@ void MTLShader::shader_source_from_msl(NSString *input_vertex_source,
|
|||
void MTLShader::set_interface(MTLShaderInterface *interface)
|
||||
{
|
||||
/* Assign gpu::Shader super-class interface. */
|
||||
BLI_assert(Shader::interface == nullptr);
|
||||
Shader::interface = interface;
|
||||
}
|
||||
|
||||
|
@ -709,7 +710,7 @@ MTLRenderPipelineStateInstance *MTLShader::bake_current_pipeline_state(
|
|||
MTL_uniform_buffer_base_index = MTL_SSBO_VERTEX_FETCH_IBO_INDEX + 1;
|
||||
}
|
||||
else {
|
||||
for (const uint i : IndexRange(current_state.vertex_descriptor.num_attributes)) {
|
||||
for (const uint i : IndexRange(current_state.vertex_descriptor.max_attribute_value + 1)) {
|
||||
|
||||
/* Metal back-end attribute descriptor state. */
|
||||
MTLVertexAttributeDescriptorPSO &attribute_desc =
|
||||
|
@ -727,8 +728,9 @@ MTLRenderPipelineStateInstance *MTLShader::bake_current_pipeline_state(
|
|||
* https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc
|
||||
*/
|
||||
if (attribute_desc.format == MTLVertexFormatInvalid) {
|
||||
/* If attributes are non-contiguous, we can skip over gaps. */
|
||||
MTL_LOG_WARNING(
|
||||
"MTLShader: baking pipeline state for '%s'- expected input attribute at "
|
||||
"MTLShader: baking pipeline state for '%s'- skipping input attribute at "
|
||||
"index '%d' but none was specified in the current vertex state\n",
|
||||
mtl_interface->get_name(),
|
||||
i);
|
||||
|
@ -777,7 +779,8 @@ MTLRenderPipelineStateInstance *MTLShader::bake_current_pipeline_state(
|
|||
}
|
||||
|
||||
/* Mark empty attribute conversion. */
|
||||
for (int i = current_state.vertex_descriptor.num_attributes; i < GPU_VERT_ATTR_MAX_LEN;
|
||||
for (int i = current_state.vertex_descriptor.max_attribute_value + 1;
|
||||
i < GPU_VERT_ATTR_MAX_LEN;
|
||||
i++) {
|
||||
int MTL_attribute_conversion_mode = 0;
|
||||
[values setConstantValue:&MTL_attribute_conversion_mode
|
||||
|
@ -790,13 +793,15 @@ MTLRenderPipelineStateInstance *MTLShader::bake_current_pipeline_state(
|
|||
* #GPUVertFormat, however, if attributes have not been set, we can sort them out here. */
|
||||
for (const uint i : IndexRange(mtl_interface->get_total_attributes())) {
|
||||
const MTLShaderInputAttribute &attribute = mtl_interface->get_attribute(i);
|
||||
MTLVertexAttributeDescriptor *current_attribute = desc.vertexDescriptor.attributes[i];
|
||||
MTLVertexAttributeDescriptor *current_attribute =
|
||||
desc.vertexDescriptor.attributes[attribute.location];
|
||||
|
||||
if (current_attribute.format == MTLVertexFormatInvalid) {
|
||||
#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
|
||||
MTL_LOG_INFO("-> Filling in unbound attribute '%s' for shader PSO '%s' \n",
|
||||
attribute.name,
|
||||
mtl_interface->name);
|
||||
printf("-> Filling in unbound attribute '%s' for shader PSO '%s' with location: %u\n",
|
||||
mtl_interface->get_name_at_offset(attribute.name_offset),
|
||||
mtl_interface->get_name(),
|
||||
attribute.location);
|
||||
#endif
|
||||
current_attribute.format = attribute.format;
|
||||
current_attribute.offset = 0;
|
||||
|
@ -828,28 +833,30 @@ MTLRenderPipelineStateInstance *MTLShader::bake_current_pipeline_state(
|
|||
}
|
||||
}
|
||||
|
||||
/* Primitive Topology */
|
||||
/* Primitive Topology. */
|
||||
desc.inputPrimitiveTopology = pipeline_descriptor.vertex_descriptor.prim_topology_class;
|
||||
}
|
||||
|
||||
/* Update constant value for 'MTL_uniform_buffer_base_index' */
|
||||
/* Update constant value for 'MTL_uniform_buffer_base_index'. */
|
||||
[values setConstantValue:&MTL_uniform_buffer_base_index
|
||||
type:MTLDataTypeInt
|
||||
withName:@"MTL_uniform_buffer_base_index"];
|
||||
|
||||
/* Transform feedback constant */
|
||||
/* Transform feedback constant.
|
||||
* Ensure buffer is placed after existing buffers, including default buffers. */
|
||||
int MTL_transform_feedback_buffer_index = (this->transform_feedback_type_ !=
|
||||
GPU_SHADER_TFB_NONE) ?
|
||||
MTL_uniform_buffer_base_index +
|
||||
mtl_interface->get_total_uniform_blocks() :
|
||||
mtl_interface->get_max_ubo_index() + 2 :
|
||||
-1;
|
||||
|
||||
if (this->transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
|
||||
[values setConstantValue:&MTL_transform_feedback_buffer_index
|
||||
type:MTLDataTypeInt
|
||||
withName:@"MTL_transform_feedback_buffer_index"];
|
||||
}
|
||||
|
||||
/* gl_PointSize constant */
|
||||
/* gl_PointSize constant. */
|
||||
bool null_pointsize = true;
|
||||
float MTL_pointsize = pipeline_descriptor.point_size;
|
||||
if (pipeline_descriptor.vertex_descriptor.prim_topology_class ==
|
||||
|
|
|
@ -228,6 +228,7 @@ struct MSLTextureSampler {
|
|||
uint location;
|
||||
|
||||
eGPUTextureType get_texture_binding_type() const;
|
||||
eGPUSamplerFormat get_sampler_format() const;
|
||||
|
||||
void resolve_binding_indices();
|
||||
|
||||
|
|
|
@ -336,7 +336,8 @@ static bool extract_ssbo_pragma_info(const MTLShader *shader,
|
|||
/* SSBO Vertex-fetch parameter extraction. */
|
||||
static std::regex use_ssbo_fetch_mode_find(
|
||||
"#pragma "
|
||||
"USE_SSBO_VERTEX_FETCH\\(\\s*(TriangleList|LineList|\\w+)\\s*,\\s*([0-9]+)\\s*\\)");
|
||||
"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;
|
||||
|
@ -352,6 +353,7 @@ static bool extract_ssbo_pragma_info(const MTLShader *shader,
|
|||
* 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. */
|
||||
|
@ -365,6 +367,9 @@ static bool extract_ssbo_pragma_info(const MTLShader *shader,
|
|||
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());
|
||||
|
@ -555,8 +560,6 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info)
|
|||
BLI_assert(shd_builder_->glsl_fragment_source_.size() > 0);
|
||||
}
|
||||
|
||||
/** Determine use of Transform Feedback. **/
|
||||
msl_iface.uses_transform_feedback = false;
|
||||
if (transform_feedback_type_ != GPU_SHADER_TFB_NONE) {
|
||||
/* Ensure #TransformFeedback is configured correctly. */
|
||||
BLI_assert(tf_output_name_list_.size() > 0);
|
||||
|
@ -1270,8 +1273,10 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
|
|||
access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READ;
|
||||
}
|
||||
BLI_assert(used_slot >= 0 && used_slot < MTL_MAX_TEXTURE_SLOTS);
|
||||
|
||||
/* Writeable image targets only assigned to Fragment shader. */
|
||||
MSLTextureSampler msl_tex(
|
||||
ShaderStage::BOTH, res.image.type, res.image.name, access, used_slot);
|
||||
ShaderStage::FRAGMENT, res.image.type, res.image.name, access, used_slot);
|
||||
texture_samplers.append(msl_tex);
|
||||
} break;
|
||||
|
||||
|
@ -1344,6 +1349,10 @@ void MSLGeneratorInterface::prepare_from_createinfo(const shader::ShaderCreateIn
|
|||
|
||||
fragment_outputs.append(mtl_frag_out);
|
||||
}
|
||||
|
||||
/* Transform feedback. */
|
||||
uses_transform_feedback = (create_info_->tf_type_ != GPU_SHADER_TFB_NONE) &&
|
||||
(create_info_->tf_names_.size() > 0);
|
||||
}
|
||||
|
||||
bool MSLGeneratorInterface::use_argument_buffer_for_samplers() const
|
||||
|
@ -1514,7 +1523,7 @@ std::string MSLGeneratorInterface::generate_msl_fragment_entry_stub()
|
|||
if (this->uses_barycentrics) {
|
||||
|
||||
/* Main barycentrics. */
|
||||
out << "fragment_shader_instance.gpu_BaryCoord = mtl_barycentric_coord.xyz;";
|
||||
out << "fragment_shader_instance.gpu_BaryCoord = mtl_barycentric_coord.xyz;" << std::endl;
|
||||
|
||||
/* barycentricDist represents the world-space distance from the current world-space position
|
||||
* to the opposite edge of the vertex. */
|
||||
|
@ -2381,8 +2390,8 @@ std::string MSLGeneratorInterface::generate_msl_texture_vars(ShaderStage shader_
|
|||
out << "\t"
|
||||
<< ((shader_stage == ShaderStage::VERTEX) ? "vertex_shader_instance." :
|
||||
"fragment_shader_instance.")
|
||||
<< this->texture_samplers[i].name << ".samp = &samplers.sampler_args[" << i << "];"
|
||||
<< std::endl;
|
||||
<< this->texture_samplers[i].name << ".samp = &samplers.sampler_args["
|
||||
<< this->texture_samplers[i].location << "];" << std::endl;
|
||||
}
|
||||
else {
|
||||
out << "\t"
|
||||
|
@ -2613,6 +2622,7 @@ MTLShaderInterface *MSLGeneratorInterface::bake_shader_interface(const char *nam
|
|||
name_buffer_offset),
|
||||
texture_sampler.location,
|
||||
texture_sampler.get_texture_binding_type(),
|
||||
texture_sampler.get_sampler_format(),
|
||||
texture_sampler.stage);
|
||||
}
|
||||
|
||||
|
@ -3011,6 +3021,51 @@ eGPUTextureType MSLTextureSampler::get_texture_binding_type() const
|
|||
};
|
||||
}
|
||||
|
||||
eGPUSamplerFormat MSLTextureSampler::get_sampler_format() const
|
||||
{
|
||||
switch (this->type) {
|
||||
case ImageType::FLOAT_BUFFER:
|
||||
case ImageType::FLOAT_1D:
|
||||
case ImageType::FLOAT_1D_ARRAY:
|
||||
case ImageType::FLOAT_2D:
|
||||
case ImageType::FLOAT_2D_ARRAY:
|
||||
case ImageType::FLOAT_3D:
|
||||
case ImageType::FLOAT_CUBE:
|
||||
case ImageType::FLOAT_CUBE_ARRAY:
|
||||
return GPU_SAMPLER_TYPE_FLOAT;
|
||||
case ImageType::INT_BUFFER:
|
||||
case ImageType::INT_1D:
|
||||
case ImageType::INT_1D_ARRAY:
|
||||
case ImageType::INT_2D:
|
||||
case ImageType::INT_2D_ARRAY:
|
||||
case ImageType::INT_3D:
|
||||
case ImageType::INT_CUBE:
|
||||
case ImageType::INT_CUBE_ARRAY:
|
||||
return GPU_SAMPLER_TYPE_INT;
|
||||
case ImageType::UINT_BUFFER:
|
||||
case ImageType::UINT_1D:
|
||||
case ImageType::UINT_1D_ARRAY:
|
||||
case ImageType::UINT_2D:
|
||||
case ImageType::UINT_2D_ARRAY:
|
||||
case ImageType::UINT_3D:
|
||||
case ImageType::UINT_CUBE:
|
||||
case ImageType::UINT_CUBE_ARRAY:
|
||||
return GPU_SAMPLER_TYPE_UINT;
|
||||
case ImageType::SHADOW_2D:
|
||||
case ImageType::SHADOW_2D_ARRAY:
|
||||
case ImageType::SHADOW_CUBE:
|
||||
case ImageType::SHADOW_CUBE_ARRAY:
|
||||
case ImageType::DEPTH_2D:
|
||||
case ImageType::DEPTH_2D_ARRAY:
|
||||
case ImageType::DEPTH_CUBE:
|
||||
case ImageType::DEPTH_CUBE_ARRAY:
|
||||
return GPU_SAMPLER_TYPE_DEPTH;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
return GPU_SAMPLER_TYPE_FLOAT;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
|
|
@ -130,6 +130,7 @@ struct MTLShaderTexture {
|
|||
/* Texture resource bind slot in shader `[[texture(n)]]`. */
|
||||
int slot_index;
|
||||
eGPUTextureType type;
|
||||
eGPUSamplerFormat sampler_format;
|
||||
ShaderStage stage_mask;
|
||||
};
|
||||
|
||||
|
@ -168,6 +169,7 @@ class MTLShaderInterface : public ShaderInterface {
|
|||
|
||||
/* Uniform Blocks. */
|
||||
uint32_t total_uniform_blocks_;
|
||||
uint32_t max_uniformbuf_index_;
|
||||
MTLShaderUniformBlock ubos_[MTL_MAX_UNIFORM_BUFFER_BINDINGS];
|
||||
MTLShaderUniformBlock push_constant_block_;
|
||||
|
||||
|
@ -209,6 +211,7 @@ class MTLShaderInterface : public ShaderInterface {
|
|||
void add_texture(uint32_t name_offset,
|
||||
uint32_t texture_slot,
|
||||
eGPUTextureType tex_binding_type,
|
||||
eGPUSamplerFormat sampler_format,
|
||||
ShaderStage stage_mask = ShaderStage::FRAGMENT);
|
||||
void add_push_constant_block(uint32_t name_offset);
|
||||
|
||||
|
@ -228,6 +231,7 @@ class MTLShaderInterface : public ShaderInterface {
|
|||
/* Fetch Uniform Blocks. */
|
||||
const MTLShaderUniformBlock &get_uniform_block(uint index) const;
|
||||
uint32_t get_total_uniform_blocks() const;
|
||||
uint32_t get_max_ubo_index() const;
|
||||
bool has_uniform_block(uint32_t block_index) const;
|
||||
uint32_t get_uniform_block_size(uint32_t block_index) const;
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ void MTLShaderInterface::init()
|
|||
{
|
||||
total_attributes_ = 0;
|
||||
total_uniform_blocks_ = 0;
|
||||
max_uniformbuf_index_ = 0;
|
||||
total_uniforms_ = 0;
|
||||
total_textures_ = 0;
|
||||
max_texture_index_ = -1;
|
||||
|
@ -121,6 +122,7 @@ uint32_t MTLShaderInterface::add_uniform_block(uint32_t name_offset,
|
|||
uni_block.size = size;
|
||||
uni_block.current_offset = 0;
|
||||
uni_block.stage_mask = ShaderStage::BOTH;
|
||||
max_uniformbuf_index_ = max_ii(max_uniformbuf_index_, buffer_index);
|
||||
return (total_uniform_blocks_++);
|
||||
}
|
||||
|
||||
|
@ -187,9 +189,11 @@ void MTLShaderInterface::add_uniform(uint32_t name_offset, eMTLDataType type, in
|
|||
void MTLShaderInterface::add_texture(uint32_t name_offset,
|
||||
uint32_t texture_slot,
|
||||
eGPUTextureType tex_binding_type,
|
||||
eGPUSamplerFormat sampler_format,
|
||||
ShaderStage stage_mask)
|
||||
{
|
||||
BLI_assert(texture_slot >= 0 && texture_slot < GPU_max_textures());
|
||||
BLI_assert(sampler_format < GPU_SAMPLER_TYPE_MAX);
|
||||
if (texture_slot >= 0 && texture_slot < GPU_max_textures()) {
|
||||
|
||||
MTLShaderTexture &tex = textures_[texture_slot];
|
||||
|
@ -197,6 +201,7 @@ void MTLShaderInterface::add_texture(uint32_t name_offset,
|
|||
tex.name_offset = name_offset;
|
||||
tex.slot_index = texture_slot;
|
||||
tex.type = tex_binding_type;
|
||||
tex.sampler_format = sampler_format;
|
||||
tex.stage_mask = stage_mask;
|
||||
tex.used = true;
|
||||
total_textures_++;
|
||||
|
@ -281,7 +286,11 @@ void MTLShaderInterface::prepare_common_shader_inputs()
|
|||
MTLShaderInputAttribute &shd_attr = attributes_[attr_index];
|
||||
current_input->name_offset = shd_attr.name_offset;
|
||||
current_input->name_hash = BLI_hash_string(this->get_name_at_offset(shd_attr.name_offset));
|
||||
current_input->location = attr_index;
|
||||
/* For Metal, we flatten the vertex attribute indices within the shader in order to minimise
|
||||
* complexity. ShaderInput "Location" contains the original attribute location, as can be
|
||||
* fetched using `GPU_shader_get_attribute_info`. ShaderInput binding contains the array index
|
||||
* into the MTLShaderInterface `attributes_` array. */
|
||||
current_input->location = shd_attr.location;
|
||||
current_input->binding = attr_index;
|
||||
current_input++;
|
||||
}
|
||||
|
@ -419,6 +428,11 @@ uint32_t MTLShaderInterface::get_total_uniform_blocks() const
|
|||
return total_uniform_blocks_;
|
||||
}
|
||||
|
||||
uint32_t MTLShaderInterface::get_max_ubo_index() const
|
||||
{
|
||||
return max_uniformbuf_index_;
|
||||
}
|
||||
|
||||
bool MTLShaderInterface::has_uniform_block(uint32_t block_index) const
|
||||
{
|
||||
return (block_index < total_uniform_blocks_);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "GPU_material.h"
|
||||
|
||||
enum eMTLDataType {
|
||||
MTL_DATATYPE_CHAR,
|
||||
|
@ -249,3 +250,25 @@ inline uint mtl_get_data_type_alignment(eMTLDataType type)
|
|||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
inline eMTLDataType gpu_type_to_mtl_type(eGPUType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GPU_FLOAT:
|
||||
return MTL_DATATYPE_FLOAT;
|
||||
case GPU_VEC2:
|
||||
return MTL_DATATYPE_FLOAT2;
|
||||
case GPU_VEC3:
|
||||
return MTL_DATATYPE_FLOAT3;
|
||||
case GPU_VEC4:
|
||||
return MTL_DATATYPE_FLOAT4;
|
||||
case GPU_MAT3:
|
||||
return MTL_DATATYPE_FLOAT3x3;
|
||||
case GPU_MAT4:
|
||||
return MTL_DATATYPE_FLOAT4x4;
|
||||
default:
|
||||
BLI_assert(false && "Other types unsupported");
|
||||
return MTL_DATATYPE_FLOAT;
|
||||
}
|
||||
return MTL_DATATYPE_FLOAT;
|
||||
}
|
|
@ -1668,9 +1668,6 @@ bool gpu::MTLTexture::init_internal(GPUVertBuf *vbo)
|
|||
/* Track Status. */
|
||||
vert_buffer_ = mtl_vbo;
|
||||
vert_buffer_mtl_ = source_buffer;
|
||||
/* Cleanup. */
|
||||
[texture_descriptor_ release];
|
||||
texture_descriptor_ = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1882,8 +1879,6 @@ void gpu::MTLTexture::ensure_baked()
|
|||
/* Standard texture allocation. */
|
||||
texture_ = [ctx->device newTextureWithDescriptor:texture_descriptor_];
|
||||
|
||||
[texture_descriptor_ release];
|
||||
texture_descriptor_ = nullptr;
|
||||
texture_.label = [NSString stringWithUTF8String:this->get_name()];
|
||||
BLI_assert(texture_);
|
||||
is_baked_ = true;
|
||||
|
|
|
@ -42,6 +42,7 @@ class MTLVertBuf : public VertBuf {
|
|||
* Access limited to friend classes. */
|
||||
id<MTLBuffer> get_metal_buffer()
|
||||
{
|
||||
BLI_assert(vbo_ != nullptr);
|
||||
vbo_->debug_ensure_used();
|
||||
return vbo_->get_metal_buffer();
|
||||
}
|
||||
|
|
|
@ -351,13 +351,23 @@ GPUTexture *IMB_create_gpu_texture(const char *name,
|
|||
bool freebuf = false;
|
||||
|
||||
/* Create Texture. */
|
||||
tex = GPU_texture_create_2d_ex(
|
||||
name, UNPACK2(size), 9999, tex_format, GPU_TEXTURE_USAGE_SHADER_READ, NULL);
|
||||
tex = GPU_texture_create_2d_ex(name,
|
||||
UNPACK2(size),
|
||||
9999,
|
||||
tex_format,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
NULL);
|
||||
if (tex == NULL) {
|
||||
size[0] = max_ii(1, size[0] / 2);
|
||||
size[1] = max_ii(1, size[1] / 2);
|
||||
tex = GPU_texture_create_2d_ex(
|
||||
name, UNPACK2(size), 9999, tex_format, GPU_TEXTURE_USAGE_SHADER_READ, NULL);
|
||||
tex = GPU_texture_create_2d_ex(name,
|
||||
UNPACK2(size),
|
||||
9999,
|
||||
tex_format,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
NULL);
|
||||
do_rescale = true;
|
||||
}
|
||||
BLI_assert(tex != NULL);
|
||||
|
|
Loading…
Reference in New Issue