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:
Jason Fielder 2022-12-20 14:03:22 +01:00 committed by Clément Foucault
parent 844b6e3982
commit 2712265598
Notes: blender-bot 2023-02-14 09:24:53 +01:00
Referenced by issue #96261, Metal Viewport
20 changed files with 480 additions and 135 deletions

View File

@ -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")

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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. */

View File

@ -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};

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 =

View File

@ -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;

View File

@ -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 ==

View File

@ -228,6 +228,7 @@ struct MSLTextureSampler {
uint location;
eGPUTextureType get_texture_binding_type() const;
eGPUSamplerFormat get_sampler_format() const;
void resolve_binding_indices();

View File

@ -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

View File

@ -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;

View File

@ -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_);

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);