Apple: Use image atomic operations on supported Apple hardware

Co-authored-by: A Thousand Ships <96648715+AThousandShips@users.noreply.github.com>
This commit is contained in:
Stuart Carnie
2025-06-27 09:59:21 +10:00
parent 9b22b41531
commit 5230f6c60c
32 changed files with 5354 additions and 719 deletions

View File

@ -417,6 +417,7 @@ void Fog::VolumetricFog::init(const Vector3i &fog_size, RID p_sky_shader) {
width = fog_size.x;
height = fog_size.y;
depth = fog_size.z;
atomic_type = RD::get_singleton()->has_feature(RD::SUPPORTS_IMAGE_ATOMIC_32_BIT) ? RD::UNIFORM_TYPE_IMAGE : RD::UNIFORM_TYPE_STORAGE_BUFFER;
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
@ -440,29 +441,29 @@ void Fog::VolumetricFog::init(const Vector3i &fog_size, RID p_sky_shader) {
fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(fog_map, "Fog map");
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
Vector<uint8_t> dm;
dm.resize_initialized(fog_size.x * fog_size.y * fog_size.z * 4);
if (atomic_type == RD::UNIFORM_TYPE_STORAGE_BUFFER) {
Vector<uint8_t> dm;
dm.resize_initialized(fog_size.x * fog_size.y * fog_size.z * 4);
density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(density_map, "Fog density map");
light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(light_map, "Fog light map");
emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map");
#else
tf.format = RD::DATA_FORMAT_R32_UINT;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(density_map, "Fog density map");
RD::get_singleton()->texture_clear(density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
light_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(light_map, "Fog light map");
RD::get_singleton()->texture_clear(light_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map");
RD::get_singleton()->texture_clear(emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
#endif
density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(density_map, "Fog density map");
light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(light_map, "Fog light map");
emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map");
} else {
tf.format = RD::DATA_FORMAT_R32_UINT;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_ATOMIC_BIT;
density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(density_map, "Fog density map");
RD::get_singleton()->texture_clear(density_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
light_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(light_map, "Fog light map");
RD::get_singleton()->texture_clear(light_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(emissive_map, "Fog emissive map");
RD::get_singleton()->texture_clear(emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
}
Vector<RD::Uniform> uniforms;
{
@ -579,11 +580,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 1;
u.append_id(fog->emissive_map);
uniforms.push_back(u);
@ -599,11 +596,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 3;
u.append_id(fog->density_map);
uniforms.push_back(u);
@ -611,11 +604,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 4;
u.append_id(fog->light_map);
uniforms.push_back(u);
@ -918,22 +907,14 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
}
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 16;
u.append_id(fog->density_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 17;
u.append_id(fog->light_map);
uniforms.push_back(u);
@ -941,11 +922,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
#endif
u.uniform_type = fog->atomic_type;
u.binding = 18;
u.append_id(fog->emissive_map);
uniforms.push_back(u);

View File

@ -316,6 +316,9 @@ public:
int last_shadow_filter = -1;
// If the device doesn't support image atomics, use storage buffers instead.
RD::UniformType atomic_type = RD::UNIFORM_TYPE_IMAGE;
virtual void configure(RenderSceneBuffersRD *p_render_buffers) override {}
virtual void free_data() override {}

View File

@ -234,11 +234,13 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
}
#if (defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED))
if (RD::get_singleton()->get_device_capabilities().device_family == RDD::DEVICE_VULKAN) {
RenderingDevice *rd = RD::get_singleton();
if (rd->get_device_capabilities().device_family == RDD::DEVICE_VULKAN) {
builder.append("#define MOLTENVK_USED\n");
}
// Image atomics are supported on Metal 3.1 but no support in MoltenVK or SPIRV-Cross yet.
builder.append("#define NO_IMAGE_ATOMICS\n");
if (!rd->has_feature(RD::SUPPORTS_IMAGE_ATOMIC_32_BIT)) {
builder.append("#define NO_IMAGE_ATOMICS\n");
}
#endif
builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n");

View File

@ -2,6 +2,8 @@
#version 450
#pragma use_vulkan_memory_model
#VERSION_DEFINES
layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;

View File

@ -2,6 +2,8 @@
#version 450
#pragma use_vulkan_memory_model
#VERSION_DEFINES
#ifdef MODE_DENSITY

View File

@ -7979,6 +7979,7 @@ void RenderingDevice::_bind_methods() {
BIND_ENUM_CONSTANT(SUPPORTS_METALFX_SPATIAL);
BIND_ENUM_CONSTANT(SUPPORTS_METALFX_TEMPORAL);
BIND_ENUM_CONSTANT(SUPPORTS_BUFFER_DEVICE_ADDRESS);
BIND_ENUM_CONSTANT(SUPPORTS_IMAGE_ATOMIC_32_BIT);
BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS);
BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS);

View File

@ -952,6 +952,7 @@ public:
// If not supported, a fragment shader with only side effects (i.e., writes to buffers, but doesn't output to attachments), may be optimized down to no-op by the GPU driver.
SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS,
SUPPORTS_BUFFER_DEVICE_ADDRESS,
SUPPORTS_IMAGE_ATOMIC_32_BIT,
};
enum SubgroupOperations {