Full support for translation and compilation of shaders in Metal, using GPUShaderCreateInfo. Includes render pipeline state creation and management, enabling all standard GPU viewport rendering features in Metal. Authored by Apple: Michael Parkin-White, Marco Giordano Ref T96261 Reviewed By: fclem Maniphest Tasks: T96261 Differential Revision: https://developer.blender.org/D15563
1165 lines
41 KiB
C++
1165 lines
41 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup gpu
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "GPU_batch.h"
|
|
#include "GPU_capabilities.h"
|
|
#include "GPU_shader.h"
|
|
#include "GPU_vertex_format.h"
|
|
|
|
#include <Metal/Metal.h>
|
|
#include <QuartzCore/QuartzCore.h>
|
|
#include <functional>
|
|
#include <unordered_map>
|
|
|
|
#include <mutex>
|
|
#include <thread>
|
|
|
|
#include "mtl_framebuffer.hh"
|
|
#include "mtl_shader_interface.hh"
|
|
#include "mtl_shader_shared.h"
|
|
#include "mtl_state.hh"
|
|
#include "mtl_texture.hh"
|
|
|
|
#include "gpu_shader_create_info.hh"
|
|
#include "gpu_shader_private.hh"
|
|
|
|
namespace blender::gpu {
|
|
|
|
class MTLShaderInterface;
|
|
class MTLContext;
|
|
|
|
/* Debug control. */
|
|
#define MTL_SHADER_DEBUG_EXPORT_SOURCE 1
|
|
#define MTL_SHADER_TRANSLATION_DEBUG_OUTPUT 0
|
|
|
|
/* Separate print used only during development and debugging. */
|
|
#if MTL_SHADER_TRANSLATION_DEBUG_OUTPUT
|
|
# define shader_debug_printf printf
|
|
#else
|
|
# define shader_debug_printf(...) /* Null print. */
|
|
#endif
|
|
|
|
/* Desired reflection data for a buffer binding. */
|
|
struct MTLBufferArgumentData {
|
|
uint32_t index;
|
|
uint32_t size;
|
|
uint32_t alignment;
|
|
bool active;
|
|
};
|
|
|
|
/* Metal Render Pipeline State Instance. */
|
|
struct MTLRenderPipelineStateInstance {
|
|
/* Function instances with specialisation.
|
|
* Required for argument encoder construction. */
|
|
id<MTLFunction> vert;
|
|
id<MTLFunction> frag;
|
|
|
|
/* PSO handle. */
|
|
id<MTLRenderPipelineState> pso;
|
|
|
|
/** Derived information. */
|
|
/* Unique index for PSO variant. */
|
|
uint32_t shader_pso_index;
|
|
/* Base bind index for binding uniform buffers, offset based on other
|
|
* bound buffers such as vertex buffers, as the count can vary. */
|
|
int base_uniform_buffer_index;
|
|
/* buffer bind slot used for null attributes (-1 if not needed). */
|
|
int null_attribute_buffer_index;
|
|
/* buffer bind used for transform feedback output buffer. */
|
|
int transform_feedback_buffer_index;
|
|
|
|
/** Reflection Data.
|
|
* Currently used to verify whether uniform buffers of incorrect sizes being bound, due to left
|
|
* over bindings being used for slots that did not need updating for a particular draw. Metal
|
|
* Backend over-generates bindings due to detecting their presence, though in many cases, the
|
|
* bindings in the source are not all used for a given shader.
|
|
* This information can also be used to eliminate redundant/unused bindings. */
|
|
bool reflection_data_available;
|
|
blender::Vector<MTLBufferArgumentData> buffer_bindings_reflection_data_vert;
|
|
blender::Vector<MTLBufferArgumentData> buffer_bindings_reflection_data_frag;
|
|
};
|
|
|
|
/* MTLShaderBuilder source wrapper used during initial compilation. */
|
|
struct MTLShaderBuilder {
|
|
NSString *msl_source_vert_ = @"";
|
|
NSString *msl_source_frag_ = @"";
|
|
|
|
/* Generated GLSL source used during compilation. */
|
|
std::string glsl_vertex_source_ = "";
|
|
std::string glsl_fragment_source_ = "";
|
|
|
|
/* Indicates whether source code has been provided via MSL directly. */
|
|
bool source_from_msl_ = false;
|
|
};
|
|
|
|
/**
|
|
* MTLShader implements shader compilation, Pipeline State Object (PSO)
|
|
* creation for rendering and uniform data binding.
|
|
* Shaders can either be created from native MSL, or generated
|
|
* from a GLSL source shader using GPUShaderCreateInfo.
|
|
*
|
|
* Shader creation process:
|
|
* - Create MTLShader:
|
|
* - Convert GLSL to MSL source if required.
|
|
* - set MSL source.
|
|
* - set Vertex/Fragment function names.
|
|
* - Create and populate MTLShaderInterface.
|
|
**/
|
|
class MTLShader : public Shader {
|
|
friend shader::ShaderCreateInfo;
|
|
friend shader::StageInterfaceInfo;
|
|
|
|
public:
|
|
/* Cached SSBO vertex fetch attribute uniform locations. */
|
|
int uni_ssbo_input_prim_type_loc = -1;
|
|
int uni_ssbo_input_vert_count_loc = -1;
|
|
int uni_ssbo_uses_indexed_rendering = -1;
|
|
int uni_ssbo_uses_index_mode_u16 = -1;
|
|
|
|
private:
|
|
/* Context Handle. */
|
|
MTLContext *context_ = nullptr;
|
|
|
|
/** Transform Feedback. */
|
|
/* Transform feedback mode. */
|
|
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
|
|
/* Transform feedback outputs written to TFB buffer. */
|
|
blender::Vector<std::string> tf_output_name_list_;
|
|
/* Whether transform feedback is currently active. */
|
|
bool transform_feedback_active_ = false;
|
|
/* Vertex buffer to write transform feedback data into. */
|
|
GPUVertBuf *transform_feedback_vertbuf_ = nullptr;
|
|
|
|
/** Shader source code. */
|
|
MTLShaderBuilder *shd_builder_ = nullptr;
|
|
NSString *vertex_function_name_ = @"";
|
|
NSString *fragment_function_name_ = @"";
|
|
|
|
/** Compiled shader resources. */
|
|
id<MTLLibrary> shader_library_vert_ = nil;
|
|
id<MTLLibrary> shader_library_frag_ = nil;
|
|
bool valid_ = false;
|
|
|
|
/** Render pipeline state and PSO caching. */
|
|
/* Metal API Descriptor used for creation of unique PSOs based on rendering state. */
|
|
MTLRenderPipelineDescriptor *pso_descriptor_ = nil;
|
|
/* Metal backend struct containing all high-level pipeline state parameters
|
|
* which contribute to instantiation of a unique PSO. */
|
|
MTLRenderPipelineStateDescriptor current_pipeline_state_;
|
|
/* Cache of compiled PipelineStateObjects. */
|
|
blender::Map<MTLRenderPipelineStateDescriptor, MTLRenderPipelineStateInstance *> pso_cache_;
|
|
|
|
/* True to enable multi-layered rendering support. */
|
|
bool uses_mtl_array_index_ = false;
|
|
|
|
/** SSBO Vertex fetch pragma options. */
|
|
/* Indicates whether to pass in VertexBuffer's as regular buffer bindings
|
|
* and perform vertex assembly manually, rather than using Stage-in.
|
|
* This is used to give a vertex shader full access to all of the
|
|
* vertex data.
|
|
* This is primarily used for optimisation techniques and
|
|
* alternative solutions for Geometry-shaders which are unsupported
|
|
* by Metal. */
|
|
bool use_ssbo_vertex_fetch_mode_ = false;
|
|
/* Output primitive type when rendering sing ssbo_vertex_fetch. */
|
|
MTLPrimitiveType ssbo_vertex_fetch_output_prim_type_;
|
|
|
|
/* Output vertices per original vertex shader instance.
|
|
* This number will be multiplied by the number of input primitives
|
|
* from the source draw call. */
|
|
uint32_t ssbo_vertex_fetch_output_num_verts_ = 0;
|
|
|
|
bool ssbo_vertex_attribute_bind_active_ = false;
|
|
int ssbo_vertex_attribute_bind_mask_ = 0;
|
|
bool ssbo_vbo_slot_used_[MTL_SSBO_VERTEX_FETCH_MAX_VBOS];
|
|
|
|
struct ShaderSSBOAttributeBinding {
|
|
int attribute_index = -1;
|
|
int uniform_stride;
|
|
int uniform_offset;
|
|
int uniform_fetchmode;
|
|
int uniform_vbo_id;
|
|
int uniform_attr_type;
|
|
};
|
|
ShaderSSBOAttributeBinding cached_ssbo_attribute_bindings_[MTL_MAX_VERTEX_INPUT_ATTRIBUTES] = {};
|
|
|
|
/* Metal Shader Uniform data store.
|
|
* This blocks is used to store current shader push_constant
|
|
* data before it is submitted to the GPU. This is currently
|
|
* stored per shader instance, though depending on GPU module
|
|
* functionality, this could potentially be a global data store.
|
|
* This data is associated with the PushConstantBlock, which is
|
|
* always at index zero in the UBO list. */
|
|
void *push_constant_data_ = nullptr;
|
|
bool push_constant_modified_ = false;
|
|
|
|
public:
|
|
MTLShader(MTLContext *ctx, const char *name);
|
|
MTLShader(MTLContext *ctx,
|
|
MTLShaderInterface *interface,
|
|
const char *name,
|
|
NSString *input_vertex_source,
|
|
NSString *input_fragment_source,
|
|
NSString *vertex_function_name_,
|
|
NSString *fragment_function_name_);
|
|
~MTLShader();
|
|
|
|
/* Assign GLSL source. */
|
|
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
|
|
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
|
|
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
|
|
void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
|
|
|
|
/* Compile and build - Return true if successful. */
|
|
bool finalize(const shader::ShaderCreateInfo *info = nullptr) override;
|
|
|
|
/* Utility. */
|
|
bool is_valid()
|
|
{
|
|
return valid_;
|
|
}
|
|
MTLRenderPipelineStateDescriptor &get_current_pipeline_state()
|
|
{
|
|
return current_pipeline_state_;
|
|
}
|
|
MTLShaderInterface *get_interface()
|
|
{
|
|
return static_cast<MTLShaderInterface *>(this->interface);
|
|
}
|
|
void *get_push_constant_data()
|
|
{
|
|
return push_constant_data_;
|
|
}
|
|
|
|
/* Shader source generators from create-info.
|
|
* These aren't all used by Metal, as certain parts of source code generation
|
|
* for shader entry-points and resource mapping occur during `finalize`. */
|
|
std::string resources_declare(const shader::ShaderCreateInfo &info) const override;
|
|
std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override;
|
|
std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override;
|
|
std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override;
|
|
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override;
|
|
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override;
|
|
|
|
void transform_feedback_names_set(Span<const char *> name_list,
|
|
const eGPUShaderTFBType geom_type) override;
|
|
bool transform_feedback_enable(GPUVertBuf *buf) override;
|
|
void transform_feedback_disable() override;
|
|
|
|
void bind() override;
|
|
void unbind() override;
|
|
|
|
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
|
|
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
|
|
bool get_push_constant_is_dirty();
|
|
void push_constant_bindstate_mark_dirty(bool is_dirty);
|
|
|
|
void vertformat_from_shader(GPUVertFormat *format) const override;
|
|
|
|
/* DEPRECATED: Kept only because of BGL API. (Returning -1 in METAL). */
|
|
int program_handle_get() const override
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
bool get_uses_ssbo_vertex_fetch()
|
|
{
|
|
return use_ssbo_vertex_fetch_mode_;
|
|
}
|
|
MTLPrimitiveType get_ssbo_vertex_fetch_output_prim_type()
|
|
{
|
|
return ssbo_vertex_fetch_output_prim_type_;
|
|
}
|
|
uint32_t get_ssbo_vertex_fetch_output_num_verts()
|
|
{
|
|
return ssbo_vertex_fetch_output_num_verts_;
|
|
}
|
|
static int ssbo_vertex_type_to_attr_type(MTLVertexFormat attribute_type);
|
|
void prepare_ssbo_vertex_fetch_metadata();
|
|
|
|
/* SSBO Vertex Bindings Utility functions. */
|
|
void ssbo_vertex_fetch_bind_attributes_begin();
|
|
void ssbo_vertex_fetch_bind_attribute(const MTLSSBOAttribute &ssbo_attr);
|
|
void ssbo_vertex_fetch_bind_attributes_end(id<MTLRenderCommandEncoder> active_encoder);
|
|
|
|
/* Metal shader properties and source mapping. */
|
|
void set_vertex_function_name(NSString *vetex_function_name);
|
|
void set_fragment_function_name(NSString *fragment_function_name_);
|
|
void shader_source_from_msl(NSString *input_vertex_source, NSString *input_fragment_source);
|
|
void set_interface(MTLShaderInterface *interface);
|
|
MTLRenderPipelineStateInstance *bake_current_pipeline_state(MTLContext *ctx,
|
|
MTLPrimitiveTopologyClass prim_type);
|
|
|
|
/* Transform Feedback. */
|
|
GPUVertBuf *get_transform_feedback_active_buffer();
|
|
bool has_transform_feedback_varying(std::string str);
|
|
|
|
private:
|
|
/* Generate MSL shader from GLSL source. */
|
|
bool generate_msl_from_glsl(const shader::ShaderCreateInfo *info);
|
|
|
|
MEM_CXX_CLASS_ALLOC_FUNCS("MTLShader");
|
|
};
|
|
|
|
/* Vertex format conversion.
|
|
* Determines whether it is possible to resize a vertex attribute type
|
|
* during input assembly. A conversion is implied by the difference
|
|
* between the input vertex descriptor (from MTLBatch/MTLImmediate)
|
|
* and the type specified in the shader source.
|
|
*
|
|
* e.g. vec3 to vec4 expansion, or vec4 to vec2 truncation.
|
|
* Note: Vector expansion will replace empty elements with the values
|
|
* (0,0,0,1).
|
|
*
|
|
* If implicit format resize is not possible, this function
|
|
* returns false.
|
|
*
|
|
* Implicitly supported conversions in Metal are described here:
|
|
* https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc
|
|
*/
|
|
inline bool mtl_vertex_format_resize(MTLVertexFormat mtl_format,
|
|
uint32_t components,
|
|
MTLVertexFormat *r_convertedFormat)
|
|
{
|
|
MTLVertexFormat out_vert_format = MTLVertexFormatInvalid;
|
|
switch (mtl_format) {
|
|
/* Char. */
|
|
case MTLVertexFormatChar:
|
|
case MTLVertexFormatChar2:
|
|
case MTLVertexFormatChar3:
|
|
case MTLVertexFormatChar4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatChar;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatChar2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatChar3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatChar4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Normalized Char. */
|
|
case MTLVertexFormatCharNormalized:
|
|
case MTLVertexFormatChar2Normalized:
|
|
case MTLVertexFormatChar3Normalized:
|
|
case MTLVertexFormatChar4Normalized:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatCharNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatChar2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatChar3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatChar4Normalized;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Unsigned Char. */
|
|
case MTLVertexFormatUChar:
|
|
case MTLVertexFormatUChar2:
|
|
case MTLVertexFormatUChar3:
|
|
case MTLVertexFormatUChar4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUChar;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUChar2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUChar3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUChar4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Normalized Unsigned char */
|
|
case MTLVertexFormatUCharNormalized:
|
|
case MTLVertexFormatUChar2Normalized:
|
|
case MTLVertexFormatUChar3Normalized:
|
|
case MTLVertexFormatUChar4Normalized:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUCharNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUChar2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUChar3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUChar4Normalized;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Short. */
|
|
case MTLVertexFormatShort:
|
|
case MTLVertexFormatShort2:
|
|
case MTLVertexFormatShort3:
|
|
case MTLVertexFormatShort4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatShort;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatShort2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatShort3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatShort4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Normalized Short. */
|
|
case MTLVertexFormatShortNormalized:
|
|
case MTLVertexFormatShort2Normalized:
|
|
case MTLVertexFormatShort3Normalized:
|
|
case MTLVertexFormatShort4Normalized:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatShortNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatShort2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatShort3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatShort4Normalized;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Unsigned Short. */
|
|
case MTLVertexFormatUShort:
|
|
case MTLVertexFormatUShort2:
|
|
case MTLVertexFormatUShort3:
|
|
case MTLVertexFormatUShort4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUShort;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUShort2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUShort3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUShort4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Normalized Unsigned Short. */
|
|
case MTLVertexFormatUShortNormalized:
|
|
case MTLVertexFormatUShort2Normalized:
|
|
case MTLVertexFormatUShort3Normalized:
|
|
case MTLVertexFormatUShort4Normalized:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUShortNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUShort2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUShort3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUShort4Normalized;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Integer. */
|
|
case MTLVertexFormatInt:
|
|
case MTLVertexFormatInt2:
|
|
case MTLVertexFormatInt3:
|
|
case MTLVertexFormatInt4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatInt;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatInt2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatInt3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatInt4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Unsigned Integer. */
|
|
case MTLVertexFormatUInt:
|
|
case MTLVertexFormatUInt2:
|
|
case MTLVertexFormatUInt3:
|
|
case MTLVertexFormatUInt4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUInt;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUInt2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUInt3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUInt4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Half. */
|
|
case MTLVertexFormatHalf:
|
|
case MTLVertexFormatHalf2:
|
|
case MTLVertexFormatHalf3:
|
|
case MTLVertexFormatHalf4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatHalf;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatHalf2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatHalf3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatHalf4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Float. */
|
|
case MTLVertexFormatFloat:
|
|
case MTLVertexFormatFloat2:
|
|
case MTLVertexFormatFloat3:
|
|
case MTLVertexFormatFloat4:
|
|
switch (components) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatFloat;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatFloat2;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatFloat3;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatFloat4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/* Other formats */
|
|
default:
|
|
out_vert_format = mtl_format;
|
|
break;
|
|
}
|
|
*r_convertedFormat = out_vert_format;
|
|
return out_vert_format != MTLVertexFormatInvalid;
|
|
}
|
|
|
|
/* Returns whether the METAL API can internally convert between the input type of data in the
|
|
* incoming vertex buffer and the format used by the vertex attribute inside the shader.
|
|
*
|
|
* - Returns TRUE if the type can be converted internally, along with returning the appropriate
|
|
* type to be passed into the MTLVertexAttributeDescriptorPSO.
|
|
*
|
|
* - Returns FALSE if the type cannot be converted internally e.g. casting Int4 to Float4.
|
|
*
|
|
* If implicit conversion is not possible, then we can fallback to performing manual attribute
|
|
* conversion using the special attribute read function specialisations in the shader.
|
|
* These functions selectively convert between types based on the specified vertex
|
|
* attribute 'GPUVertFetchMode fetch_mode' e.g. GPU_FETCH_INT.
|
|
*/
|
|
inline bool mtl_convert_vertex_format(MTLVertexFormat shader_attrib_format,
|
|
GPUVertCompType component_type,
|
|
uint32_t component_length,
|
|
GPUVertFetchMode fetch_mode,
|
|
MTLVertexFormat *r_convertedFormat)
|
|
{
|
|
bool normalized = (fetch_mode == GPU_FETCH_INT_TO_FLOAT_UNIT);
|
|
MTLVertexFormat out_vert_format = MTLVertexFormatInvalid;
|
|
|
|
switch (component_type) {
|
|
|
|
case GPU_COMP_I8:
|
|
switch (fetch_mode) {
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatChar ||
|
|
shader_attrib_format == MTLVertexFormatChar2 ||
|
|
shader_attrib_format == MTLVertexFormatChar3 ||
|
|
shader_attrib_format == MTLVertexFormatChar4) {
|
|
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_type, &out_vert_format);
|
|
|
|
/* Ensure format resize successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt4 && component_length == 4) {
|
|
/* Allow type expansion - Shader expects MTLVertexFormatInt4, we can supply a type
|
|
* with fewer bytes if component count is the same. Sign must also match original type
|
|
* -- which is not a problem in this case. */
|
|
out_vert_format = MTLVertexFormatChar4;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt3 && component_length == 3) {
|
|
/* Same as above case for matching length and signage (Len=3)*/
|
|
out_vert_format = MTLVertexFormatChar3;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt2 && component_length == 2) {
|
|
/* Same as above case for matching length and signage (Len=2)*/
|
|
out_vert_format = MTLVertexFormatChar2;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt && component_length == 1) {
|
|
/* Same as above case for matching length and signage (Len=1)*/
|
|
out_vert_format = MTLVertexFormatChar;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt && component_length == 4) {
|
|
/* Special case here, format has been specified as GPU_COMP_U8 with 4 components, which
|
|
* is equivalent to an Int -- so data will be compatible with the shader interface. */
|
|
out_vert_format = MTLVertexFormatInt;
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either Char, Char2, Char3, Char4 but "
|
|
"format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
|
|
/* Source vertex data is integer type, but shader interface type is floating point.
|
|
* If the input attribute is specified as normalized, we can convert. */
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
if (normalized) {
|
|
switch (component_length) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatCharNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatChar2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatChar3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatChar4Normalized;
|
|
break;
|
|
default:
|
|
BLI_assert_msg(false, "invalid vertex format");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
}
|
|
else {
|
|
/* Cannot convert. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_U8:
|
|
switch (fetch_mode) {
|
|
/* Fetching INT: Check backing shader format matches source input. */
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatUChar ||
|
|
shader_attrib_format == MTLVertexFormatUChar2 ||
|
|
shader_attrib_format == MTLVertexFormatUChar3 ||
|
|
shader_attrib_format == MTLVertexFormatUChar4) {
|
|
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Ensure format resize successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
/* TODO(Metal): Add other format conversions if needed. Currently no attributes hit
|
|
* this path. */
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatUInt4 && component_length == 4) {
|
|
/* Allow type expansion - Shader expects MTLVertexFormatUInt4, we can supply a type
|
|
* with fewer bytes if component count is the same. */
|
|
out_vert_format = MTLVertexFormatUChar4;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatUInt3 && component_length == 3) {
|
|
/* Same as above case for matching length and signage (Len=3)*/
|
|
out_vert_format = MTLVertexFormatUChar3;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatUInt2 && component_length == 2) {
|
|
/* Same as above case for matching length and signage (Len=2)*/
|
|
out_vert_format = MTLVertexFormatUChar2;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatUInt && component_length == 1) {
|
|
/* Same as above case for matching length and signage (Len=1)*/
|
|
out_vert_format = MTLVertexFormatUChar;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatInt && component_length == 4) {
|
|
/* Special case here, format has been specified as GPU_COMP_U8 with 4 components, which
|
|
* is equivalent to an Int-- so data will be compatible with shader interface. */
|
|
out_vert_format = MTLVertexFormatInt;
|
|
}
|
|
else if (shader_attrib_format == MTLVertexFormatUInt && component_length == 4) {
|
|
/* Special case here, format has been specified as GPU_COMP_U8 with 4 components, which
|
|
*is equivalent to a UInt-- so data will be compatible with shader interface. */
|
|
out_vert_format = MTLVertexFormatUInt;
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either UChar, UChar2, UChar3, UChar4 but "
|
|
"format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
|
|
/* Source vertex data is integral type, but shader interface type is floating point.
|
|
* If the input attribute is specified as normalized, we can convert. */
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
if (normalized) {
|
|
switch (component_length) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUCharNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUChar2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUChar3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUChar4Normalized;
|
|
break;
|
|
default:
|
|
BLI_assert_msg(false, "invalid vertex format");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
}
|
|
else {
|
|
/* Cannot convert. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_I16:
|
|
switch (fetch_mode) {
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatShort ||
|
|
shader_attrib_format == MTLVertexFormatShort2 ||
|
|
shader_attrib_format == MTLVertexFormatShort3 ||
|
|
shader_attrib_format == MTLVertexFormatShort4) {
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Ensure conversion successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either Short, Short2, Short3, Short4 but "
|
|
"format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
|
|
/* Source vertex data is integral type, but shader interface type is floating point.
|
|
* If the input attribute is specified as normalized, we can convert. */
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
if (normalized) {
|
|
switch (component_length) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatShortNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatShort2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatShort3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatShort4Normalized;
|
|
break;
|
|
default:
|
|
BLI_assert_msg(false, "invalid vertex format");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
}
|
|
else {
|
|
/* Cannot convert. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_U16:
|
|
switch (fetch_mode) {
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatUShort ||
|
|
shader_attrib_format == MTLVertexFormatUShort2 ||
|
|
shader_attrib_format == MTLVertexFormatUShort3 ||
|
|
shader_attrib_format == MTLVertexFormatUShort4) {
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Ensure format resize successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either UShort, UShort2, UShort3, UShort4 "
|
|
"but format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
|
|
/* Source vertex data is integral type, but shader interface type is floating point.
|
|
* If the input attribute is specified as normalized, we can convert. */
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
if (normalized) {
|
|
switch (component_length) {
|
|
case 1:
|
|
out_vert_format = MTLVertexFormatUShortNormalized;
|
|
break;
|
|
case 2:
|
|
out_vert_format = MTLVertexFormatUShort2Normalized;
|
|
break;
|
|
case 3:
|
|
out_vert_format = MTLVertexFormatUShort3Normalized;
|
|
break;
|
|
case 4:
|
|
out_vert_format = MTLVertexFormatUShort4Normalized;
|
|
break;
|
|
default:
|
|
BLI_assert_msg(false, "invalid vertex format");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
}
|
|
else {
|
|
/* Cannot convert. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_I32:
|
|
switch (fetch_mode) {
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatInt ||
|
|
shader_attrib_format == MTLVertexFormatInt2 ||
|
|
shader_attrib_format == MTLVertexFormatInt3 ||
|
|
shader_attrib_format == MTLVertexFormatInt4) {
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Verify conversion successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either Int, Int2, Int3, Int4 but format "
|
|
"in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
/* Unfortunately we cannot implicitly convert between Int and Float in METAL. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_U32:
|
|
switch (fetch_mode) {
|
|
case GPU_FETCH_INT:
|
|
if (shader_attrib_format == MTLVertexFormatUInt ||
|
|
shader_attrib_format == MTLVertexFormatUInt2 ||
|
|
shader_attrib_format == MTLVertexFormatUInt3 ||
|
|
shader_attrib_format == MTLVertexFormatUInt4) {
|
|
/* No conversion Needed (as type matches) - Just a vector resize if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Verify conversion successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either UInt, UInt2, UInt3, UInt4 but "
|
|
"format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
/* Unfortunately we cannot convert between UInt and Float in METAL */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_F32:
|
|
switch (fetch_mode) {
|
|
|
|
/* Source data is float. This will be compatible
|
|
* if type specified in shader is also float. */
|
|
case GPU_FETCH_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT:
|
|
case GPU_FETCH_INT_TO_FLOAT_UNIT:
|
|
if (shader_attrib_format == MTLVertexFormatFloat ||
|
|
shader_attrib_format == MTLVertexFormatFloat2 ||
|
|
shader_attrib_format == MTLVertexFormatFloat3 ||
|
|
shader_attrib_format == MTLVertexFormatFloat4) {
|
|
/* No conversion Needed (as type matches) - Just a vector resize, if needed. */
|
|
bool can_convert = mtl_vertex_format_resize(
|
|
shader_attrib_format, component_length, &out_vert_format);
|
|
|
|
/* Verify conversion successful. */
|
|
BLI_assert(can_convert);
|
|
UNUSED_VARS_NDEBUG(can_convert);
|
|
}
|
|
else {
|
|
BLI_assert_msg(false,
|
|
"Source vertex data format is either Float, Float2, Float3, Float4 but "
|
|
"format in shader interface is NOT compatible.\n");
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
}
|
|
break;
|
|
|
|
case GPU_FETCH_INT:
|
|
/* Unfortunately we cannot convert between Float and Int implicitly in METAL. */
|
|
out_vert_format = MTLVertexFormatInvalid;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case GPU_COMP_I10:
|
|
out_vert_format = MTLVertexFormatInt1010102Normalized;
|
|
break;
|
|
}
|
|
*r_convertedFormat = out_vert_format;
|
|
return (out_vert_format != MTLVertexFormatInvalid);
|
|
}
|
|
|
|
inline uint comp_count_from_vert_format(MTLVertexFormat vert_format)
|
|
{
|
|
switch (vert_format) {
|
|
case MTLVertexFormatFloat:
|
|
case MTLVertexFormatInt:
|
|
case MTLVertexFormatUInt:
|
|
case MTLVertexFormatShort:
|
|
case MTLVertexFormatUChar:
|
|
case MTLVertexFormatUCharNormalized:
|
|
return 1;
|
|
case MTLVertexFormatUChar2:
|
|
case MTLVertexFormatUInt2:
|
|
case MTLVertexFormatFloat2:
|
|
case MTLVertexFormatInt2:
|
|
case MTLVertexFormatUChar2Normalized:
|
|
return 2;
|
|
case MTLVertexFormatUChar3:
|
|
case MTLVertexFormatUInt3:
|
|
case MTLVertexFormatFloat3:
|
|
case MTLVertexFormatInt3:
|
|
case MTLVertexFormatShort3Normalized:
|
|
case MTLVertexFormatUChar3Normalized:
|
|
return 3;
|
|
case MTLVertexFormatUChar4:
|
|
case MTLVertexFormatFloat4:
|
|
case MTLVertexFormatUInt4:
|
|
case MTLVertexFormatInt4:
|
|
case MTLVertexFormatUChar4Normalized:
|
|
case MTLVertexFormatInt1010102Normalized:
|
|
|
|
default:
|
|
BLI_assert_msg(false, "Unrecognised attribute type. Add types to switch as needed.");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
inline GPUVertFetchMode fetchmode_from_vert_format(MTLVertexFormat vert_format)
|
|
{
|
|
switch (vert_format) {
|
|
case MTLVertexFormatFloat:
|
|
case MTLVertexFormatFloat2:
|
|
case MTLVertexFormatFloat3:
|
|
case MTLVertexFormatFloat4:
|
|
return GPU_FETCH_FLOAT;
|
|
|
|
case MTLVertexFormatUChar:
|
|
case MTLVertexFormatUChar2:
|
|
case MTLVertexFormatUChar3:
|
|
case MTLVertexFormatUChar4:
|
|
case MTLVertexFormatChar:
|
|
case MTLVertexFormatChar2:
|
|
case MTLVertexFormatChar3:
|
|
case MTLVertexFormatChar4:
|
|
case MTLVertexFormatUShort:
|
|
case MTLVertexFormatUShort2:
|
|
case MTLVertexFormatUShort3:
|
|
case MTLVertexFormatUShort4:
|
|
case MTLVertexFormatShort:
|
|
case MTLVertexFormatShort2:
|
|
case MTLVertexFormatShort3:
|
|
case MTLVertexFormatShort4:
|
|
case MTLVertexFormatUInt:
|
|
case MTLVertexFormatUInt2:
|
|
case MTLVertexFormatUInt3:
|
|
case MTLVertexFormatUInt4:
|
|
case MTLVertexFormatInt:
|
|
case MTLVertexFormatInt2:
|
|
case MTLVertexFormatInt3:
|
|
case MTLVertexFormatInt4:
|
|
return GPU_FETCH_INT;
|
|
|
|
case MTLVertexFormatUCharNormalized:
|
|
case MTLVertexFormatUChar2Normalized:
|
|
case MTLVertexFormatUChar3Normalized:
|
|
case MTLVertexFormatUChar4Normalized:
|
|
case MTLVertexFormatCharNormalized:
|
|
case MTLVertexFormatChar2Normalized:
|
|
case MTLVertexFormatChar3Normalized:
|
|
case MTLVertexFormatChar4Normalized:
|
|
case MTLVertexFormatUShortNormalized:
|
|
case MTLVertexFormatUShort2Normalized:
|
|
case MTLVertexFormatUShort3Normalized:
|
|
case MTLVertexFormatUShort4Normalized:
|
|
case MTLVertexFormatShortNormalized:
|
|
case MTLVertexFormatShort2Normalized:
|
|
case MTLVertexFormatShort3Normalized:
|
|
case MTLVertexFormatShort4Normalized:
|
|
case MTLVertexFormatInt1010102Normalized:
|
|
return GPU_FETCH_INT_TO_FLOAT_UNIT;
|
|
|
|
default:
|
|
BLI_assert_msg(false, "Unrecognised attribute type. Add types to switch as needed.");
|
|
return GPU_FETCH_FLOAT;
|
|
}
|
|
}
|
|
|
|
inline GPUVertCompType comp_type_from_vert_format(MTLVertexFormat vert_format)
|
|
{
|
|
switch (vert_format) {
|
|
case MTLVertexFormatUChar:
|
|
case MTLVertexFormatUChar2:
|
|
case MTLVertexFormatUChar3:
|
|
case MTLVertexFormatUChar4:
|
|
case MTLVertexFormatUCharNormalized:
|
|
case MTLVertexFormatUChar2Normalized:
|
|
case MTLVertexFormatUChar3Normalized:
|
|
case MTLVertexFormatUChar4Normalized:
|
|
return GPU_COMP_U8;
|
|
|
|
case MTLVertexFormatChar:
|
|
case MTLVertexFormatChar2:
|
|
case MTLVertexFormatChar3:
|
|
case MTLVertexFormatChar4:
|
|
case MTLVertexFormatCharNormalized:
|
|
case MTLVertexFormatChar2Normalized:
|
|
case MTLVertexFormatChar3Normalized:
|
|
case MTLVertexFormatChar4Normalized:
|
|
return GPU_COMP_I8;
|
|
|
|
case MTLVertexFormatShort:
|
|
case MTLVertexFormatShort2:
|
|
case MTLVertexFormatShort3:
|
|
case MTLVertexFormatShort4:
|
|
case MTLVertexFormatShortNormalized:
|
|
case MTLVertexFormatShort2Normalized:
|
|
case MTLVertexFormatShort3Normalized:
|
|
case MTLVertexFormatShort4Normalized:
|
|
return GPU_COMP_I16;
|
|
|
|
case MTLVertexFormatUShort:
|
|
case MTLVertexFormatUShort2:
|
|
case MTLVertexFormatUShort3:
|
|
case MTLVertexFormatUShort4:
|
|
case MTLVertexFormatUShortNormalized:
|
|
case MTLVertexFormatUShort2Normalized:
|
|
case MTLVertexFormatUShort3Normalized:
|
|
case MTLVertexFormatUShort4Normalized:
|
|
return GPU_COMP_U16;
|
|
|
|
case MTLVertexFormatInt:
|
|
case MTLVertexFormatInt2:
|
|
case MTLVertexFormatInt3:
|
|
case MTLVertexFormatInt4:
|
|
return GPU_COMP_I32;
|
|
|
|
case MTLVertexFormatUInt:
|
|
case MTLVertexFormatUInt2:
|
|
case MTLVertexFormatUInt3:
|
|
case MTLVertexFormatUInt4:
|
|
return GPU_COMP_U32;
|
|
|
|
case MTLVertexFormatFloat:
|
|
case MTLVertexFormatFloat2:
|
|
case MTLVertexFormatFloat3:
|
|
case MTLVertexFormatFloat4:
|
|
return GPU_COMP_F32;
|
|
|
|
case MTLVertexFormatInt1010102Normalized:
|
|
return GPU_COMP_I10;
|
|
|
|
default:
|
|
BLI_assert_msg(false, "Unrecognised attribute type. Add types to switch as needed.");
|
|
return GPU_COMP_F32;
|
|
}
|
|
}
|
|
|
|
} // namespace blender::gpu
|