Skip to content

Commit

Permalink
Implement support for fragment density maps.
Browse files Browse the repository at this point in the history
Co-Authored-By: Bastiaan Olij <mux213@gmail.com>
  • Loading branch information
DarioSamo and BastiaanOlij committed Dec 5, 2024
1 parent 1f47e4c commit aa73990
Show file tree
Hide file tree
Showing 21 changed files with 756 additions and 345 deletions.
79 changes: 37 additions & 42 deletions drivers/d3d12/rendering_device_driver_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1203,7 +1203,7 @@ RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p
if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT)) {
if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && (p_format.usage_bits & TEXTURE_USAGE_VRS_FRAGMENT_SHADING_RATE_BIT)) {
// For VRS images we can't use the typeless format.
resource_desc.Format = DXGI_FORMAT_R8_UINT;
}
Expand Down Expand Up @@ -1808,8 +1808,11 @@ static D3D12_BARRIER_ACCESS _rd_texture_layout_access_mask(RDD::TextureLayout p_
return D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;
case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:
return D3D12_BARRIER_ACCESS_RESOLVE_DEST;
case RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL:
case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:
return D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE;
case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:
DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");
return D3D12_BARRIER_ACCESS_NO_ACCESS;
default:
return D3D12_BARRIER_ACCESS_NO_ACCESS;
}
Expand Down Expand Up @@ -1928,7 +1931,7 @@ static void _rd_stages_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, D3D12
r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING;
}

if (p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) {
if (p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT)) {
r_sync |= D3D12_BARRIER_SYNC_PIXEL_SHADING;
}

Expand Down Expand Up @@ -2023,8 +2026,11 @@ static D3D12_BARRIER_LAYOUT _rd_texture_layout_to_d3d12_barrier_layout(RDD::Text
return D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE;
case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:
return D3D12_BARRIER_LAYOUT_RESOLVE_DEST;
case RDD::TEXTURE_LAYOUT_VRS_ATTACHMENT_OPTIMAL:
case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:
return D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE;
case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:
DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");
return D3D12_BARRIER_LAYOUT_UNDEFINED;
default:
DEV_ASSERT(false && "Unknown texture layout.");
return D3D12_BARRIER_LAYOUT_UNDEFINED;
Expand Down Expand Up @@ -2412,7 +2418,7 @@ RDD::SwapChainID RenderingDeviceDriverD3D12::swap_chain_create(RenderingContextD
color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
subpass.color_references.push_back(color_ref);

RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1);
RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1, AttachmentReference());
ERR_FAIL_COND_V(!render_pass, SwapChainID());

// Create the empty swap chain until it is resized.
Expand Down Expand Up @@ -2772,8 +2778,8 @@ RDD::FramebufferID RenderingDeviceDriverD3D12::_framebuffer_create(RenderPassID

uint32_t vrs_index = UINT32_MAX;
for (const Subpass &E : pass_info->subpasses) {
if (E.vrs_reference.attachment != AttachmentReference::UNUSED) {
vrs_index = E.vrs_reference.attachment;
if (E.fragment_shading_rate_reference.attachment != AttachmentReference::UNUSED) {
vrs_index = E.fragment_shading_rate_reference.attachment;
}
}

Expand Down Expand Up @@ -4922,7 +4928,9 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::pipeline_cache_serialize() {

// ----- SUBPASS -----

RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) {
RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) {
ERR_FAIL_COND_V_MSG(p_fragment_density_map_attachment.attachment != AttachmentReference::UNUSED, RenderPassID(), "Fragment density maps are not supported in D3D12.");

// Pre-bookkeep.
RenderPassInfo *pass_info = VersatileResource::allocate<RenderPassInfo>(resources_allocator);

Expand Down Expand Up @@ -5023,7 +5031,7 @@ void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd
}
}

if (fb_info->vrs_attachment && vrs_capabilities.ss_image_supported) {
if (fb_info->vrs_attachment && fsr_capabilities.attachment_supported) {
ComPtr<ID3D12GraphicsCommandList5> cmd_list_5;
cmd_buf_info->cmd_list->QueryInterface(cmd_list_5.GetAddressOf());
if (cmd_list_5) {
Expand Down Expand Up @@ -5143,7 +5151,7 @@ void RenderingDeviceDriverD3D12::command_end_render_pass(CommandBufferID p_cmd_b
const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;

if (vrs_capabilities.ss_image_supported) {
if (fsr_capabilities.attachment_supported) {
ComPtr<ID3D12GraphicsCommandList5> cmd_list_5;
cmd_buf_info->cmd_list->QueryInterface(cmd_list_5.GetAddressOf());
if (cmd_list_5) {
Expand Down Expand Up @@ -6173,12 +6181,6 @@ uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) {
return subgroup_capabilities.supported_stages_flags_rd();
case LIMIT_SUBGROUP_OPERATIONS:
return subgroup_capabilities.supported_operations_flags_rd();
case LIMIT_VRS_TEXEL_WIDTH:
case LIMIT_VRS_TEXEL_HEIGHT:
return vrs_capabilities.ss_image_tile_size;
case LIMIT_VRS_MAX_FRAGMENT_WIDTH:
case LIMIT_VRS_MAX_FRAGMENT_HEIGHT:
return vrs_capabilities.ss_max_fragment_size;
default: {
#ifdef DEV_ENABLED
WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");
Expand Down Expand Up @@ -6213,12 +6215,8 @@ uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) {

bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) {
switch (p_feature) {
case SUPPORTS_MULTIVIEW:
return multiview_capabilities.is_supported && multiview_capabilities.max_view_count > 1;
case SUPPORTS_FSR_HALF_FLOAT:
return shader_capabilities.native_16bit_ops && storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported;
case SUPPORTS_ATTACHMENT_VRS:
return vrs_capabilities.ss_image_supported;
case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS:
return true;
default:
Expand All @@ -6230,6 +6228,14 @@ const RDD::MultiviewCapabilities &RenderingDeviceDriverD3D12::get_multiview_capa
return multiview_capabilities;
}

const RDD::FragmentShadingRateCapabilities &RenderingDeviceDriverD3D12::get_fragment_shading_rate_capabilities() {
return fsr_capabilities;
}

const RDD::FragmentDensityMapCapabilities &RenderingDeviceDriverD3D12::get_fragment_density_map_capabilities() {
return fdm_capabilities;
}

String RenderingDeviceDriverD3D12::get_api_name() const {
return "D3D12";
}
Expand Down Expand Up @@ -6391,12 +6397,6 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() {
device_capabilities.version_minor = feature_level % 10;

// Assume not supported until proven otherwise.
vrs_capabilities.draw_call_supported = false;
vrs_capabilities.primitive_supported = false;
vrs_capabilities.primitive_in_multiviewport = false;
vrs_capabilities.ss_image_supported = false;
vrs_capabilities.ss_image_tile_size = 1;
vrs_capabilities.additional_rates_supported = false;
multiview_capabilities.is_supported = false;
multiview_capabilities.geometry_shader_is_supported = false;
multiview_capabilities.tessellation_shader_is_supported = false;
Expand Down Expand Up @@ -6487,14 +6487,12 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() {
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6));
if (SUCCEEDED(res)) {
if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1) {
vrs_capabilities.draw_call_supported = true;
fsr_capabilities.pipeline_supported = true;
if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2) {
vrs_capabilities.primitive_supported = true;
vrs_capabilities.primitive_in_multiviewport = options6.PerPrimitiveShadingRateSupportedWithViewportIndexing;
vrs_capabilities.ss_image_supported = true;
vrs_capabilities.ss_image_tile_size = options6.ShadingRateImageTileSize;
vrs_capabilities.ss_max_fragment_size = 8; // TODO figure out if this is supplied and/or needed
vrs_capabilities.additional_rates_supported = options6.AdditionalShadingRatesSupported;
fsr_capabilities.primitive_supported = true;
fsr_capabilities.attachment_supported = true;
fsr_capabilities.min_texel_size = Size2i(options6.ShadingRateImageTileSize, options6.ShadingRateImageTileSize);
fsr_capabilities.max_texel_size = Size2i(8, 8);
}
}
}
Expand All @@ -6506,19 +6504,16 @@ Error RenderingDeviceDriverD3D12::_check_capabilities() {
barrier_capabilities.enhanced_barriers_supported = options12.EnhancedBarriersSupported;
}

if (vrs_capabilities.draw_call_supported || vrs_capabilities.primitive_supported || vrs_capabilities.ss_image_supported) {
if (fsr_capabilities.pipeline_supported || fsr_capabilities.primitive_supported || fsr_capabilities.attachment_supported) {
print_verbose("- D3D12 Variable Rate Shading supported:");
if (vrs_capabilities.draw_call_supported) {
if (fsr_capabilities.pipeline_supported) {
print_verbose(" Draw call");
}
if (vrs_capabilities.primitive_supported) {
print_verbose(String(" Per-primitive (multi-viewport: ") + (vrs_capabilities.primitive_in_multiviewport ? "yes" : "no") + ")");
}
if (vrs_capabilities.ss_image_supported) {
print_verbose(String(" Screen-space image (tile size: ") + itos(vrs_capabilities.ss_image_tile_size) + ")");
if (fsr_capabilities.primitive_supported) {
print_verbose(" Primitive");
}
if (vrs_capabilities.additional_rates_supported) {
print_verbose(String(" Additional rates: ") + (vrs_capabilities.additional_rates_supported ? "yes" : "no"));
if (fsr_capabilities.attachment_supported) {
print_verbose(String(" Screen-space image (tile size: ") + itos(fsr_capabilities.min_texel_size.x) + ")");
}
} else {
print_verbose("- D3D12 Variable Rate Shading not supported");
Expand Down
17 changes: 5 additions & 12 deletions drivers/d3d12/rendering_device_driver_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,6 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
uint32_t supported_operations_flags_rd() const;
};

struct VRSCapabilities {
bool draw_call_supported = false; // We can specify our fragment rate on a draw call level.
bool primitive_supported = false; // We can specify our fragment rate on each drawcall.
bool primitive_in_multiviewport = false;
bool ss_image_supported = false; // We can provide a density map attachment on our framebuffer.
uint32_t ss_image_tile_size = 0;
uint32_t ss_max_fragment_size = 0;
bool additional_rates_supported = false;
};

struct ShaderCapabilities {
D3D_SHADER_MODEL shader_model = (D3D_SHADER_MODEL)0;
bool native_16bit_ops = false;
Expand Down Expand Up @@ -157,7 +147,8 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
uint32_t feature_level = 0; // Major * 10 + minor.
SubgroupCapabilities subgroup_capabilities;
RDD::MultiviewCapabilities multiview_capabilities;
VRSCapabilities vrs_capabilities;
FragmentShadingRateCapabilities fsr_capabilities;
FragmentDensityMapCapabilities fdm_capabilities;
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
FormatCapabilities format_capabilities;
Expand Down Expand Up @@ -825,7 +816,7 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
};

public:
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) override final;
virtual void render_pass_free(RenderPassID p_render_pass) override final;

// ----- COMMANDS -----
Expand Down Expand Up @@ -990,6 +981,8 @@ class RenderingDeviceDriverD3D12 : public RenderingDeviceDriver {
virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
virtual bool has_feature(Features p_feature) override final;
virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
virtual const FragmentShadingRateCapabilities &get_fragment_shading_rate_capabilities() override final;
virtual const FragmentDensityMapCapabilities &get_fragment_density_map_capabilities() override final;
virtual String get_api_name() const override final;
virtual String get_api_version() const override final;
virtual String get_pipeline_cache_uuid() const override final;
Expand Down
6 changes: 5 additions & 1 deletion drivers/metal/rendering_device_driver_metal.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public

RDD::Capabilities capabilities;
RDD::MultiviewCapabilities multiview_capabilities;
RDD::FragmentShadingRateCapabilities fsr_capabilities;
RDD::FragmentDensityMapCapabilities fdm_capabilities;

id<MTLBinaryArchive> archive = nil;
uint32_t archive_count = 0;
Expand Down Expand Up @@ -315,7 +317,7 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public

// ----- SUBPASS -----

virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) override final;
virtual RenderPassID render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) override final;
virtual void render_pass_free(RenderPassID p_render_pass) override final;

// ----- COMMANDS -----
Expand Down Expand Up @@ -417,6 +419,8 @@ class API_AVAILABLE(macos(11.0), ios(14.0)) RenderingDeviceDriverMetal : public
virtual uint64_t api_trait_get(ApiTrait p_trait) override final;
virtual bool has_feature(Features p_feature) override final;
virtual const MultiviewCapabilities &get_multiview_capabilities() override final;
virtual const FragmentShadingRateCapabilities &get_fragment_shading_rate_capabilities() override final;
virtual const FragmentDensityMapCapabilities &get_fragment_density_map_capabilities() override final;
virtual String get_api_name() const override final { return "Metal"; }
virtual String get_api_version() const override final;
virtual String get_pipeline_cache_uuid() const override final;
Expand Down
23 changes: 10 additions & 13 deletions drivers/metal/rendering_device_driver_metal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ static const API_AVAILABLE(macos(11.0), ios(14.0)) MTLSamplerBorderColor SAMPLER
color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
subpass.color_references.push_back(color_ref);

RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1);
RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1, RDD::AttachmentReference());
ERR_FAIL_COND_V(!render_pass, SwapChainID());

// Create the empty swap chain until it is resized.
Expand Down Expand Up @@ -3006,7 +3006,7 @@ bool isArrayTexture(MTLTextureType p_type) {

// ----- SUBPASS -----

RDD::RenderPassID RenderingDeviceDriverMetal::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count) {
RDD::RenderPassID RenderingDeviceDriverMetal::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) {
PixelFormats &pf = *pixel_formats;

size_t subpass_count = p_subpasses.size();
Expand Down Expand Up @@ -3886,8 +3886,6 @@ bool isArrayTexture(MTLTextureType p_type) {
return (int64_t)limits.subgroupSupportedShaderStages;
case LIMIT_SUBGROUP_OPERATIONS:
return (int64_t)limits.subgroupSupportedOperations;
UNKNOWN(LIMIT_VRS_TEXEL_WIDTH);
UNKNOWN(LIMIT_VRS_TEXEL_HEIGHT);
default:
ERR_FAIL_V(0);
}
Expand All @@ -3906,17 +3904,8 @@ bool isArrayTexture(MTLTextureType p_type) {

bool RenderingDeviceDriverMetal::has_feature(Features p_feature) {
switch (p_feature) {
case SUPPORTS_MULTIVIEW:
return multiview_capabilities.is_supported;
case SUPPORTS_FSR_HALF_FLOAT:
return true;
case SUPPORTS_ATTACHMENT_VRS:
// TODO(sgc): Maybe supported via https://developer.apple.com/documentation/metal/render_passes/rendering_at_different_rasterization_rates?language=objc
// See also:
//
// * https://forum.beyond3d.com/threads/variable-rate-shading-vs-variable-rate-rasterization.62243/post-2191363
//
return false;
case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS:
return true;
default:
Expand All @@ -3928,6 +3917,14 @@ bool isArrayTexture(MTLTextureType p_type) {
return multiview_capabilities;
}

const RDD::FragmentShadingRateCapabilities &RenderingDeviceDriverMetal::get_fragment_shading_rate_capabilities() {
return fsr_capabilities;
}

const RDD::FragmentDensityMapCapabilities &RenderingDeviceDriverMetal::get_fragment_density_map_capabilities() {
return fdm_capabilities;
}

String RenderingDeviceDriverMetal::get_api_version() const {
return vformat("%d.%d", version_major, version_minor);
}
Expand Down
Loading

0 comments on commit aa73990

Please sign in to comment.