1219 lines
43 KiB
C++
1219 lines
43 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 0
|
|
#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 specialization.
|
|
* 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;
|
|
/* Base bind index for binding storage buffers. */
|
|
int base_ssbo_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;
|
|
/* Topology class. */
|
|
MTLPrimitiveTopologyClass prim_type;
|
|
|
|
/** 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
|
|
* Back-end 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;
|
|
};
|
|
|
|
/* Metal COmpute Pipeline State instance. */
|
|
struct MTLComputePipelineStateInstance {
|
|
/* Function instances with specialization.
|
|
* Required for argument encoder construction. */
|
|
id<MTLFunction> compute = nil;
|
|
/* PSO handle. */
|
|
id<MTLComputePipelineState> pso = nil;
|
|
/* 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 = -1;
|
|
/* Base bind index for binding storage buffers. */
|
|
int base_ssbo_buffer_index = -1;
|
|
|
|
int threadgroup_x_len = 1;
|
|
int threadgroup_y_len = 1;
|
|
int threadgroup_z_len = 1;
|
|
|
|
inline void set_compute_workgroup_size(int workgroup_size_x,
|
|
int workgroup_size_y,
|
|
int workgroup_size_z)
|
|
{
|
|
this->threadgroup_x_len = workgroup_size_x;
|
|
this->threadgroup_y_len = workgroup_size_y;
|
|
this->threadgroup_z_len = workgroup_size_z;
|
|
}
|
|
};
|
|
|
|
/* #MTLShaderBuilder source wrapper used during initial compilation. */
|
|
struct MTLShaderBuilder {
|
|
NSString *msl_source_vert_ = @"";
|
|
NSString *msl_source_frag_ = @"";
|
|
NSString *msl_source_compute_ = @"";
|
|
|
|
/* Generated GLSL source used during compilation. */
|
|
std::string glsl_vertex_source_ = "";
|
|
std::string glsl_fragment_source_ = "";
|
|
std::string glsl_compute_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_ = @"";
|
|
NSString *compute_function_name_ = @"";
|
|
|
|
/** Compiled shader resources. */
|
|
id<MTLLibrary> shader_library_vert_ = nil;
|
|
id<MTLLibrary> shader_library_frag_ = nil;
|
|
id<MTLLibrary> shader_library_compute_ = 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_;
|
|
std::mutex pso_cache_lock_;
|
|
|
|
/** Compute pipeline state and Compute PSO caching. */
|
|
MTLComputePipelineStateInstance compute_pso_instance_;
|
|
|
|
/* 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 optimization techniques and
|
|
* alternative solutions for Geometry-shaders which are unsupported
|
|
* by Metal. */
|
|
bool use_ssbo_vertex_fetch_mode_ = false;
|
|
/* Output primitive type when rendering sing ssbo_vertex_fetch. */
|
|
MTLPrimitiveType ssbo_vertex_fetch_output_prim_type_;
|
|
|
|
/* Output vertices per original vertex shader instance.
|
|
* This number will be multiplied by the number of input primitives
|
|
* from the source draw call. */
|
|
uint32_t ssbo_vertex_fetch_output_num_verts_ = 0;
|
|
|
|
bool ssbo_vertex_attribute_bind_active_ = false;
|
|
int ssbo_vertex_attribute_bind_mask_ = 0;
|
|
bool ssbo_vbo_slot_used_[MTL_SSBO_VERTEX_FETCH_MAX_VBOS];
|
|
|
|
struct ShaderSSBOAttributeBinding {
|
|
int attribute_index = -1;
|
|
int uniform_stride;
|
|
int uniform_offset;
|
|
int uniform_fetchmode;
|
|
int uniform_vbo_id;
|
|
int uniform_attr_type;
|
|
};
|
|
ShaderSSBOAttributeBinding cached_ssbo_attribute_bindings_[MTL_MAX_VERTEX_INPUT_ATTRIBUTES] = {};
|
|
|
|
/* Metal Shader Uniform data store.
|
|
* This blocks is used to store current shader push_constant
|
|
* data before it is submitted to the GPU. This is currently
|
|
* 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;
|
|
bool finalize_compute(const shader::ShaderCreateInfo *info);
|
|
void warm_cache(int limit) 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);
|
|
|
|
/* 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 set_compute_function_name(NSString *compute_function_name);
|
|
void shader_source_from_msl(NSString *input_vertex_source, NSString *input_fragment_source);
|
|
void shader_compute_source_from_msl(NSString *input_compute_source);
|
|
void set_interface(MTLShaderInterface *interface);
|
|
|
|
MTLRenderPipelineStateInstance *bake_current_pipeline_state(MTLContext *ctx,
|
|
MTLPrimitiveTopologyClass prim_type);
|
|
MTLRenderPipelineStateInstance *bake_pipeline_state(
|
|
MTLContext *ctx,
|
|
MTLPrimitiveTopologyClass prim_type,
|
|
const MTLRenderPipelineStateDescriptor &pipeline_descriptor);
|
|
|
|
bool bake_compute_pipeline_state(MTLContext *ctx);
|
|
const MTLComputePipelineStateInstance &get_compute_pipeline_state();
|
|
|
|
/* 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);
|
|
bool generate_msl_from_glsl_compute(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 specializations 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;
|
|
case GPU_COMP_MAX:
|
|
BLI_assert_unreachable();
|
|
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, "Unrecognized 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, "Unrecognized 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, "Unrecognized attribute type. Add types to switch as needed.");
|
|
return GPU_COMP_F32;
|
|
}
|
|
}
|
|
|
|
} // namespace blender::gpu
|