mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
first try on dynamic rendering unused attachments
This commit is contained in:
@@ -88,6 +88,18 @@ bool ComputeAttachment0DualSourceBlend(const Maxwell& regs) {
|
||||
: uses_dual_source(regs.blend);
|
||||
}
|
||||
|
||||
bool WritesColorTarget(const Maxwell& regs, size_t index, bool static_masks) {
|
||||
if (!static_masks || (index == 0 && regs.anti_alias_alpha_control.alpha_to_coverage != 0)) {
|
||||
return true;
|
||||
}
|
||||
size_t mask_index = index;
|
||||
if (regs.color_mask_common) {
|
||||
mask_index = 0;
|
||||
}
|
||||
const auto& mask = regs.color_mask[mask_index];
|
||||
return mask.R || mask.G || mask.B || mask.A;
|
||||
}
|
||||
|
||||
void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs) {
|
||||
std::ranges::transform(regs.transform_feedback.controls, state.layouts.begin(),
|
||||
[](const auto& layout) {
|
||||
@@ -101,7 +113,8 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell&
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features) {
|
||||
void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features,
|
||||
u32 color_outputs) {
|
||||
const Maxwell& regs = maxwell3d.regs;
|
||||
const auto topology_ = maxwell3d.draw_manager.draw_state.topology;
|
||||
|
||||
@@ -141,8 +154,13 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
regs.alpha_test_enabled != 0 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always_GL;
|
||||
alpha_test_func.Assign(PackComparisonOp(test_func));
|
||||
early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
|
||||
depth_enabled.Assign(regs.zeta_enable != 0 ? 1 : 0);
|
||||
depth_format.Assign(static_cast<u32>(regs.zeta.format));
|
||||
const bool drop_unused = features.has_dynamic_rendering_unused_attachments;
|
||||
const bool depth_used = regs.depth_test_enable || regs.depth_bounds_enable ||
|
||||
regs.stencil_enable || extended_dynamic_state;
|
||||
if (regs.zeta_enable != 0 && regs.zeta.Address() != 0 && (depth_used || !drop_unused)) {
|
||||
depth_enabled.Assign(1);
|
||||
depth_format.Assign(static_cast<u32>(regs.zeta.format));
|
||||
}
|
||||
y_negate.Assign(regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft ? 1 : 0);
|
||||
|
||||
bool use_last_provoking_vertex = false;
|
||||
@@ -179,8 +197,18 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
line_stipple_pattern = regs.line_stipple_params.pattern;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < regs.rt.size(); ++i) {
|
||||
color_formats[i] = static_cast<u8>(regs.rt[i].format);
|
||||
const bool static_masks =
|
||||
!features.has_extended_dynamic_state_3_blend && !features.has_color_write_enable;
|
||||
const auto previous_formats = color_formats;
|
||||
color_formats.fill(static_cast<u8>(Tegra::RenderTargetFormat::NONE));
|
||||
const size_t num_targets = (std::min)(size_t{regs.rt_control.count}, color_formats.size());
|
||||
for (size_t index = 0; index < num_targets; ++index) {
|
||||
const bool used = ((color_outputs >> index) & 1) != 0 &&
|
||||
WritesColorTarget(regs, index, static_masks);
|
||||
if (regs.rt[index].Address() == 0 || (drop_unused && !used)) {
|
||||
continue;
|
||||
}
|
||||
color_formats[index] = static_cast<u8>(regs.rt[index].format);
|
||||
}
|
||||
alpha_test_ref = 0;
|
||||
if (regs.alpha_test_enabled != 0) {
|
||||
@@ -251,11 +279,15 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
|
||||
}
|
||||
if (!extended_dynamic_state_3_blend) {
|
||||
if (maxwell3d.dirty.flags[Dirty::Blending]) {
|
||||
if (maxwell3d.dirty.flags[Dirty::Blending] || color_formats != previous_formats) {
|
||||
maxwell3d.dirty.flags[Dirty::Blending] = false;
|
||||
for (size_t index = 0; index < attachments.size(); ++index) {
|
||||
attachments[index].Refresh(regs, index);
|
||||
auto& attachment = attachments[index];
|
||||
attachment.raw = 0;
|
||||
if (color_formats[index] == static_cast<u8>(Tegra::RenderTargetFormat::NONE)) {
|
||||
continue;
|
||||
}
|
||||
attachment.Refresh(regs, index);
|
||||
if (color_write_enable_dynamic && attachment.mask_r == 0 &&
|
||||
attachment.mask_g == 0 && attachment.mask_b == 0 &&
|
||||
attachment.mask_a == 0) {
|
||||
|
||||
@@ -38,6 +38,7 @@ struct DynamicFeatures {
|
||||
bool has_provoking_vertex_first_mode;
|
||||
bool has_provoking_vertex_last_mode;
|
||||
bool has_provoking_vertex_tf_preserve;
|
||||
bool has_dynamic_rendering_unused_attachments;
|
||||
};
|
||||
|
||||
struct FixedPipelineState {
|
||||
@@ -255,7 +256,8 @@ struct FixedPipelineState {
|
||||
|
||||
VideoCommon::TransformFeedbackState xfb_state;
|
||||
|
||||
void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features);
|
||||
void Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFeatures& features,
|
||||
u32 color_outputs);
|
||||
|
||||
size_t Hash() const noexcept;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ using VideoCommon::FileEnvironment;
|
||||
using VideoCommon::GenericEnvironment;
|
||||
using VideoCommon::GraphicsEnvironment;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 19;
|
||||
constexpr u32 CACHE_VERSION = 20;
|
||||
constexpr size_t VULKAN_CACHE_FLUSH_PIPELINES = 128;
|
||||
constexpr size_t VULKAN_CACHE_FLUSH_MIN_SECONDS = 30;
|
||||
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
|
||||
@@ -551,6 +551,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
device.SupportsProvokingVertexLastMode();
|
||||
dynamic_features.has_provoking_vertex_tf_preserve =
|
||||
device.SupportsTransformFeedbackProvokingVertexPreservation();
|
||||
dynamic_features.has_dynamic_rendering_unused_attachments =
|
||||
device.IsExtDynamicRenderingUnusedAttachmentsSupported();
|
||||
}
|
||||
|
||||
PipelineCache::~PipelineCache() {
|
||||
@@ -566,7 +568,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
|
||||
current_pipeline = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
graphics_key.state.Refresh(*maxwell3d, dynamic_features);
|
||||
graphics_key.state.Refresh(*maxwell3d, dynamic_features, fragment_color_outputs);
|
||||
|
||||
if (current_pipeline) {
|
||||
GraphicsPipeline* const next{current_pipeline->Next(graphics_key)};
|
||||
|
||||
@@ -244,24 +244,37 @@ void Scheduler::RequestComputeDispatchContext() {
|
||||
|
||||
void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const {
|
||||
const bool load_op_none = device.IsLoadOpNoneSupported();
|
||||
const bool drop_unused = device.IsExtDynamicRenderingUnusedAttachmentsSupported();
|
||||
const auto relax = [&](VkRenderingAttachmentInfo& attachment, u32 bit) {
|
||||
if (attachment.imageView == VK_NULL_HANDLE ||
|
||||
attachment.resolveMode != VK_RESOLVE_MODE_NONE ||
|
||||
if (attachment.imageView == VK_NULL_HANDLE) {
|
||||
return true;
|
||||
}
|
||||
if (attachment.resolveMode != VK_RESOLVE_MODE_NONE ||
|
||||
attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ||
|
||||
attachment.storeOp != VK_ATTACHMENT_STORE_OP_STORE ||
|
||||
(attachments_written & bit) != 0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
attachment.storeOp = VK_ATTACHMENT_STORE_OP_NONE;
|
||||
if (load_op_none && (attachments_touched & bit) == 0) {
|
||||
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_NONE;
|
||||
}
|
||||
return (attachments_touched & bit) == 0;
|
||||
};
|
||||
for (u32 slot = 0; slot < attachments.num_colors; ++slot) {
|
||||
relax(attachments.colors[slot], 1u << slot);
|
||||
VkRenderingAttachmentInfo& color = attachments.colors[slot];
|
||||
if (!relax(color, 1u << slot)) {
|
||||
continue;
|
||||
}
|
||||
if (drop_unused) {
|
||||
color.imageView = VK_NULL_HANDLE;
|
||||
} else if (load_op_none) {
|
||||
color.loadOp = VK_ATTACHMENT_LOAD_OP_NONE;
|
||||
}
|
||||
}
|
||||
const bool depth_unused = relax(attachments.depth, DEPTH_ATTACHMENT_BIT);
|
||||
const bool stencil_unused = relax(attachments.stencil, STENCIL_ATTACHMENT_BIT);
|
||||
if (drop_unused && depth_unused && stencil_unused) {
|
||||
attachments.depth.imageView = VK_NULL_HANDLE;
|
||||
attachments.stencil.imageView = VK_NULL_HANDLE;
|
||||
}
|
||||
relax(attachments.depth, DEPTH_ATTACHMENT_BIT);
|
||||
relax(attachments.stencil, STENCIL_ATTACHMENT_BIT);
|
||||
}
|
||||
|
||||
void Scheduler::PublishComputeWrites() {
|
||||
|
||||
@@ -49,6 +49,7 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) {
|
||||
return last_shaders_valid;
|
||||
}
|
||||
dirty[VideoCommon::Dirty::Shaders] = false;
|
||||
fragment_color_outputs = 0;
|
||||
|
||||
const GPUVAddr base_addr{maxwell3d->regs.program_region.Address()};
|
||||
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) {
|
||||
@@ -78,6 +79,9 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) {
|
||||
}
|
||||
shader_infos[index] = shader_info;
|
||||
unique_hashes[index] = shader_info->unique_hash;
|
||||
if (program == Tegra::Engines::Maxwell3D::Regs::ShaderType::Pixel) {
|
||||
fragment_color_outputs = shader_info->color_outputs;
|
||||
}
|
||||
}
|
||||
last_shaders_valid = true;
|
||||
return true;
|
||||
@@ -241,6 +245,13 @@ const ShaderInfo* ShaderCache::MakeShaderInfo(GenericEnvironment& env, VAddr cpu
|
||||
info->unique_hash = env.CalculateHash();
|
||||
info->size_bytes = env.ReadSizeBytes();
|
||||
}
|
||||
if (env.ShaderStage() == Shader::Stage::Fragment) {
|
||||
for (u32 target = 0; target < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; ++target) {
|
||||
if (env.SPH().ps.HasOutputComponents(target)) {
|
||||
info->color_outputs |= 1U << target;
|
||||
}
|
||||
}
|
||||
}
|
||||
const size_t size_bytes{info->size_bytes};
|
||||
const ShaderInfo* const result{info.get()};
|
||||
Register(std::move(info), cpu_addr, size_bytes);
|
||||
|
||||
@@ -36,6 +36,7 @@ class GenericEnvironment;
|
||||
struct ShaderInfo {
|
||||
u64 unique_hash{};
|
||||
size_t size_bytes{};
|
||||
u32 color_outputs{};
|
||||
};
|
||||
|
||||
class ShaderCache : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
|
||||
@@ -98,6 +99,7 @@ protected:
|
||||
|
||||
std::array<const ShaderInfo*, NUM_PROGRAMS> shader_infos{};
|
||||
bool last_shaders_valid = false;
|
||||
u32 fragment_color_outputs{};
|
||||
|
||||
private:
|
||||
/// @brief Tries to obtain a cached shader starting in a given address
|
||||
|
||||
@@ -1247,6 +1247,12 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.descriptor_buffer, features.descriptor_buffer,
|
||||
VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
|
||||
|
||||
extensions.dynamic_rendering_unused_attachments =
|
||||
features.dynamic_rendering_unused_attachments.dynamicRenderingUnusedAttachments;
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.dynamic_rendering_unused_attachments,
|
||||
features.dynamic_rendering_unused_attachments,
|
||||
VK_EXT_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_extended_dynamic_state
|
||||
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
|
||||
|
||||
@@ -61,6 +61,8 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
|
||||
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
|
||||
FEATURE(EXT, DescriptorBuffer, DESCRIPTOR_BUFFER, descriptor_buffer) \
|
||||
FEATURE(EXT, DynamicRenderingUnusedAttachments, DYNAMIC_RENDERING_UNUSED_ATTACHMENTS, \
|
||||
dynamic_rendering_unused_attachments) \
|
||||
FEATURE(EXT, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
|
||||
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
|
||||
FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
|
||||
@@ -670,11 +672,15 @@ FN_MAX_LIMIT_LIST
|
||||
return extensions.depth_clip_control;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_depth_bias_control.
|
||||
bool IsLoadOpNoneSupported() const {
|
||||
return extensions.load_store_op_none || extensions.load_store_op_none_ext;
|
||||
}
|
||||
|
||||
bool IsExtDynamicRenderingUnusedAttachmentsSupported() const {
|
||||
return extensions.dynamic_rendering_unused_attachments;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_depth_bias_control.
|
||||
bool IsExtDepthBiasControlSupported() const {
|
||||
return extensions.depth_bias_control;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user