|
@@ -218,7 +218,7 @@ RDD::TextureID RenderingDeviceDriverMetal::texture_create(const TextureFormat &p
|
|
// desc.compressionType = MTLTextureCompressionTypeLossy;
|
|
// desc.compressionType = MTLTextureCompressionTypeLossy;
|
|
|
|
|
|
if (p_format.samples > TEXTURE_SAMPLES_1) {
|
|
if (p_format.samples > TEXTURE_SAMPLES_1) {
|
|
- SampleCount supported = (*metal_device_properties).find_nearest_supported_sample_count(p_format.samples);
|
|
|
|
|
|
+ SampleCount supported = (*device_properties).find_nearest_supported_sample_count(p_format.samples);
|
|
|
|
|
|
if (supported > SampleCount1) {
|
|
if (supported > SampleCount1) {
|
|
bool ok = p_format.texture_type == TEXTURE_TYPE_2D || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY;
|
|
bool ok = p_format.texture_type == TEXTURE_TYPE_2D || p_format.texture_type == TEXTURE_TYPE_2D_ARRAY;
|
|
@@ -277,7 +277,7 @@ RDD::TextureID RenderingDeviceDriverMetal::texture_create(const TextureFormat &p
|
|
// Usage.
|
|
// Usage.
|
|
|
|
|
|
MTLResourceOptions options = 0;
|
|
MTLResourceOptions options = 0;
|
|
- const bool supports_memoryless = (*metal_device_properties).features.highestFamily >= MTLGPUFamilyApple2 && (*metal_device_properties).features.highestFamily < MTLGPUFamilyMac1;
|
|
|
|
|
|
+ const bool supports_memoryless = (*device_properties).features.highestFamily >= MTLGPUFamilyApple2 && (*device_properties).features.highestFamily < MTLGPUFamilyMac1;
|
|
if (supports_memoryless && p_format.usage_bits & TEXTURE_USAGE_TRANSIENT_BIT) {
|
|
if (supports_memoryless && p_format.usage_bits & TEXTURE_USAGE_TRANSIENT_BIT) {
|
|
options = MTLResourceStorageModeMemoryless | MTLResourceHazardTrackingModeTracked;
|
|
options = MTLResourceStorageModeMemoryless | MTLResourceHazardTrackingModeTracked;
|
|
desc.storageMode = MTLStorageModeMemoryless;
|
|
desc.storageMode = MTLStorageModeMemoryless;
|
|
@@ -1058,7 +1058,7 @@ void RenderingDeviceDriverMetal::framebuffer_free(FramebufferID p_framebuffer) {
|
|
|
|
|
|
#pragma mark - Shader
|
|
#pragma mark - Shader
|
|
|
|
|
|
-const uint32_t SHADER_BINARY_VERSION = 3;
|
|
|
|
|
|
+const uint32_t SHADER_BINARY_VERSION = 4;
|
|
|
|
|
|
// region Serialization
|
|
// region Serialization
|
|
|
|
|
|
@@ -1503,6 +1503,9 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) UniformSetData {
|
|
p_reader.read(index);
|
|
p_reader.read(index);
|
|
p_reader.read(uniforms);
|
|
p_reader.read(uniforms);
|
|
}
|
|
}
|
|
|
|
+ UniformSetData() = default;
|
|
|
|
+ UniformSetData(uint32_t p_index) :
|
|
|
|
+ index(p_index) {}
|
|
};
|
|
};
|
|
|
|
|
|
struct PushConstantData {
|
|
struct PushConstantData {
|
|
@@ -1536,6 +1539,11 @@ struct PushConstantData {
|
|
};
|
|
};
|
|
|
|
|
|
struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
|
|
+ enum Flags : uint32_t {
|
|
|
|
+ NONE = 0,
|
|
|
|
+ NEEDS_VIEW_MASK_BUFFER = 1 << 0,
|
|
|
|
+ USES_ARGUMENT_BUFFERS = 1 << 1,
|
|
|
|
+ };
|
|
CharString shader_name;
|
|
CharString shader_name;
|
|
// The Metal language version specified when compiling SPIR-V to MSL.
|
|
// The Metal language version specified when compiling SPIR-V to MSL.
|
|
// Format is major * 10000 + minor * 100 + patch.
|
|
// Format is major * 10000 + minor * 100 + patch.
|
|
@@ -1543,8 +1551,7 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
uint32_t vertex_input_mask = UINT32_MAX;
|
|
uint32_t vertex_input_mask = UINT32_MAX;
|
|
uint32_t fragment_output_mask = UINT32_MAX;
|
|
uint32_t fragment_output_mask = UINT32_MAX;
|
|
uint32_t spirv_specialization_constants_ids_mask = UINT32_MAX;
|
|
uint32_t spirv_specialization_constants_ids_mask = UINT32_MAX;
|
|
- uint32_t is_compute = UINT32_MAX;
|
|
|
|
- uint32_t needs_view_mask_buffer = UINT32_MAX;
|
|
|
|
|
|
+ uint32_t flags = NONE;
|
|
ComputeSize compute_local_size;
|
|
ComputeSize compute_local_size;
|
|
PushConstantData push_constant;
|
|
PushConstantData push_constant;
|
|
LocalVector<ShaderStageData> stages;
|
|
LocalVector<ShaderStageData> stages;
|
|
@@ -1557,17 +1564,46 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
return MTLLanguageVersion((major << 0x10) + minor);
|
|
return MTLLanguageVersion((major << 0x10) + minor);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ bool is_compute() const {
|
|
|
|
+ return std::any_of(stages.begin(), stages.end(), [](ShaderStageData const &e) {
|
|
|
|
+ return e.stage == RD::ShaderStage::SHADER_STAGE_COMPUTE;
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool needs_view_mask_buffer() const {
|
|
|
|
+ return flags & NEEDS_VIEW_MASK_BUFFER;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void set_needs_view_mask_buffer(bool p_value) {
|
|
|
|
+ if (p_value) {
|
|
|
|
+ flags |= NEEDS_VIEW_MASK_BUFFER;
|
|
|
|
+ } else {
|
|
|
|
+ flags &= ~NEEDS_VIEW_MASK_BUFFER;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ bool uses_argument_buffers() const {
|
|
|
|
+ return flags & USES_ARGUMENT_BUFFERS;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void set_uses_argument_buffers(bool p_value) {
|
|
|
|
+ if (p_value) {
|
|
|
|
+ flags |= USES_ARGUMENT_BUFFERS;
|
|
|
|
+ } else {
|
|
|
|
+ flags &= ~USES_ARGUMENT_BUFFERS;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
size_t serialize_size() const {
|
|
size_t serialize_size() const {
|
|
size_t size = 0;
|
|
size_t size = 0;
|
|
size += sizeof(uint32_t) + shader_name.length(); // shader_name
|
|
size += sizeof(uint32_t) + shader_name.length(); // shader_name
|
|
- size += sizeof(uint32_t); // msl_version
|
|
|
|
- size += sizeof(uint32_t); // vertex_input_mask
|
|
|
|
- size += sizeof(uint32_t); // fragment_output_mask
|
|
|
|
- size += sizeof(uint32_t); // spirv_specialization_constants_ids_mask
|
|
|
|
- size += sizeof(uint32_t); // is_compute
|
|
|
|
- size += sizeof(uint32_t); // needs_view_mask_buffer
|
|
|
|
- size += compute_local_size.serialize_size(); // compute_local_size
|
|
|
|
- size += push_constant.serialize_size(); // push_constant
|
|
|
|
|
|
+ size += sizeof(msl_version);
|
|
|
|
+ size += sizeof(vertex_input_mask);
|
|
|
|
+ size += sizeof(fragment_output_mask);
|
|
|
|
+ size += sizeof(spirv_specialization_constants_ids_mask);
|
|
|
|
+ size += sizeof(flags);
|
|
|
|
+ size += compute_local_size.serialize_size();
|
|
|
|
+ size += push_constant.serialize_size();
|
|
size += sizeof(uint32_t); // stages.size()
|
|
size += sizeof(uint32_t); // stages.size()
|
|
for (ShaderStageData const &e : stages) {
|
|
for (ShaderStageData const &e : stages) {
|
|
size += e.serialize_size();
|
|
size += e.serialize_size();
|
|
@@ -1589,8 +1625,7 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
p_writer.write(vertex_input_mask);
|
|
p_writer.write(vertex_input_mask);
|
|
p_writer.write(fragment_output_mask);
|
|
p_writer.write(fragment_output_mask);
|
|
p_writer.write(spirv_specialization_constants_ids_mask);
|
|
p_writer.write(spirv_specialization_constants_ids_mask);
|
|
- p_writer.write(is_compute);
|
|
|
|
- p_writer.write(needs_view_mask_buffer);
|
|
|
|
|
|
+ p_writer.write(flags);
|
|
p_writer.write(compute_local_size);
|
|
p_writer.write(compute_local_size);
|
|
p_writer.write(push_constant);
|
|
p_writer.write(push_constant);
|
|
p_writer.write(VectorView(stages));
|
|
p_writer.write(VectorView(stages));
|
|
@@ -1604,8 +1639,7 @@ struct API_AVAILABLE(macos(11.0), ios(14.0)) ShaderBinaryData {
|
|
p_reader.read(vertex_input_mask);
|
|
p_reader.read(vertex_input_mask);
|
|
p_reader.read(fragment_output_mask);
|
|
p_reader.read(fragment_output_mask);
|
|
p_reader.read(spirv_specialization_constants_ids_mask);
|
|
p_reader.read(spirv_specialization_constants_ids_mask);
|
|
- p_reader.read(is_compute);
|
|
|
|
- p_reader.read(needs_view_mask_buffer);
|
|
|
|
|
|
+ p_reader.read(flags);
|
|
p_reader.read(compute_local_size);
|
|
p_reader.read(compute_local_size);
|
|
p_reader.read(push_constant);
|
|
p_reader.read(push_constant);
|
|
p_reader.read(stages);
|
|
p_reader.read(stages);
|
|
@@ -1952,14 +1986,13 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
|
|
.y = spirv_data.compute_local_size[1],
|
|
.y = spirv_data.compute_local_size[1],
|
|
.z = spirv_data.compute_local_size[2],
|
|
.z = spirv_data.compute_local_size[2],
|
|
};
|
|
};
|
|
- bin_data.is_compute = spirv_data.is_compute;
|
|
|
|
bin_data.push_constant.size = spirv_data.push_constant_size;
|
|
bin_data.push_constant.size = spirv_data.push_constant_size;
|
|
bin_data.push_constant.stages = (ShaderStageUsage)(uint8_t)spirv_data.push_constant_stages;
|
|
bin_data.push_constant.stages = (ShaderStageUsage)(uint8_t)spirv_data.push_constant_stages;
|
|
- bin_data.needs_view_mask_buffer = shader_meta.has_multiview ? 1 : 0;
|
|
|
|
|
|
+ bin_data.set_needs_view_mask_buffer(shader_meta.has_multiview);
|
|
|
|
|
|
for (uint32_t i = 0; i < spirv_data.uniform_sets.size(); i++) {
|
|
for (uint32_t i = 0; i < spirv_data.uniform_sets.size(); i++) {
|
|
const ::Vector<ShaderUniform> &spirv_set = spirv_data.uniform_sets[i];
|
|
const ::Vector<ShaderUniform> &spirv_set = spirv_data.uniform_sets[i];
|
|
- UniformSetData set{ .index = i };
|
|
|
|
|
|
+ UniformSetData set(i);
|
|
for (const ShaderUniform &spirv_uniform : spirv_set) {
|
|
for (const ShaderUniform &spirv_uniform : spirv_set) {
|
|
UniformData binding{};
|
|
UniformData binding{};
|
|
binding.type = spirv_uniform.type;
|
|
binding.type = spirv_uniform.type;
|
|
@@ -1999,10 +2032,25 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if TARGET_OS_IOS
|
|
#if TARGET_OS_IOS
|
|
- msl_options.ios_use_simdgroup_functions = (*metal_device_properties).features.simdPermute;
|
|
|
|
|
|
+ msl_options.ios_use_simdgroup_functions = (*device_properties).features.simdPermute;
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- msl_options.argument_buffers = true;
|
|
|
|
|
|
+ bool disable_argument_buffers = false;
|
|
|
|
+ if (String v = OS::get_singleton()->get_environment(U"GODOT_DISABLE_ARGUMENT_BUFFERS"); v == U"1") {
|
|
|
|
+ disable_argument_buffers = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (device_properties->features.argument_buffers_tier >= MTLArgumentBuffersTier2 && !disable_argument_buffers) {
|
|
|
|
+ msl_options.argument_buffers_tier = CompilerMSL::Options::ArgumentBuffersTier::Tier2;
|
|
|
|
+ msl_options.argument_buffers = true;
|
|
|
|
+ bin_data.set_uses_argument_buffers(true);
|
|
|
|
+ } else {
|
|
|
|
+ msl_options.argument_buffers_tier = CompilerMSL::Options::ArgumentBuffersTier::Tier1;
|
|
|
|
+ // Tier 1 argument buffers don't support writable textures, so we disable them completely.
|
|
|
|
+ msl_options.argument_buffers = false;
|
|
|
|
+ bin_data.set_uses_argument_buffers(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
msl_options.force_active_argument_buffer_resources = true; // Same as MoltenVK when using argument buffers.
|
|
msl_options.force_active_argument_buffer_resources = true; // Same as MoltenVK when using argument buffers.
|
|
// msl_options.pad_argument_buffer_resources = true; // Same as MoltenVK when using argument buffers.
|
|
// msl_options.pad_argument_buffer_resources = true; // Same as MoltenVK when using argument buffers.
|
|
msl_options.texture_buffer_native = true; // Enable texture buffer support.
|
|
msl_options.texture_buffer_native = true; // Enable texture buffer support.
|
|
@@ -2042,7 +2090,12 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
|
|
std::unordered_set<VariableID> active = compiler.get_active_interface_variables();
|
|
std::unordered_set<VariableID> active = compiler.get_active_interface_variables();
|
|
ShaderResources resources = compiler.get_shader_resources();
|
|
ShaderResources resources = compiler.get_shader_resources();
|
|
|
|
|
|
- std::string source = compiler.compile();
|
|
|
|
|
|
+ std::string source;
|
|
|
|
+ try {
|
|
|
|
+ source = compiler.compile();
|
|
|
|
+ } catch (CompilerError &e) {
|
|
|
|
+ ERR_FAIL_V_MSG(Result(), "Failed to compile stage " + String(SHADER_STAGE_NAMES[stage]) + ": " + e.what());
|
|
|
|
+ }
|
|
|
|
|
|
ERR_FAIL_COND_V_MSG(compiler.get_entry_points_and_stages().size() != 1, Result(), "Expected a single entry point and stage.");
|
|
ERR_FAIL_COND_V_MSG(compiler.get_entry_points_and_stages().size() != 1, Result(), "Expected a single entry point and stage.");
|
|
|
|
|
|
@@ -2088,8 +2141,8 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
|
|
return res;
|
|
return res;
|
|
};
|
|
};
|
|
|
|
|
|
- auto descriptor_bindings = [&compiler, &active, &uniform_sets, stage, &get_decoration](SmallVector<Resource> &resources, Writable writable) {
|
|
|
|
- for (Resource const &res : resources) {
|
|
|
|
|
|
+ auto descriptor_bindings = [&compiler, &active, &uniform_sets, stage, &get_decoration](SmallVector<Resource> &p_resources, Writable p_writable) {
|
|
|
|
+ for (Resource const &res : p_resources) {
|
|
uint32_t dset = get_decoration(res.id, spv::DecorationDescriptorSet);
|
|
uint32_t dset = get_decoration(res.id, spv::DecorationDescriptorSet);
|
|
uint32_t dbin = get_decoration(res.id, spv::DecorationBinding);
|
|
uint32_t dbin = get_decoration(res.id, spv::DecorationBinding);
|
|
UniformData *found = nullptr;
|
|
UniformData *found = nullptr;
|
|
@@ -2195,7 +2248,7 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
|
|
}
|
|
}
|
|
|
|
|
|
// Update writable.
|
|
// Update writable.
|
|
- if (writable == Writable::Maybe) {
|
|
|
|
|
|
+ if (p_writable == Writable::Maybe) {
|
|
if (basetype == BT::Struct) {
|
|
if (basetype == BT::Struct) {
|
|
Bitset flags = compiler.get_buffer_block_flags(res.id);
|
|
Bitset flags = compiler.get_buffer_block_flags(res.id);
|
|
if (!flags.get(spv::DecorationNonWritable)) {
|
|
if (!flags.get(spv::DecorationNonWritable)) {
|
|
@@ -2384,6 +2437,11 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
|
|
ERR_FAIL_V_MSG(ShaderID(), "Unexpected end of buffer");
|
|
ERR_FAIL_V_MSG(ShaderID(), "Unexpected end of buffer");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // We need to regenerate the shader if the cache is moved to an incompatible device.
|
|
|
|
+ ERR_FAIL_COND_V_MSG(device_properties->features.argument_buffers_tier < MTLArgumentBuffersTier2 && binary_data.uses_argument_buffers(),
|
|
|
|
+ ShaderID(),
|
|
|
|
+ "Shader was generated with argument buffers, but device has limited support");
|
|
|
|
+
|
|
MTLCompileOptions *options = [MTLCompileOptions new];
|
|
MTLCompileOptions *options = [MTLCompileOptions new];
|
|
options.languageVersion = binary_data.get_msl_version();
|
|
options.languageVersion = binary_data.get_msl_version();
|
|
HashMap<ShaderStage, MDLibrary *> libraries;
|
|
HashMap<ShaderStage, MDLibrary *> libraries;
|
|
@@ -2505,8 +2563,12 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
|
|
}
|
|
}
|
|
|
|
|
|
MDShader *shader = nullptr;
|
|
MDShader *shader = nullptr;
|
|
- if (binary_data.is_compute) {
|
|
|
|
- MDComputeShader *cs = new MDComputeShader(binary_data.shader_name, uniform_sets, libraries[ShaderStage::SHADER_STAGE_COMPUTE]);
|
|
|
|
|
|
+ if (binary_data.is_compute()) {
|
|
|
|
+ MDComputeShader *cs = new MDComputeShader(
|
|
|
|
+ binary_data.shader_name,
|
|
|
|
+ uniform_sets,
|
|
|
|
+ binary_data.uses_argument_buffers(),
|
|
|
|
+ libraries[ShaderStage::SHADER_STAGE_COMPUTE]);
|
|
|
|
|
|
uint32_t *binding = binary_data.push_constant.msl_binding.getptr(SHADER_STAGE_COMPUTE);
|
|
uint32_t *binding = binary_data.push_constant.msl_binding.getptr(SHADER_STAGE_COMPUTE);
|
|
if (binding) {
|
|
if (binding) {
|
|
@@ -2520,7 +2582,13 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
|
|
#endif
|
|
#endif
|
|
shader = cs;
|
|
shader = cs;
|
|
} else {
|
|
} else {
|
|
- MDRenderShader *rs = new MDRenderShader(binary_data.shader_name, (bool)binary_data.needs_view_mask_buffer, uniform_sets, libraries[ShaderStage::SHADER_STAGE_VERTEX], libraries[ShaderStage::SHADER_STAGE_FRAGMENT]);
|
|
|
|
|
|
+ MDRenderShader *rs = new MDRenderShader(
|
|
|
|
+ binary_data.shader_name,
|
|
|
|
+ uniform_sets,
|
|
|
|
+ binary_data.needs_view_mask_buffer(),
|
|
|
|
+ binary_data.uses_argument_buffers(),
|
|
|
|
+ libraries[ShaderStage::SHADER_STAGE_VERTEX],
|
|
|
|
+ libraries[ShaderStage::SHADER_STAGE_FRAGMENT]);
|
|
|
|
|
|
uint32_t *vert_binding = binary_data.push_constant.msl_binding.getptr(SHADER_STAGE_VERTEX);
|
|
uint32_t *vert_binding = binary_data.push_constant.msl_binding.getptr(SHADER_STAGE_VERTEX);
|
|
if (vert_binding) {
|
|
if (vert_binding) {
|
|
@@ -2547,7 +2615,7 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
|
|
|
|
|
|
r_shader_desc.vertex_input_mask = binary_data.vertex_input_mask;
|
|
r_shader_desc.vertex_input_mask = binary_data.vertex_input_mask;
|
|
r_shader_desc.fragment_output_mask = binary_data.fragment_output_mask;
|
|
r_shader_desc.fragment_output_mask = binary_data.fragment_output_mask;
|
|
- r_shader_desc.is_compute = binary_data.is_compute;
|
|
|
|
|
|
+ r_shader_desc.is_compute = binary_data.is_compute();
|
|
r_shader_desc.compute_local_size[0] = binary_data.compute_local_size.x;
|
|
r_shader_desc.compute_local_size[0] = binary_data.compute_local_size.x;
|
|
r_shader_desc.compute_local_size[1] = binary_data.compute_local_size.y;
|
|
r_shader_desc.compute_local_size[1] = binary_data.compute_local_size.y;
|
|
r_shader_desc.compute_local_size[2] = binary_data.compute_local_size.z;
|
|
r_shader_desc.compute_local_size[2] = binary_data.compute_local_size.z;
|
|
@@ -2572,7 +2640,7 @@ void RenderingDeviceDriverMetal::shader_destroy_modules(ShaderID p_shader) {
|
|
RDD::UniformSetID RenderingDeviceDriverMetal::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index, int p_linear_pool_index) {
|
|
RDD::UniformSetID RenderingDeviceDriverMetal::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index, int p_linear_pool_index) {
|
|
//p_linear_pool_index = -1; // TODO:? Linear pools not implemented or not supported by API backend.
|
|
//p_linear_pool_index = -1; // TODO:? Linear pools not implemented or not supported by API backend.
|
|
|
|
|
|
- MDUniformSet *set = new MDUniformSet();
|
|
|
|
|
|
+ MDUniformSet *set = memnew(MDUniformSet);
|
|
Vector<BoundUniform> bound_uniforms;
|
|
Vector<BoundUniform> bound_uniforms;
|
|
bound_uniforms.resize(p_uniforms.size());
|
|
bound_uniforms.resize(p_uniforms.size());
|
|
for (uint32_t i = 0; i < p_uniforms.size(); i += 1) {
|
|
for (uint32_t i = 0; i < p_uniforms.size(); i += 1) {
|
|
@@ -2586,7 +2654,7 @@ RDD::UniformSetID RenderingDeviceDriverMetal::uniform_set_create(VectorView<Boun
|
|
|
|
|
|
void RenderingDeviceDriverMetal::uniform_set_free(UniformSetID p_uniform_set) {
|
|
void RenderingDeviceDriverMetal::uniform_set_free(UniformSetID p_uniform_set) {
|
|
MDUniformSet *obj = (MDUniformSet *)p_uniform_set.id;
|
|
MDUniformSet *obj = (MDUniformSet *)p_uniform_set.id;
|
|
- delete obj;
|
|
|
|
|
|
+ memdelete(obj);
|
|
}
|
|
}
|
|
|
|
|
|
void RenderingDeviceDriverMetal::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
|
|
void RenderingDeviceDriverMetal::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
|
|
@@ -2800,7 +2868,7 @@ void RenderingDeviceDriverMetal::command_clear_color_texture(CommandBufferID p_c
|
|
uint32_t layerCnt = p_subresources.layer_count;
|
|
uint32_t layerCnt = p_subresources.layer_count;
|
|
uint32_t layerEnd = layerStart + layerCnt;
|
|
uint32_t layerEnd = layerStart + layerCnt;
|
|
|
|
|
|
- MetalFeatures const &features = (*metal_device_properties).features;
|
|
|
|
|
|
+ MetalFeatures const &features = (*device_properties).features;
|
|
|
|
|
|
// Iterate across mipmap levels and layers, and perform and empty render to clear each.
|
|
// Iterate across mipmap levels and layers, and perform and empty render to clear each.
|
|
for (uint32_t mipLvl = mipLvlStart; mipLvl < mipLvlEnd; mipLvl++) {
|
|
for (uint32_t mipLvl = mipLvlStart; mipLvl < mipLvlEnd; mipLvl++) {
|
|
@@ -3057,7 +3125,7 @@ RDD::RenderPassID RenderingDeviceDriverMetal::render_pass_create(VectorView<Atta
|
|
MTLPixelFormat format = pf.getMTLPixelFormat(a.format);
|
|
MTLPixelFormat format = pf.getMTLPixelFormat(a.format);
|
|
mda.format = format;
|
|
mda.format = format;
|
|
if (a.samples > TEXTURE_SAMPLES_1) {
|
|
if (a.samples > TEXTURE_SAMPLES_1) {
|
|
- mda.samples = (*metal_device_properties).find_nearest_supported_sample_count(a.samples);
|
|
|
|
|
|
+ mda.samples = (*device_properties).find_nearest_supported_sample_count(a.samples);
|
|
}
|
|
}
|
|
mda.loadAction = LOAD_ACTIONS[a.load_op];
|
|
mda.loadAction = LOAD_ACTIONS[a.load_op];
|
|
mda.storeAction = STORE_ACTIONS[a.store_op];
|
|
mda.storeAction = STORE_ACTIONS[a.store_op];
|
|
@@ -3436,7 +3504,7 @@ RDD::PipelineID RenderingDeviceDriverMetal::render_pipeline_create(
|
|
}
|
|
}
|
|
|
|
|
|
if (p_multisample_state.sample_count > TEXTURE_SAMPLES_1) {
|
|
if (p_multisample_state.sample_count > TEXTURE_SAMPLES_1) {
|
|
- pipeline->sample_count = (*metal_device_properties).find_nearest_supported_sample_count(p_multisample_state.sample_count);
|
|
|
|
|
|
+ pipeline->sample_count = (*device_properties).find_nearest_supported_sample_count(p_multisample_state.sample_count);
|
|
}
|
|
}
|
|
desc.rasterSampleCount = static_cast<NSUInteger>(pipeline->sample_count);
|
|
desc.rasterSampleCount = static_cast<NSUInteger>(pipeline->sample_count);
|
|
desc.alphaToCoverageEnabled = p_multisample_state.enable_alpha_to_coverage;
|
|
desc.alphaToCoverageEnabled = p_multisample_state.enable_alpha_to_coverage;
|
|
@@ -3815,7 +3883,7 @@ uint64_t RenderingDeviceDriverMetal::get_lazily_memory_used() {
|
|
}
|
|
}
|
|
|
|
|
|
uint64_t RenderingDeviceDriverMetal::limit_get(Limit p_limit) {
|
|
uint64_t RenderingDeviceDriverMetal::limit_get(Limit p_limit) {
|
|
- MetalDeviceProperties const &props = (*metal_device_properties);
|
|
|
|
|
|
+ MetalDeviceProperties const &props = (*device_properties);
|
|
MetalLimits const &limits = props.limits;
|
|
MetalLimits const &limits = props.limits;
|
|
|
|
|
|
#if defined(DEV_ENABLED)
|
|
#if defined(DEV_ENABLED)
|
|
@@ -3911,11 +3979,13 @@ uint64_t RenderingDeviceDriverMetal::limit_get(Limit p_limit) {
|
|
case LIMIT_SUBGROUP_MAX_SIZE:
|
|
case LIMIT_SUBGROUP_MAX_SIZE:
|
|
return limits.maxSubgroupSize;
|
|
return limits.maxSubgroupSize;
|
|
case LIMIT_SUBGROUP_IN_SHADERS:
|
|
case LIMIT_SUBGROUP_IN_SHADERS:
|
|
- return (int64_t)limits.subgroupSupportedShaderStages;
|
|
|
|
|
|
+ return (uint64_t)limits.subgroupSupportedShaderStages;
|
|
case LIMIT_SUBGROUP_OPERATIONS:
|
|
case LIMIT_SUBGROUP_OPERATIONS:
|
|
- return (int64_t)limits.subgroupSupportedOperations;
|
|
|
|
|
|
+ return (uint64_t)limits.subgroupSupportedOperations;
|
|
UNKNOWN(LIMIT_VRS_TEXEL_WIDTH);
|
|
UNKNOWN(LIMIT_VRS_TEXEL_WIDTH);
|
|
UNKNOWN(LIMIT_VRS_TEXEL_HEIGHT);
|
|
UNKNOWN(LIMIT_VRS_TEXEL_HEIGHT);
|
|
|
|
+ UNKNOWN(LIMIT_VRS_MAX_FRAGMENT_WIDTH);
|
|
|
|
+ UNKNOWN(LIMIT_VRS_MAX_FRAGMENT_HEIGHT);
|
|
default:
|
|
default:
|
|
ERR_FAIL_V(0);
|
|
ERR_FAIL_V(0);
|
|
}
|
|
}
|
|
@@ -4042,11 +4112,11 @@ Error RenderingDeviceDriverMetal::initialize(uint32_t p_device_index, uint32_t p
|
|
// Set the pipeline cache ID based on the Metal version.
|
|
// Set the pipeline cache ID based on the Metal version.
|
|
pipeline_cache_id = "metal-driver-" + get_api_version();
|
|
pipeline_cache_id = "metal-driver-" + get_api_version();
|
|
|
|
|
|
- metal_device_properties = memnew(MetalDeviceProperties(device));
|
|
|
|
|
|
+ device_properties = memnew(MetalDeviceProperties(device));
|
|
pixel_formats = memnew(PixelFormats(device));
|
|
pixel_formats = memnew(PixelFormats(device));
|
|
- if (metal_device_properties->features.layeredRendering) {
|
|
|
|
|
|
+ if (device_properties->features.layeredRendering) {
|
|
multiview_capabilities.is_supported = true;
|
|
multiview_capabilities.is_supported = true;
|
|
- multiview_capabilities.max_view_count = metal_device_properties->limits.maxViewports;
|
|
|
|
|
|
+ multiview_capabilities.max_view_count = device_properties->limits.maxViewports;
|
|
// NOTE: I'm not sure what the limit is as I don't see it referenced anywhere
|
|
// NOTE: I'm not sure what the limit is as I don't see it referenced anywhere
|
|
multiview_capabilities.max_instance_count = UINT32_MAX;
|
|
multiview_capabilities.max_instance_count = UINT32_MAX;
|
|
|
|
|
|
@@ -4057,11 +4127,10 @@ Error RenderingDeviceDriverMetal::initialize(uint32_t p_device_index, uint32_t p
|
|
print_verbose("- Metal multiview not supported");
|
|
print_verbose("- Metal multiview not supported");
|
|
}
|
|
}
|
|
|
|
|
|
- // Check required features and abort if any of them is missing.
|
|
|
|
- if (!metal_device_properties->features.imageCubeArray) {
|
|
|
|
- // NOTE: Apple A11 (Apple4) GPUs support image cube arrays, which are devices from 2017 and newer.
|
|
|
|
- String error_string = vformat("Your Apple GPU does not support the following features which are required to use Metal-based renderers in Godot:\n\n");
|
|
|
|
- if (!metal_device_properties->features.imageCubeArray) {
|
|
|
|
|
|
+ // The Metal renderer requires Apple4 family. This is 2017 era A11 chips and newer.
|
|
|
|
+ if (device_properties->features.highestFamily < MTLGPUFamilyApple4) {
|
|
|
|
+ String error_string = vformat("Your Apple GPU does not support the following features, which are required to use Metal-based renderers in Godot:\n\n");
|
|
|
|
+ if (!device_properties->features.imageCubeArray) {
|
|
error_string += "- No support for image cube arrays.\n";
|
|
error_string += "- No support for image cube arrays.\n";
|
|
}
|
|
}
|
|
|
|
|