Browse Source

[TEST] DR Adjustment 2

temporary-branch
CamilleLaVey 4 days ago
parent
commit
7fcf88cb10
  1. 15
      src/video_core/renderer_vulkan/vk_rasterizer.cpp
  2. 272
      src/video_core/renderer_vulkan/vk_scheduler.cpp
  3. 11
      src/video_core/renderer_vulkan/vk_scheduler.h
  4. 12
      src/video_core/renderer_vulkan/vk_texture_cache.cpp

15
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -438,10 +438,17 @@ void RasterizerVulkan::Clear(u32 layer_count) {
const bool ds_deferrable = const bool ds_deferrable =
!ds_used || ((!framebuffer->HasAspectDepthBit() || use_depth) && !ds_used || ((!framebuffer->HasAspectDepthBit() || use_depth) &&
(!framebuffer->HasAspectStencilBit() || use_stencil) && !stencil_partial); (!framebuffer->HasAspectStencilBit() || use_stencil) && !stencil_partial);
const bool can_defer_clear = ENABLE_DEFERRED_CLEAR && !regs.clear_control.use_scissor &&
regs.clear_surface.layer == 0 &&
!scheduler.IsRenderPassActive() &&
(!use_color || color_full_channels) && ds_deferrable;
const bool clear_shape_deferrable = ENABLE_DEFERRED_CLEAR &&
!regs.clear_control.use_scissor &&
regs.clear_surface.layer == 0 &&
(!use_color || color_full_channels) && ds_deferrable;
// An open pass normally blocks deferral, which drops the clear to ClearAttachments inside the
// pass and also loses the MSAA store discard, since that only applies when a clear is folded
// into the begin. A pass whose BeginRendering has not been recorded yet can be retracted for
// free, so the clear becomes a load op after all. Only retract when it will actually be used.
const bool can_defer_clear =
clear_shape_deferrable &&
(!scheduler.IsRenderPassActive() || scheduler.RetractUnrecordedRenderPass());
if (!can_defer_clear) { if (!can_defer_clear) {
scheduler.RequestRenderpass(framebuffer); scheduler.RequestRenderpass(framebuffer);
} }

272
src/video_core/renderer_vulkan/vk_scheduler.cpp

@ -126,12 +126,43 @@ void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const Defe
GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info); GPU::Logging::GPULogger::GetInstance().LogRenderPassBegin(render_pass_info);
} }
RecordDynamicBegin(clear);
pending_begin = true;
has_pending_begin_clear = clear != nullptr;
pending_begin_clear = clear != nullptr ? *clear : DeferredClear{};
num_renderpass_images = framebuffer->NumImages(); num_renderpass_images = framebuffer->NumImages();
renderpass_images = framebuffer->Images(); renderpass_images = framebuffer->Images();
renderpass_image_ranges = framebuffer->ImageRanges(); renderpass_image_ranges = framebuffer->ImageRanges();
} }
void Scheduler::FlushPendingRenderPass() {
if (!pending_begin) {
return;
}
pending_begin = false;
const bool had_clear = has_pending_begin_clear;
has_pending_begin_clear = false;
RecordDynamicBegin(had_clear ? &pending_begin_clear : nullptr);
}
bool Scheduler::RetractUnrecordedRenderPass() {
if (!pending_begin) {
return false;
}
pending_begin = false;
if (has_pending_begin_clear) {
deferred_clear = pending_begin_clear;
has_pending_begin_clear = false;
}
state.renderpass = VkRenderPass{};
state.framebuffer = VkFramebuffer{};
state.attachment_views = {};
state.rendering = false;
state.uses_transform_feedback = false;
num_renderpass_images = 0;
return true;
}
void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass, void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, VkRenderPass renderpass,
const VkClearValue* clear_values, u32 clear_value_count) { const VkClearValue* clear_values, u32 clear_value_count) {
if (device.IsKhrDynamicRenderingSupported()) { if (device.IsKhrDynamicRenderingSupported()) {
@ -439,101 +470,152 @@ void Scheduler::InvalidateState() {
state_tracker.InvalidateCommandBufferState(); state_tracker.InvalidateCommandBufferState();
} }
void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
const std::array<VkImageView, 9> views = state.attachment_views;
const std::array<VkImageView, 8> resolve_views = state.color_resolve_views;
const std::array<VkResolveModeFlagBits, 8> resolve_modes = state.color_resolve_modes;
const u32 num_color = state.num_color;
const bool has_depth = state.has_depth;
const bool has_stencil = state.has_stencil;
const u32 layers = state.layer_count;
const VkExtent2D render_area = state.render_area;
const u32 color_clear_mask = clear ? clear->color_clear_mask : 0u;
const u32 color_discard_mask =
clear != nullptr && state.discards_msaa_color ? clear->color_clear_mask : 0u;
const std::array<VkClearValue, 8> color_clear_values =
clear ? clear->color_values : std::array<VkClearValue, 8>{};
const bool ds_clear = clear != nullptr && clear->depth_stencil;
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
const bool ds_discard = state.discards_msaa_depth;
const VkImageView ds_resolve_view = state.depth_resolve_view;
const VkResolveModeFlagBits depth_resolve_mode = state.depth_resolve_mode;
const VkResolveModeFlagBits stencil_resolve_mode = state.stencil_resolve_mode;
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
ds_clear_value, ds_discard, ds_resolve_view, depth_resolve_mode,
stencil_resolve_mode](vk::CommandBuffer cmdbuf) {
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
for (u32 index = 0; index < num_color; ++index) {
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
const VkImageView resolve_view = resolve_views[index];
const bool has_resolve = resolve_view != VK_NULL_HANDLE;
const bool discard_slot = has_resolve && ((color_discard_mask >> index) & 1u) != 0;
color_infos[index] = VkRenderingAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = views[index],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_resolve ? resolve_modes[index] : VK_RESOLVE_MODE_NONE,
.resolveImageView = resolve_view,
.resolveImageLayout =
has_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = discard_slot ? VK_ATTACHMENT_STORE_OP_DONT_CARE
: VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
};
}
const bool has_ds_resolve = ds_resolve_view != VK_NULL_HANDLE;
const VkAttachmentLoadOp ds_load_op = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR
: ds_discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD;
const VkAttachmentStoreOp ds_store_op =
ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
const VkRenderingAttachmentInfo depth_info{
namespace {
/// The part of a dynamic rendering begin that every pass needs.
struct DynamicRenderingBase {
std::array<VkImageView, 9> views;
VkExtent2D render_area;
u32 num_color;
u32 layers;
VkImageView ds_resolve_view;
VkResolveModeFlagBits depth_resolve_mode;
VkResolveModeFlagBits stencil_resolve_mode;
bool has_depth;
bool has_stencil;
bool ds_discard;
};
/// The part only a pass that actually clears something needs.
struct DynamicRenderingClears {
std::array<VkClearValue, 8> color_values;
VkClearValue ds_value;
u32 color_clear_mask;
u32 color_discard_mask;
bool ds_clear;
};
/// Builds the rendering info and begins the instance. `resolve_views`/`resolve_modes` and `clears`
/// are null for passes with no colour resolve targets and no clears, so those tables never have to
/// be copied into the recorded command.
void IssueBeginRendering(vk::CommandBuffer cmdbuf, const DynamicRenderingBase& base,
const std::array<VkImageView, 8>* resolve_views,
const std::array<VkResolveModeFlagBits, 8>* resolve_modes,
const DynamicRenderingClears* clears) {
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
for (u32 index = 0; index < base.num_color; ++index) {
const bool clear_slot =
clears != nullptr && ((clears->color_clear_mask >> index) & 1u) != 0;
const VkImageView resolve_view =
resolve_views != nullptr ? (*resolve_views)[index] : VK_NULL_HANDLE;
const bool has_resolve = resolve_view != VK_NULL_HANDLE;
const bool discard_slot =
has_resolve && clears != nullptr && ((clears->color_discard_mask >> index) & 1u) != 0;
color_infos[index] = VkRenderingAttachmentInfo{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr, .pNext = nullptr,
.imageView = views[8],
.imageView = base.views[index],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL, .imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_ds_resolve ? depth_resolve_mode : VK_RESOLVE_MODE_NONE,
.resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE,
.resolveMode = has_resolve ? (*resolve_modes)[index] : VK_RESOLVE_MODE_NONE,
.resolveImageView = resolve_view,
.resolveImageLayout = .resolveImageLayout =
has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = ds_load_op,
.storeOp = ds_store_op,
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
has_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = clear_slot ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
.storeOp = discard_slot ? VK_ATTACHMENT_STORE_OP_DONT_CARE
: VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = clear_slot ? clears->color_values[index] : VkClearValue{},
}; };
// Stencil gets its own struct because its resolve mode may differ from depth's.
const VkRenderingAttachmentInfo stencil_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = views[8],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_ds_resolve ? stencil_resolve_mode : VK_RESOLVE_MODE_NONE,
.resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE,
.resolveImageLayout =
has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = ds_load_op,
.storeOp = ds_store_op,
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
};
const VkRenderingInfo rendering_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.pNext = nullptr,
.flags = 0,
.renderArea =
{
.offset = {.x = 0, .y = 0},
.extent = render_area,
},
.layerCount = layers,
.viewMask = 0,
.colorAttachmentCount = num_color,
.pColorAttachments = color_infos.data(),
.pDepthAttachment = has_depth ? &depth_info : nullptr,
.pStencilAttachment = has_stencil ? &stencil_info : nullptr,
};
cmdbuf.BeginRendering(rendering_info);
}
const bool ds_clear = clears != nullptr && clears->ds_clear;
const VkClearValue ds_clear_value = clears != nullptr ? clears->ds_value : VkClearValue{};
const bool has_ds_resolve = base.ds_resolve_view != VK_NULL_HANDLE;
const VkAttachmentLoadOp ds_load_op = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR
: base.ds_discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
: VK_ATTACHMENT_LOAD_OP_LOAD;
const VkAttachmentStoreOp ds_store_op =
base.ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
const VkRenderingAttachmentInfo depth_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = base.views[8],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_ds_resolve ? base.depth_resolve_mode : VK_RESOLVE_MODE_NONE,
.resolveImageView = has_ds_resolve ? base.ds_resolve_view : VK_NULL_HANDLE,
.resolveImageLayout = has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL
: VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = ds_load_op,
.storeOp = ds_store_op,
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
};
// Stencil gets its own struct because its resolve mode may differ from depth's.
const VkRenderingAttachmentInfo stencil_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.pNext = nullptr,
.imageView = base.views[8],
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
.resolveMode = has_ds_resolve ? base.stencil_resolve_mode : VK_RESOLVE_MODE_NONE,
.resolveImageView = has_ds_resolve ? base.ds_resolve_view : VK_NULL_HANDLE,
.resolveImageLayout = has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL
: VK_IMAGE_LAYOUT_UNDEFINED,
.loadOp = ds_load_op,
.storeOp = ds_store_op,
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
};
const VkRenderingInfo rendering_info{
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.pNext = nullptr,
.flags = 0,
.renderArea =
{
.offset = {.x = 0, .y = 0},
.extent = base.render_area,
},
.layerCount = base.layers,
.viewMask = 0,
.colorAttachmentCount = base.num_color,
.pColorAttachments = color_infos.data(),
.pDepthAttachment = base.has_depth ? &depth_info : nullptr,
.pStencilAttachment = base.has_stencil ? &stencil_info : nullptr,
};
cmdbuf.BeginRendering(rendering_info);
}
} // Anonymous namespace
void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
const DynamicRenderingBase base{
.views = state.attachment_views,
.render_area = state.render_area,
.num_color = state.num_color,
.layers = state.layer_count,
.ds_resolve_view = state.depth_resolve_view,
.depth_resolve_mode = state.depth_resolve_mode,
.stencil_resolve_mode = state.stencil_resolve_mode,
.has_depth = state.has_depth,
.has_stencil = state.has_stencil,
.ds_discard = state.discards_msaa_depth,
};
bool has_color_resolve = false;
for (const VkImageView resolve_view : state.color_resolve_views) {
has_color_resolve = has_color_resolve || resolve_view != VK_NULL_HANDLE;
}
if (clear == nullptr && !has_color_resolve) {
// Common case. Every byte captured here is copied into the command chunk on every single
// pass begin, and the clear values plus the two resolve tables are two thirds of them.
Record([base](vk::CommandBuffer cmdbuf) {
IssueBeginRendering(cmdbuf, base, nullptr, nullptr, nullptr);
});
return;
}
const DynamicRenderingClears clears{
.color_values = clear != nullptr ? clear->color_values : std::array<VkClearValue, 8>{},
.ds_value = clear != nullptr ? clear->depth_stencil_value : VkClearValue{},
.color_clear_mask = clear != nullptr ? clear->color_clear_mask : 0u,
.color_discard_mask =
clear != nullptr && state.discards_msaa_color ? clear->color_clear_mask : 0u,
.ds_clear = clear != nullptr && clear->depth_stencil,
};
Record([base, resolve_views = state.color_resolve_views,
resolve_modes = state.color_resolve_modes, clears](vk::CommandBuffer cmdbuf) {
IssueBeginRendering(cmdbuf, base, &resolve_views, &resolve_modes, &clears);
}); });
} }
@ -560,6 +642,14 @@ void Scheduler::EndRenderPass()
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false); query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
query_cache->NotifySegment(false); query_cache->NotifySegment(false);
if (pending_begin) {
if (!has_pending_begin_clear) {
RetractUnrecordedRenderPass();
return;
}
FlushPendingRenderPass();
}
Record([num_images = num_renderpass_images, Record([num_images = num_renderpass_images,
images = renderpass_images, images = renderpass_images,
ranges = renderpass_image_ranges, ranges = renderpass_image_ranges,

11
src/video_core/renderer_vulkan/vk_scheduler.h

@ -112,12 +112,17 @@ public:
template <typename T> template <typename T>
requires std::is_invocable_v<T, vk::CommandBuffer> requires std::is_invocable_v<T, vk::CommandBuffer>
void Record(T&& c) { void Record(T&& c) {
if (pending_begin) {
FlushPendingRenderPass();
}
this->RecordWithUploadBuffer( this->RecordWithUploadBuffer(
[command = std::move(c)](vk::CommandBuffer cmdbuf, vk::CommandBuffer) { [command = std::move(c)](vk::CommandBuffer cmdbuf, vk::CommandBuffer) {
command(cmdbuf); command(cmdbuf);
}); });
} }
bool RetractUnrecordedRenderPass();
/// Returns the current command buffer tick. /// Returns the current command buffer tick.
[[nodiscard]] u64 CurrentTick() const noexcept { [[nodiscard]] u64 CurrentTick() const noexcept {
return master_semaphore->CurrentTick(); return master_semaphore->CurrentTick();
@ -318,6 +323,8 @@ private:
void RecordDynamicBegin(const DeferredClear* clear); void RecordDynamicBegin(const DeferredClear* clear);
void FlushPendingRenderPass();
void EndRenderPass(); void EndRenderPass();
void AcquireNewChunk(); void AcquireNewChunk();
@ -335,6 +342,10 @@ private:
DeferredClear deferred_clear; DeferredClear deferred_clear;
bool pending_begin = false;
bool has_pending_begin_clear = false;
DeferredClear pending_begin_clear;
std::unique_ptr<CommandChunk> chunk; std::unique_ptr<CommandChunk> chunk;
std::function<void()> on_submit; std::function<void()> on_submit;

12
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -56,6 +56,7 @@ namespace {
constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true; constexpr bool ENABLE_MSAA_RESOLVE_CONSUME = true;
constexpr bool ENABLE_MSAA_COLOR_DISCARD = true; constexpr bool ENABLE_MSAA_COLOR_DISCARD = true;
constexpr bool ENABLE_MSAA_DEPTH_DISCARD = true; constexpr bool ENABLE_MSAA_DEPTH_DISCARD = true;
constexpr bool ENABLE_MSAA_DEPTH_RESOLVE = false;
constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) { constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
if (color == std::array<float, 4>{0, 0, 0, 0}) { if (color == std::array<float, 4>{0, 0, 0, 0}) {
@ -2882,14 +2883,15 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
(!has_stencil || (stencil_mode != VK_RESOLVE_MODE_NONE && (!has_stencil || (stencil_mode != VK_RESOLVE_MODE_NONE &&
(runtime.device.IsIndependentResolveSupported() || (runtime.device.IsIndependentResolveSupported() ||
depth_mode == stencil_mode))); depth_mode == stencil_mode)));
const bool do_resolve_depth =
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler() &&
runtime.device.IsKhrDynamicRenderingSupported() && resolve_modes_compatible;
const bool msaa_depth =
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler();
const bool do_resolve_depth = ENABLE_MSAA_DEPTH_RESOLVE && msaa_depth &&
runtime.device.IsKhrDynamicRenderingSupported() &&
resolve_modes_compatible;
discard_msaa_color = discard_msaa_color =
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color; ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
discard_msaa_depth =
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD && do_resolve_depth;
discard_msaa_depth = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD && msaa_depth;
render_pass_key = renderpass_key; render_pass_key = renderpass_key;
render_pass_cache = &runtime.render_pass_cache; render_pass_cache = &runtime.render_pass_cache;

Loading…
Cancel
Save