mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-20 18:59:26 +02:00
first try on dynamic rendering unused attachments
This commit is contained in:
parent
dfe0b7e7c7
commit
14b6160fcd
8 changed files with 94 additions and 20 deletions
|
|
@ -88,6 +88,18 @@ bool ComputeAttachment0DualSourceBlend(const Maxwell& regs) {
|
||||||
: uses_dual_source(regs.blend);
|
: 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) {
|
void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell& regs) {
|
||||||
std::ranges::transform(regs.transform_feedback.controls, state.layouts.begin(),
|
std::ranges::transform(regs.transform_feedback.controls, state.layouts.begin(),
|
||||||
[](const auto& layout) {
|
[](const auto& layout) {
|
||||||
|
|
@ -101,7 +113,8 @@ void RefreshXfbState(VideoCommon::TransformFeedbackState& state, const Maxwell&
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // 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 Maxwell& regs = maxwell3d.regs;
|
||||||
const auto topology_ = maxwell3d.draw_manager.draw_state.topology;
|
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;
|
regs.alpha_test_enabled != 0 ? regs.alpha_test_func : Maxwell::ComparisonOp::Always_GL;
|
||||||
alpha_test_func.Assign(PackComparisonOp(test_func));
|
alpha_test_func.Assign(PackComparisonOp(test_func));
|
||||||
early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
|
early_z.Assign(regs.mandated_early_z != 0 ? 1 : 0);
|
||||||
depth_enabled.Assign(regs.zeta_enable != 0 ? 1 : 0);
|
const bool drop_unused = features.has_dynamic_rendering_unused_attachments;
|
||||||
depth_format.Assign(static_cast<u32>(regs.zeta.format));
|
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);
|
y_negate.Assign(regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft ? 1 : 0);
|
||||||
|
|
||||||
bool use_last_provoking_vertex = false;
|
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;
|
line_stipple_pattern = regs.line_stipple_params.pattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < regs.rt.size(); ++i) {
|
const bool static_masks =
|
||||||
color_formats[i] = static_cast<u8>(regs.rt[i].format);
|
!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;
|
alpha_test_ref = 0;
|
||||||
if (regs.alpha_test_enabled != 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);
|
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
|
||||||
}
|
}
|
||||||
if (!extended_dynamic_state_3_blend) {
|
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;
|
maxwell3d.dirty.flags[Dirty::Blending] = false;
|
||||||
for (size_t index = 0; index < attachments.size(); ++index) {
|
for (size_t index = 0; index < attachments.size(); ++index) {
|
||||||
attachments[index].Refresh(regs, index);
|
|
||||||
auto& attachment = attachments[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 &&
|
if (color_write_enable_dynamic && attachment.mask_r == 0 &&
|
||||||
attachment.mask_g == 0 && attachment.mask_b == 0 &&
|
attachment.mask_g == 0 && attachment.mask_b == 0 &&
|
||||||
attachment.mask_a == 0) {
|
attachment.mask_a == 0) {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ struct DynamicFeatures {
|
||||||
bool has_provoking_vertex_first_mode;
|
bool has_provoking_vertex_first_mode;
|
||||||
bool has_provoking_vertex_last_mode;
|
bool has_provoking_vertex_last_mode;
|
||||||
bool has_provoking_vertex_tf_preserve;
|
bool has_provoking_vertex_tf_preserve;
|
||||||
|
bool has_dynamic_rendering_unused_attachments;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FixedPipelineState {
|
struct FixedPipelineState {
|
||||||
|
|
@ -255,7 +256,8 @@ struct FixedPipelineState {
|
||||||
|
|
||||||
VideoCommon::TransformFeedbackState xfb_state;
|
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;
|
size_t Hash() const noexcept;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ using VideoCommon::FileEnvironment;
|
||||||
using VideoCommon::GenericEnvironment;
|
using VideoCommon::GenericEnvironment;
|
||||||
using VideoCommon::GraphicsEnvironment;
|
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_PIPELINES = 128;
|
||||||
constexpr size_t VULKAN_CACHE_FLUSH_MIN_SECONDS = 30;
|
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'};
|
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();
|
device.SupportsProvokingVertexLastMode();
|
||||||
dynamic_features.has_provoking_vertex_tf_preserve =
|
dynamic_features.has_provoking_vertex_tf_preserve =
|
||||||
device.SupportsTransformFeedbackProvokingVertexPreservation();
|
device.SupportsTransformFeedbackProvokingVertexPreservation();
|
||||||
|
dynamic_features.has_dynamic_rendering_unused_attachments =
|
||||||
|
device.IsExtDynamicRenderingUnusedAttachmentsSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineCache::~PipelineCache() {
|
PipelineCache::~PipelineCache() {
|
||||||
|
|
@ -566,7 +568,7 @@ GraphicsPipeline* PipelineCache::CurrentGraphicsPipeline() {
|
||||||
current_pipeline = nullptr;
|
current_pipeline = nullptr;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
graphics_key.state.Refresh(*maxwell3d, dynamic_features);
|
graphics_key.state.Refresh(*maxwell3d, dynamic_features, fragment_color_outputs);
|
||||||
|
|
||||||
if (current_pipeline) {
|
if (current_pipeline) {
|
||||||
GraphicsPipeline* const next{current_pipeline->Next(graphics_key)};
|
GraphicsPipeline* const next{current_pipeline->Next(graphics_key)};
|
||||||
|
|
|
||||||
|
|
@ -244,24 +244,37 @@ void Scheduler::RequestComputeDispatchContext() {
|
||||||
|
|
||||||
void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const {
|
void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const {
|
||||||
const bool load_op_none = device.IsLoadOpNoneSupported();
|
const bool load_op_none = device.IsLoadOpNoneSupported();
|
||||||
|
const bool drop_unused = device.IsExtDynamicRenderingUnusedAttachmentsSupported();
|
||||||
const auto relax = [&](VkRenderingAttachmentInfo& attachment, u32 bit) {
|
const auto relax = [&](VkRenderingAttachmentInfo& attachment, u32 bit) {
|
||||||
if (attachment.imageView == VK_NULL_HANDLE ||
|
if (attachment.imageView == VK_NULL_HANDLE) {
|
||||||
attachment.resolveMode != VK_RESOLVE_MODE_NONE ||
|
return true;
|
||||||
|
}
|
||||||
|
if (attachment.resolveMode != VK_RESOLVE_MODE_NONE ||
|
||||||
attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ||
|
attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ||
|
||||||
attachment.storeOp != VK_ATTACHMENT_STORE_OP_STORE ||
|
attachment.storeOp != VK_ATTACHMENT_STORE_OP_STORE ||
|
||||||
(attachments_written & bit) != 0) {
|
(attachments_written & bit) != 0) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
attachment.storeOp = VK_ATTACHMENT_STORE_OP_NONE;
|
attachment.storeOp = VK_ATTACHMENT_STORE_OP_NONE;
|
||||||
if (load_op_none && (attachments_touched & bit) == 0) {
|
return (attachments_touched & bit) == 0;
|
||||||
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_NONE;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
for (u32 slot = 0; slot < attachments.num_colors; ++slot) {
|
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() {
|
void Scheduler::PublishComputeWrites() {
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) {
|
||||||
return last_shaders_valid;
|
return last_shaders_valid;
|
||||||
}
|
}
|
||||||
dirty[VideoCommon::Dirty::Shaders] = false;
|
dirty[VideoCommon::Dirty::Shaders] = false;
|
||||||
|
fragment_color_outputs = 0;
|
||||||
|
|
||||||
const GPUVAddr base_addr{maxwell3d->regs.program_region.Address()};
|
const GPUVAddr base_addr{maxwell3d->regs.program_region.Address()};
|
||||||
for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) {
|
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;
|
shader_infos[index] = shader_info;
|
||||||
unique_hashes[index] = shader_info->unique_hash;
|
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;
|
last_shaders_valid = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -241,6 +245,13 @@ const ShaderInfo* ShaderCache::MakeShaderInfo(GenericEnvironment& env, VAddr cpu
|
||||||
info->unique_hash = env.CalculateHash();
|
info->unique_hash = env.CalculateHash();
|
||||||
info->size_bytes = env.ReadSizeBytes();
|
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 size_t size_bytes{info->size_bytes};
|
||||||
const ShaderInfo* const result{info.get()};
|
const ShaderInfo* const result{info.get()};
|
||||||
Register(std::move(info), cpu_addr, size_bytes);
|
Register(std::move(info), cpu_addr, size_bytes);
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class GenericEnvironment;
|
||||||
struct ShaderInfo {
|
struct ShaderInfo {
|
||||||
u64 unique_hash{};
|
u64 unique_hash{};
|
||||||
size_t size_bytes{};
|
size_t size_bytes{};
|
||||||
|
u32 color_outputs{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShaderCache : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
|
class ShaderCache : public VideoCommon::ChannelSetupCaches<VideoCommon::ChannelInfo> {
|
||||||
|
|
@ -98,6 +99,7 @@ protected:
|
||||||
|
|
||||||
std::array<const ShaderInfo*, NUM_PROGRAMS> shader_infos{};
|
std::array<const ShaderInfo*, NUM_PROGRAMS> shader_infos{};
|
||||||
bool last_shaders_valid = false;
|
bool last_shaders_valid = false;
|
||||||
|
u32 fragment_color_outputs{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @brief Tries to obtain a cached shader starting in a given address
|
/// @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,
|
RemoveExtensionFeatureIfUnsuitable(extensions.descriptor_buffer, features.descriptor_buffer,
|
||||||
VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME);
|
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
|
// VK_EXT_extended_dynamic_state
|
||||||
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
|
extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
|
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||||
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
|
FEATURE(EXT, DepthBiasControl, DEPTH_BIAS_CONTROL, depth_bias_control) \
|
||||||
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
|
FEATURE(EXT, DepthClipControl, DEPTH_CLIP_CONTROL, depth_clip_control) \
|
||||||
FEATURE(EXT, DescriptorBuffer, DESCRIPTOR_BUFFER, descriptor_buffer) \
|
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, ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, extended_dynamic_state) \
|
||||||
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
|
FEATURE(EXT, ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, extended_dynamic_state2) \
|
||||||
FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
|
FEATURE(EXT, ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, extended_dynamic_state3) \
|
||||||
|
|
@ -670,11 +672,15 @@ FN_MAX_LIMIT_LIST
|
||||||
return extensions.depth_clip_control;
|
return extensions.depth_clip_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_depth_bias_control.
|
|
||||||
bool IsLoadOpNoneSupported() const {
|
bool IsLoadOpNoneSupported() const {
|
||||||
return extensions.load_store_op_none || extensions.load_store_op_none_ext;
|
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 {
|
bool IsExtDepthBiasControlSupported() const {
|
||||||
return extensions.depth_bias_control;
|
return extensions.depth_bias_control;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue