mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 20:06:54 +02:00
Track depth and stencil attachment feedback across graphics stages
Co-authored-by: TarkusR <90155059+TarkusR@users.noreply.github.com>
This commit is contained in:
@@ -41,13 +41,42 @@ struct RenderDepthInfo {
|
|||||||
[[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const;
|
[[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline vk::ImageAspectFlags DepthFeedbackAspects(vk::ImageAspectFlags draw_writes,
|
||||||
|
const ImageViewInfo& target,
|
||||||
|
const ImageViewInfo& sampled) {
|
||||||
|
if (!ImageRangeOverlaps(target.base_level, target.level_count, sampled.base_level,
|
||||||
|
sampled.level_count) ||
|
||||||
|
!ImageRangeOverlaps(target.base_layer, target.layer_count, sampled.base_layer,
|
||||||
|
sampled.layer_count)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return draw_writes & sampled.aspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline vk::ImageAspectFlags DepthReadableAspects(vk::ImageLayout layout) {
|
||||||
|
switch (layout) {
|
||||||
|
case vk::ImageLayout::eDepthReadOnlyOptimal:
|
||||||
|
case vk::ImageLayout::eDepthReadOnlyStencilAttachmentOptimal:
|
||||||
|
return vk::ImageAspectFlagBits::eDepth;
|
||||||
|
case vk::ImageLayout::eStencilReadOnlyOptimal:
|
||||||
|
case vk::ImageLayout::eDepthAttachmentStencilReadOnlyOptimal:
|
||||||
|
return vk::ImageAspectFlagBits::eStencil;
|
||||||
|
case vk::ImageLayout::eDepthStencilReadOnlyOptimal:
|
||||||
|
case vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT:
|
||||||
|
case vk::ImageLayout::eGeneral:
|
||||||
|
return vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
|
inline vk::ImageLayout depth_attachment_layout(const RenderDepthInfo& depth) {
|
||||||
const auto available = ImageViewOps::DepthAspectMask(depth.desc.view_info.format);
|
const auto available = ImageViewOps::DepthAspectMask(depth.desc.view_info.format);
|
||||||
const auto writes = depth.AttachmentWriteAspects();
|
const auto writes = depth.AttachmentWriteAspects();
|
||||||
const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth);
|
const bool has_depth = static_cast<bool>(available & vk::ImageAspectFlagBits::eDepth);
|
||||||
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
|
const bool has_stencil = static_cast<bool>(available & vk::ImageAspectFlagBits::eStencil);
|
||||||
// LoadOp clears are separate from guest depth writes.
|
// The attachment layout must permit load clears as well as draw writes.
|
||||||
const bool depth_write = depth.depth_write_enable;
|
const bool depth_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eDepth);
|
||||||
const bool stencil_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eStencil);
|
const bool stencil_write = static_cast<bool>(writes & vk::ImageAspectFlagBits::eStencil);
|
||||||
if (!has_stencil) {
|
if (!has_stencil) {
|
||||||
return depth_write ? vk::ImageLayout::eDepthAttachmentOptimal
|
return depth_write ? vk::ImageLayout::eDepthAttachmentOptimal
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "graphics/host_gpu/hostMemory.h"
|
#include "graphics/host_gpu/hostMemory.h"
|
||||||
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
#include "graphics/host_gpu/renderer/colorRenderTarget.h"
|
||||||
#include "graphics/host_gpu/renderer/debug.h"
|
#include "graphics/host_gpu/renderer/debug.h"
|
||||||
|
#include "graphics/host_gpu/renderer/depthRenderTarget.h"
|
||||||
#include "graphics/host_gpu/renderer/image/imageView.h"
|
#include "graphics/host_gpu/renderer/image/imageView.h"
|
||||||
#include "graphics/host_gpu/renderer/image/textureCommon.h"
|
#include "graphics/host_gpu/renderer/image/textureCommon.h"
|
||||||
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
#include "graphics/host_gpu/renderer/pipeline/shaderResourceBarrier.h"
|
||||||
@@ -989,19 +990,7 @@ void RenderExecutor::CommitBindings(CommandBuffer& buffer,
|
|||||||
std::ranges::find(image.views, binding.image_view, &CachedImageView::view);
|
std::ranges::find(image.views, binding.image_view, &CachedImageView::view);
|
||||||
EXIT_IF(storage || host_view == image.views.end());
|
EXIT_IF(storage || host_view == image.views.end());
|
||||||
const auto aspect = host_view->info.aspect;
|
const auto aspect = host_view->info.aspect;
|
||||||
const bool depth_feedback =
|
if (aspect & ~DepthReadableAspects(layout)) {
|
||||||
layout == vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT &&
|
|
||||||
program.stage == ShaderType::Pixel;
|
|
||||||
const bool depth_read =
|
|
||||||
depth_feedback || layout == vk::ImageLayout::eDepthReadOnlyOptimal ||
|
|
||||||
layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal ||
|
|
||||||
layout == vk::ImageLayout::eDepthReadOnlyStencilAttachmentOptimal;
|
|
||||||
const bool stencil_read =
|
|
||||||
layout == vk::ImageLayout::eStencilReadOnlyOptimal ||
|
|
||||||
layout == vk::ImageLayout::eDepthStencilReadOnlyOptimal ||
|
|
||||||
layout == vk::ImageLayout::eDepthAttachmentStencilReadOnlyOptimal;
|
|
||||||
if ((aspect & vk::ImageAspectFlagBits::eDepth && !depth_read) ||
|
|
||||||
(aspect & vk::ImageAspectFlagBits::eStencil && !stencil_read)) {
|
|
||||||
EXIT("sampling a writable depth/stencil attachment aspect\n");
|
EXIT("sampling a writable depth/stencil attachment aspect\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ private:
|
|||||||
bool primitive_restart_enable);
|
bool primitive_restart_enable);
|
||||||
[[nodiscard]] RenderState AcquireRenderTargets(CommandBuffer& buffer, RenderColorInfo* colors,
|
[[nodiscard]] RenderState AcquireRenderTargets(CommandBuffer& buffer, RenderColorInfo* colors,
|
||||||
uint32_t color_count, RenderDepthInfo& depth,
|
uint32_t color_count, RenderDepthInfo& depth,
|
||||||
const std::optional<PreparedBindings>& pixel = std::nullopt);
|
vk::ImageAspectFlags& feedback_aspects,
|
||||||
|
std::span<PreparedBindings* const> stages = {});
|
||||||
[[nodiscard]] bool ResolveColorTargets(CommandBuffer& buffer,
|
[[nodiscard]] bool ResolveColorTargets(CommandBuffer& buffer,
|
||||||
uint32_t render_target_slice_offset);
|
uint32_t render_target_slice_offset);
|
||||||
void BindImage(ImageId id, bool storage);
|
void BindImage(ImageId id, bool storage);
|
||||||
|
|||||||
@@ -453,8 +453,10 @@ struct DrawCallInfo {
|
|||||||
|
|
||||||
RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderColorInfo* colors,
|
RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderColorInfo* colors,
|
||||||
uint32_t color_count, RenderDepthInfo& depth,
|
uint32_t color_count, RenderDepthInfo& depth,
|
||||||
const std::optional<PreparedBindings>& pixel) {
|
vk::ImageAspectFlags& feedback_aspects,
|
||||||
|
std::span<PreparedBindings* const> stages) {
|
||||||
EXIT_IF(colors == nullptr || color_count > RENDER_COLOR_ATTACHMENTS_MAX);
|
EXIT_IF(colors == nullptr || color_count > RENDER_COLOR_ATTACHMENTS_MAX);
|
||||||
|
feedback_aspects = {};
|
||||||
auto& cache = m_context.GetTextureCache();
|
auto& cache = m_context.GetTextureCache();
|
||||||
RenderState state {};
|
RenderState state {};
|
||||||
state.width = std::numeric_limits<uint32_t>::max();
|
state.width = std::numeric_limits<uint32_t>::max();
|
||||||
@@ -529,28 +531,29 @@ RenderState RenderExecutor::AcquireRenderTargets(CommandBuffer& buffer, RenderCo
|
|||||||
image.info.data.address, depth.desc.view_info.base_layer,
|
image.info.data.address, depth.desc.view_info.base_layer,
|
||||||
depth.desc.view_info.layer_count);
|
depth.desc.view_info.layer_count);
|
||||||
EXIT_IF(image_view == nullptr || image.backing.samples != depth.desc.info.samples);
|
EXIT_IF(image_view == nullptr || image.backing.samples != depth.desc.info.samples);
|
||||||
const bool feedback = depth.depth_write_enable && pixel &&
|
const auto draw_writes = depth.AttachmentWriteAspects();
|
||||||
std::ranges::any_of(pixel->images, [&](const TextureBinding& binding) {
|
vk::ImageAspectFlags sampled_aspects;
|
||||||
if (binding.image_id != depth.image_id ||
|
for (const auto* stage: stages) {
|
||||||
binding.desc.type != TextureCache::BindingType::Texture) {
|
for (const auto& binding: stage->images) {
|
||||||
return false;
|
if (binding.image_id != depth.image_id ||
|
||||||
}
|
binding.desc.type != TextureCache::BindingType::Texture) continue;
|
||||||
const auto native =
|
const auto native =
|
||||||
std::ranges::find(image.views, binding.image_view, &CachedImageView::view);
|
std::ranges::find(image.views, binding.image_view, &CachedImageView::view);
|
||||||
EXIT_IF(native == image.views.end());
|
EXIT_IF(native == image.views.end());
|
||||||
const auto& sampled = native->info;
|
sampled_aspects |= native->info.aspect;
|
||||||
const auto& target = depth.desc.view_info;
|
feedback_aspects |= DepthFeedbackAspects(draw_writes, depth.desc.view_info,
|
||||||
return (sampled.aspect & vk::ImageAspectFlagBits::eDepth) &&
|
native->info);
|
||||||
ImageRangeOverlaps(sampled.base_level, sampled.level_count,
|
}
|
||||||
target.base_level, target.level_count) &&
|
}
|
||||||
ImageRangeOverlaps(sampled.base_layer, sampled.layer_count,
|
if (feedback_aspects && !m_context.GetGraphics().attachment_feedback_loop_enabled) {
|
||||||
target.base_layer, target.layer_count);
|
|
||||||
});
|
|
||||||
if (feedback && !m_context.GetGraphics().attachment_feedback_loop_enabled) {
|
|
||||||
EXIT("depth attachment feedback loop is not supported by the host\n");
|
EXIT("depth attachment feedback loop is not supported by the host\n");
|
||||||
}
|
}
|
||||||
const auto layout = feedback ? vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT
|
auto layout = depth_attachment_layout(depth);
|
||||||
: depth_attachment_layout(depth);
|
if (sampled_aspects & ~DepthReadableAspects(layout)) {
|
||||||
|
layout = m_context.GetGraphics().attachment_feedback_loop_enabled
|
||||||
|
? vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT
|
||||||
|
: vk::ImageLayout::eGeneral;
|
||||||
|
}
|
||||||
// The attachment store writes even when guest depth/stencil tests do not.
|
// The attachment store writes even when guest depth/stencil tests do not.
|
||||||
const auto access = vk::AccessFlagBits2::eDepthStencilAttachmentRead |
|
const auto access = vk::AccessFlagBits2::eDepthStencilAttachmentRead |
|
||||||
vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
|
vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
|
||||||
@@ -1100,9 +1103,10 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
|||||||
std::span {state.color_info, state.color_count}, state.depth_info, vertex_stages, buffer,
|
std::span {state.color_info, state.color_count}, state.depth_info, vertex_stages, buffer,
|
||||||
state.ps_active ? &state.ps_input_info : nullptr, topology, primitive_restart_enable,
|
state.ps_active ? &state.ps_input_info : nullptr, topology, primitive_restart_enable,
|
||||||
state.programs);
|
state.programs);
|
||||||
|
vk::ImageAspectFlags feedback_aspects;
|
||||||
const auto rendering =
|
const auto rendering =
|
||||||
AcquireRenderTargets(buffer, state.color_info, state.color_count, state.depth_info,
|
AcquireRenderTargets(buffer, state.color_info, state.color_count, state.depth_info,
|
||||||
bindings.pixel);
|
feedback_aspects, stages);
|
||||||
|
|
||||||
// Resource preparation above may synchronously finish and restart the scheduler. From this
|
// Resource preparation above may synchronously finish and restart the scheduler. From this
|
||||||
// point onward, every operation targets the current command buffer and cannot touch guest
|
// point onward, every operation targets the current command buffer and cannot touch guest
|
||||||
@@ -1134,11 +1138,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
|||||||
|
|
||||||
SetGraphicsDynamicParams(buffer, vk_buffer, vertex_stages.back(), state.depth_info, rendering);
|
SetGraphicsDynamicParams(buffer, vk_buffer, vertex_stages.back(), state.depth_info, rendering);
|
||||||
if (m_context.GetGraphics().attachment_feedback_loop_enabled) {
|
if (m_context.GetGraphics().attachment_feedback_loop_enabled) {
|
||||||
vk_buffer.setAttachmentFeedbackLoopEnableEXT(
|
vk_buffer.setAttachmentFeedbackLoopEnableEXT(feedback_aspects);
|
||||||
rendering.depth_stencil_attachment.image_layout ==
|
|
||||||
vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT
|
|
||||||
? vk::ImageAspectFlags {vk::ImageAspectFlagBits::eDepth}
|
|
||||||
: vk::ImageAspectFlags {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDrawPhase(draw.Name(), "BeginRendering");
|
LogDrawPhase(draw.Name(), "BeginRendering");
|
||||||
|
|||||||
@@ -543,8 +543,15 @@ struct RenderExecutorTestAccess {
|
|||||||
RenderColorInfo *colors,
|
RenderColorInfo *colors,
|
||||||
uint32_t color_count,
|
uint32_t color_count,
|
||||||
RenderDepthInfo &depth,
|
RenderDepthInfo &depth,
|
||||||
const std::optional<PreparedBindings> &pixel = std::nullopt) {
|
std::span<PreparedBindings *const> stages = {},
|
||||||
return executor.AcquireRenderTargets(buffer, colors, color_count, depth, pixel);
|
vk::ImageAspectFlags *feedback_out = nullptr) {
|
||||||
|
vk::ImageAspectFlags feedback;
|
||||||
|
auto state = executor.AcquireRenderTargets(buffer, colors, color_count, depth,
|
||||||
|
feedback, stages);
|
||||||
|
if (feedback_out != nullptr) {
|
||||||
|
*feedback_out = feedback;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ResetBindings(RenderExecutor &executor) {
|
static void ResetBindings(RenderExecutor &executor) {
|
||||||
@@ -10886,6 +10893,95 @@ public:
|
|||||||
"descriptor layouts were queried after a later mip transition "
|
"descriptor layouts were queried after a later mip transition "
|
||||||
"instead of being captured at each binding");
|
"instead of being captured at each binding");
|
||||||
|
|
||||||
|
auto disjoint_depth_desc = split_desc;
|
||||||
|
disjoint_depth_desc.type = BindingType::DepthTarget;
|
||||||
|
disjoint_depth_desc.info.data.address = base + 0xe00000;
|
||||||
|
disjoint_depth_desc.info.pixel_format = vk::Format::eD32Sfloat;
|
||||||
|
disjoint_depth_desc.info.guest_format = Prospero::BufferFormat::k32Float;
|
||||||
|
disjoint_depth_desc.view_info.format = vk::Format::eD32Sfloat;
|
||||||
|
disjoint_depth_desc.view_info.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||||
|
disjoint_depth_desc.view_info.level_count = 1;
|
||||||
|
disjoint_depth_desc.view_info.usage =
|
||||||
|
vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
const auto disjoint_depth_id = texture_cache.FindImage(disjoint_depth_desc);
|
||||||
|
auto disjoint_sampled_desc = disjoint_depth_desc;
|
||||||
|
disjoint_sampled_desc.type = BindingType::Texture;
|
||||||
|
disjoint_sampled_desc.view_info.base_level = 1;
|
||||||
|
disjoint_sampled_desc.view_info.usage = vk::ImageUsageFlagBits::eSampled;
|
||||||
|
const auto disjoint_sampled_view =
|
||||||
|
texture_cache.FindTexture(disjoint_depth_id, disjoint_sampled_desc);
|
||||||
|
RenderDepthInfo disjoint_depth{};
|
||||||
|
disjoint_depth.desc = disjoint_depth_desc;
|
||||||
|
disjoint_depth.image_id = disjoint_depth_id;
|
||||||
|
disjoint_depth.depth_test_enable = true;
|
||||||
|
disjoint_depth.depth_write_enable = true;
|
||||||
|
disjoint_depth.depth_compare_op = vk::CompareOp::eAlways;
|
||||||
|
PreparedBindings disjoint_binding{};
|
||||||
|
disjoint_binding.runtime = &sampled_runtime;
|
||||||
|
disjoint_binding.images.push_back(
|
||||||
|
{disjoint_depth_id, disjoint_sampled_view, disjoint_sampled_desc});
|
||||||
|
RenderExecutorTestAccess::BindRenderTarget(executor, disjoint_depth_id);
|
||||||
|
vk::ImageAspectFlags disjoint_feedback;
|
||||||
|
std::array<PreparedBindings *, 1> disjoint_stages{&disjoint_binding};
|
||||||
|
RenderColorInfo no_disjoint_color{};
|
||||||
|
const auto disjoint_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
|
executor, scheduler.Current(), &no_disjoint_color, 0, disjoint_depth,
|
||||||
|
disjoint_stages, &disjoint_feedback);
|
||||||
|
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
||||||
|
executor, scheduler.Current(), disjoint_binding));
|
||||||
|
const auto &disjoint_image = texture_cache.GetImage(disjoint_depth_id);
|
||||||
|
Require(name, "disjoint depth sampling during depth writes",
|
||||||
|
!disjoint_feedback &&
|
||||||
|
disjoint_rendering.depth_stencil_attachment.image_layout ==
|
||||||
|
vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT &&
|
||||||
|
disjoint_binding.images[0].layout ==
|
||||||
|
disjoint_rendering.depth_stencil_attachment.image_layout &&
|
||||||
|
disjoint_image.backing.state.layout ==
|
||||||
|
disjoint_rendering.depth_stencil_attachment.image_layout &&
|
||||||
|
disjoint_image.backing.subresource_states.empty(),
|
||||||
|
"disjoint sampling used inconsistent image layouts or enabled feedback");
|
||||||
|
RenderExecutorTestAccess::ResetBindings(executor);
|
||||||
|
|
||||||
|
auto overlapping_sampled_desc = disjoint_sampled_desc;
|
||||||
|
overlapping_sampled_desc.view_info.base_level = 0;
|
||||||
|
const auto overlapping_view = texture_cache.FindTexture(
|
||||||
|
disjoint_depth_id, overlapping_sampled_desc);
|
||||||
|
ShaderRecompiler::IR::Program depth_views_ir{};
|
||||||
|
depth_views_ir.stage = ShaderType::Pixel;
|
||||||
|
depth_views_ir.resource_tracking_complete = true;
|
||||||
|
depth_views_ir.info.images = {sampled_resource, sampled_resource};
|
||||||
|
allocate_bindings(depth_views_ir);
|
||||||
|
ShaderRecompiler::IR::CompiledShaderInfo depth_views_program{};
|
||||||
|
depth_views_program.stage = depth_views_ir.stage;
|
||||||
|
depth_views_program.info = std::move(depth_views_ir.info);
|
||||||
|
depth_views_program.bindings = std::move(depth_views_ir.bindings);
|
||||||
|
ShaderRecompiler::IR::ResourceSnapshot depth_views_snapshot;
|
||||||
|
ShaderStageRuntime depth_views_runtime{&depth_views_program, &depth_views_snapshot};
|
||||||
|
PreparedBindings depth_views_binding{};
|
||||||
|
depth_views_binding.runtime = &depth_views_runtime;
|
||||||
|
depth_views_binding.images.push_back(
|
||||||
|
{disjoint_depth_id, overlapping_view, overlapping_sampled_desc});
|
||||||
|
depth_views_binding.images.push_back(
|
||||||
|
{disjoint_depth_id, disjoint_sampled_view, disjoint_sampled_desc});
|
||||||
|
RenderExecutorTestAccess::BindRenderTarget(executor, disjoint_depth_id);
|
||||||
|
std::array<PreparedBindings *, 1> depth_views_stages{&depth_views_binding};
|
||||||
|
vk::ImageAspectFlags depth_views_feedback;
|
||||||
|
const auto depth_views_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
|
executor, scheduler.Current(), &no_disjoint_color, 0, disjoint_depth,
|
||||||
|
depth_views_stages, &depth_views_feedback);
|
||||||
|
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
||||||
|
executor, scheduler.Current(), depth_views_binding));
|
||||||
|
Require(name, "overlapping and disjoint depth views",
|
||||||
|
overlapping_view != nullptr &&
|
||||||
|
depth_views_feedback == vk::ImageAspectFlagBits::eDepth &&
|
||||||
|
depth_views_rendering.depth_stencil_attachment.image_layout ==
|
||||||
|
vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT &&
|
||||||
|
MakeImageInfo(depth_views_binding.images[0]).imageLayout ==
|
||||||
|
depth_views_rendering.depth_stencil_attachment.image_layout &&
|
||||||
|
MakeImageInfo(depth_views_binding.images[1]).imageLayout ==
|
||||||
|
depth_views_rendering.depth_stencil_attachment.image_layout,
|
||||||
|
"two depth views chose different descriptor layouts or feedback aspects");
|
||||||
|
|
||||||
Libs::LibKernel::Memory::WriteBacking(
|
Libs::LibKernel::Memory::WriteBacking(
|
||||||
storage_address, &storage_stale_value, sizeof(storage_stale_value));
|
storage_address, &storage_stale_value, sizeof(storage_stale_value));
|
||||||
texture_cache.ProcessDownloadImages();
|
texture_cache.ProcessDownloadImages();
|
||||||
@@ -11212,26 +11308,35 @@ public:
|
|||||||
executor, scheduler.Current(), bounds_depth);
|
executor, scheduler.Current(), bounds_depth);
|
||||||
auto bounds_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings(
|
auto bounds_bindings = RenderExecutorTestAccess::PrepareGraphicsBindings(
|
||||||
executor, bounds_vertex, bounds_pixel, true);
|
executor, bounds_vertex, bounds_pixel, true);
|
||||||
|
std::array<PreparedBindings *, 2> bounds_stages{
|
||||||
|
&bounds_bindings.vertex[0], &*bounds_bindings.pixel};
|
||||||
|
vk::ImageAspectFlags bounds_feedback;
|
||||||
const auto bounds_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
const auto bounds_rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
executor, scheduler.Current(), &no_color, 0, bounds_depth, bounds_bindings.pixel);
|
executor, scheduler.Current(), &no_color, 0, bounds_depth,
|
||||||
|
bounds_stages, &bounds_feedback);
|
||||||
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
||||||
executor, scheduler.Current(), bounds_bindings.vertex[0], *bounds_bindings.pixel));
|
executor, scheduler.Current(), bounds_bindings.vertex[0], *bounds_bindings.pixel));
|
||||||
const auto &vertex_depth = bounds_bindings.vertex[0].images[0];
|
const auto &vertex_depth = bounds_bindings.vertex[0].images[0];
|
||||||
const auto &pixel_depth = bounds_bindings.pixel->images[0];
|
const auto &pixel_depth = bounds_bindings.pixel->images[0];
|
||||||
constexpr auto readonly_layout = vk::ImageLayout::eDepthReadOnlyOptimal;
|
const auto expected_layout = pass == 0
|
||||||
Require(name, "deferred clear with sampled read-only depth bounds",
|
? vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT
|
||||||
|
: vk::ImageLayout::eDepthReadOnlyOptimal;
|
||||||
|
Require(name, "deferred clear with sampled depth bounds",
|
||||||
bounds_depth.image_id == depth_only.image_id &&
|
bounds_depth.image_id == depth_only.image_id &&
|
||||||
bounds_depth.depth_bounds_test_enable &&
|
bounds_depth.depth_bounds_test_enable &&
|
||||||
!bounds_depth.depth_write_enable &&
|
!bounds_depth.depth_write_enable &&
|
||||||
bounds_depth.depth_load_clear_enable == (pass == 0) &&
|
bounds_depth.depth_load_clear_enable == (pass == 0) &&
|
||||||
!texture_cache.IsMetaCleared(depth_only_htile_address, 0) &&
|
!texture_cache.IsMetaCleared(depth_only_htile_address, 0) &&
|
||||||
bounds_rendering.depth_stencil_attachment.image_layout == readonly_layout &&
|
bounds_feedback == (pass == 0
|
||||||
|
? vk::ImageAspectFlagBits::eDepth
|
||||||
|
: vk::ImageAspectFlags{}) &&
|
||||||
|
bounds_rendering.depth_stencil_attachment.image_layout == expected_layout &&
|
||||||
bounds_rendering.depth_stencil_attachment.depth_clear == (pass == 0) &&
|
bounds_rendering.depth_stencil_attachment.depth_clear == (pass == 0) &&
|
||||||
vertex_depth.image_id == depth_only.image_id &&
|
vertex_depth.image_id == depth_only.image_id &&
|
||||||
pixel_depth.image_id == depth_only.image_id &&
|
pixel_depth.image_id == depth_only.image_id &&
|
||||||
MakeImageInfo(vertex_depth).imageLayout == readonly_layout &&
|
MakeImageInfo(vertex_depth).imageLayout == expected_layout &&
|
||||||
MakeImageInfo(pixel_depth).imageLayout == readonly_layout,
|
MakeImageInfo(pixel_depth).imageLayout == expected_layout,
|
||||||
"deferred clear changed guest depth writes, sampled layouts, or repeated");
|
"a deferred clear sampled by vertex and pixel stages missed depth feedback");
|
||||||
scheduler.BeginRendering(bounds_rendering);
|
scheduler.BeginRendering(bounds_rendering);
|
||||||
scheduler.EndRendering();
|
scheduler.EndRendering();
|
||||||
RenderExecutorTestAccess::ResetBindings(executor);
|
RenderExecutorTestAccess::ResetBindings(executor);
|
||||||
@@ -11554,35 +11659,50 @@ public:
|
|||||||
auto shared_bindings =
|
auto shared_bindings =
|
||||||
RenderExecutorTestAccess::PrepareGraphicsBindings(
|
RenderExecutorTestAccess::PrepareGraphicsBindings(
|
||||||
executor, shared_depth_vertex, shared_depth_pixel, true);
|
executor, shared_depth_vertex, shared_depth_pixel, true);
|
||||||
|
auto& shared_image = texture_cache.GetImage(shared_depth.image_id);
|
||||||
|
auto stencil_view_info = shared_depth.desc.view_info;
|
||||||
|
stencil_view_info.aspect = vk::ImageAspectFlagBits::eStencil;
|
||||||
|
stencil_view_info.usage = vk::ImageUsageFlagBits::eSampled;
|
||||||
|
const auto stencil_view = shared_image.FindView(stencil_view_info);
|
||||||
|
auto& pixel_image = shared_bindings.pixel->images[0];
|
||||||
|
pixel_image.image_view = stencil_view;
|
||||||
|
pixel_image.desc.view_info = stencil_view_info;
|
||||||
|
std::array<PreparedBindings *, 2> shared_stages{
|
||||||
|
&shared_bindings.vertex[0], &*shared_bindings.pixel};
|
||||||
|
vk::ImageAspectFlags shared_feedback;
|
||||||
const auto shared_rendering =
|
const auto shared_rendering =
|
||||||
RenderExecutorTestAccess::AcquireRenderTargets(
|
RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
executor, scheduler.Current(), &no_color, 0, shared_depth, shared_bindings.pixel);
|
executor, scheduler.Current(), &no_color, 0, shared_depth,
|
||||||
|
shared_stages, &shared_feedback);
|
||||||
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
descriptor_pipelines.push_back(RenderExecutorTestAccess::CommitBindings(
|
||||||
executor, scheduler.Current(), shared_bindings.vertex[0],
|
executor, scheduler.Current(), shared_bindings.vertex[0],
|
||||||
*shared_bindings.pixel));
|
*shared_bindings.pixel));
|
||||||
const auto expected_layout =
|
const auto expected_layout =
|
||||||
stencil_write
|
stencil_write
|
||||||
? vk::ImageLayout::eDepthReadOnlyStencilAttachmentOptimal
|
? vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT
|
||||||
: vk::ImageLayout::eDepthStencilReadOnlyOptimal;
|
: vk::ImageLayout::eDepthStencilReadOnlyOptimal;
|
||||||
const auto expected_access =
|
const auto expected_access =
|
||||||
vk::AccessFlagBits2::eShaderRead |
|
vk::AccessFlagBits2::eShaderRead |
|
||||||
vk::AccessFlagBits2::eDepthStencilAttachmentRead |
|
vk::AccessFlagBits2::eDepthStencilAttachmentRead |
|
||||||
vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
|
vk::AccessFlagBits2::eDepthStencilAttachmentWrite;
|
||||||
const auto &shared_image = texture_cache.GetImage(shared_depth.image_id);
|
|
||||||
const auto &vertex_image = shared_bindings.vertex[0].images[0];
|
const auto &vertex_image = shared_bindings.vertex[0].images[0];
|
||||||
const auto &pixel_image = shared_bindings.pixel->images[0];
|
|
||||||
Require(name, "sampled depth and stencil attachment layout",
|
Require(name, "sampled depth and stencil attachment layout",
|
||||||
shared_depth.image_id == phased_depth.image_id &&
|
shared_depth.image_id == phased_depth.image_id &&
|
||||||
|
stencil_view != nullptr &&
|
||||||
|
shared_feedback == (stencil_write
|
||||||
|
? vk::ImageAspectFlagBits::eStencil
|
||||||
|
: vk::ImageAspectFlags{}) &&
|
||||||
vertex_image.image_id == shared_depth.image_id &&
|
vertex_image.image_id == shared_depth.image_id &&
|
||||||
pixel_image.image_id == shared_depth.image_id &&
|
pixel_image.image_id == shared_depth.image_id &&
|
||||||
|
pixel_image.image_view == stencil_view &&
|
||||||
MakeImageInfo(vertex_image).imageLayout == expected_layout &&
|
MakeImageInfo(vertex_image).imageLayout == expected_layout &&
|
||||||
MakeImageInfo(pixel_image).imageLayout == expected_layout &&
|
MakeImageInfo(pixel_image).imageLayout == expected_layout &&
|
||||||
shared_rendering.depth_stencil_attachment.image_layout ==
|
shared_rendering.depth_stencil_attachment.image_layout ==
|
||||||
expected_layout &&
|
expected_layout &&
|
||||||
shared_image.backing.state.layout == expected_layout &&
|
shared_image.backing.state.layout == expected_layout &&
|
||||||
shared_image.backing.state.access_mask == expected_access,
|
shared_image.backing.state.access_mask == expected_access,
|
||||||
"a shader alias replaced the depth/stencil attachment layout "
|
"stencil sampling and writes lost the feedback aspect, shared "
|
||||||
"or dropped an attachment access");
|
"layout, or attachment access");
|
||||||
scheduler.BeginRendering(shared_rendering);
|
scheduler.BeginRendering(shared_rendering);
|
||||||
scheduler.EndRendering();
|
scheduler.EndRendering();
|
||||||
RenderExecutorTestAccess::ResetBindings(executor);
|
RenderExecutorTestAccess::ResetBindings(executor);
|
||||||
@@ -13501,12 +13621,18 @@ public:
|
|||||||
!depth_feedback || bindings.pixel->images[0].image_id == depth.image_id,
|
!depth_feedback || bindings.pixel->images[0].image_id == depth.image_id,
|
||||||
"the fragment must sample the depth attachment's native image");
|
"the fragment must sample the depth attachment's native image");
|
||||||
auto &command = scheduler.Current();
|
auto &command = scheduler.Current();
|
||||||
|
vk::ImageAspectFlags feedback_aspects;
|
||||||
|
std::array<PreparedBindings *, 2> stages{
|
||||||
|
&bindings.vertex[0], &*bindings.pixel};
|
||||||
auto rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
auto rendering = RenderExecutorTestAccess::AcquireRenderTargets(
|
||||||
executor, command, &color, 1, depth, bindings.pixel);
|
executor, command, &color, 1, depth, stages, &feedback_aspects);
|
||||||
const bool feedback_enabled = rendering.depth_stencil_attachment.image_layout ==
|
const bool feedback_enabled = rendering.depth_stencil_attachment.image_layout ==
|
||||||
vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT;
|
vk::ImageLayout::eAttachmentFeedbackLoopOptimalEXT;
|
||||||
Require(name, "per-draw depth feedback",
|
Require(name, "per-draw depth feedback",
|
||||||
feedback_enabled == (depth_feedback && depth.depth_write_enable),
|
feedback_enabled == (depth_feedback && depth.depth_write_enable) &&
|
||||||
|
feedback_aspects == (feedback_enabled
|
||||||
|
? vk::ImageAspectFlagBits::eDepth
|
||||||
|
: vk::ImageAspectFlags{}),
|
||||||
"feedback was not selected only for an overlapping fragment depth read/write");
|
"feedback was not selected only for an overlapping fragment depth read/write");
|
||||||
RenderExecutorTestAccess::CommitBindings(
|
RenderExecutorTestAccess::CommitBindings(
|
||||||
executor, command, selected, bindings.vertex[0], *bindings.pixel);
|
executor, command, selected, bindings.vertex[0], *bindings.pixel);
|
||||||
@@ -13539,9 +13665,7 @@ public:
|
|||||||
}
|
}
|
||||||
const vk::Bool32 write = true;
|
const vk::Bool32 write = true;
|
||||||
cmd.setColorWriteEnableEXT(1, &write);
|
cmd.setColorWriteEnableEXT(1, &write);
|
||||||
cmd.setAttachmentFeedbackLoopEnableEXT(
|
cmd.setAttachmentFeedbackLoopEnableEXT(feedback_aspects);
|
||||||
feedback_enabled ? vk::ImageAspectFlags{vk::ImageAspectFlagBits::eDepth}
|
|
||||||
: vk::ImageAspectFlags{});
|
|
||||||
const vk::DeviceSize offset = 0;
|
const vk::DeviceSize offset = 0;
|
||||||
cmd.bindVertexBuffers(0, 1, &buffer.buffer, &offset);
|
cmd.bindVertexBuffers(0, 1, &buffer.buffer, &offset);
|
||||||
cmd.draw(vertex_count, 1, 0, 0);
|
cmd.draw(vertex_count, 1, 0, 0);
|
||||||
@@ -31083,6 +31207,81 @@ void CheckDepthAttachmentWrites() {
|
|||||||
std::printf("[host] %-32s ok\n", "DepthAttachmentWrites");
|
std::printf("[host] %-32s ok\n", "DepthAttachmentWrites");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckDepthFeedbackAspects() {
|
||||||
|
RenderDepthInfo target{};
|
||||||
|
target.desc.view_info.format = vk::Format::eD32SfloatS8Uint;
|
||||||
|
target.desc.view_info.base_level = 1;
|
||||||
|
target.desc.view_info.level_count = 2;
|
||||||
|
target.desc.view_info.base_layer = 3;
|
||||||
|
target.desc.view_info.layer_count = 2;
|
||||||
|
target.depth_test_enable = true;
|
||||||
|
target.depth_write_enable = true;
|
||||||
|
target.depth_compare_op = vk::CompareOp::eAlways;
|
||||||
|
target.stencil_test_enable = true;
|
||||||
|
target.stencil_front = {vk::StencilOp::eKeep, vk::StencilOp::eReplace,
|
||||||
|
vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0xff, 0xff, 0};
|
||||||
|
target.stencil_back = target.stencil_front;
|
||||||
|
|
||||||
|
auto sampled = target.desc.view_info;
|
||||||
|
const auto feedback = [&](const ImageViewInfo& view) {
|
||||||
|
return DepthFeedbackAspects(target.AttachmentWriteAspects(),
|
||||||
|
target.desc.view_info, view);
|
||||||
|
};
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||||
|
Require("DepthFeedbackAspects", "sampled writable depth",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eDepth,
|
||||||
|
"overlapping depth sampling did not request depth feedback");
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eStencil;
|
||||||
|
Require("DepthFeedbackAspects", "sampled writable stencil",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eStencil,
|
||||||
|
"overlapping stencil sampling did not request stencil feedback");
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil;
|
||||||
|
Require("DepthFeedbackAspects", "both writable aspects",
|
||||||
|
feedback(sampled) == sampled.aspect,
|
||||||
|
"combined depth/stencil sampling lost a writable aspect");
|
||||||
|
|
||||||
|
target.depth_write_enable = false;
|
||||||
|
Require("DepthFeedbackAspects", "read-only depth",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eStencil,
|
||||||
|
"read-only depth was included in stencil feedback");
|
||||||
|
target.depth_write_enable = true;
|
||||||
|
target.stencil_test_enable = false;
|
||||||
|
Require("DepthFeedbackAspects", "read-only stencil",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eDepth,
|
||||||
|
"read-only stencil was included in depth feedback");
|
||||||
|
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eStencil;
|
||||||
|
Require("DepthFeedbackAspects", "sampled read-only aspect",
|
||||||
|
!feedback(sampled),
|
||||||
|
"sampling a read-only stencil requested feedback for depth writes");
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||||
|
sampled.base_level = 3;
|
||||||
|
Require("DepthFeedbackAspects", "disjoint mip",
|
||||||
|
!feedback(sampled),
|
||||||
|
"disjoint mip ranges requested depth feedback");
|
||||||
|
sampled.base_level = 2;
|
||||||
|
sampled.base_layer = 5;
|
||||||
|
Require("DepthFeedbackAspects", "disjoint layer",
|
||||||
|
!feedback(sampled),
|
||||||
|
"disjoint layer ranges requested depth feedback");
|
||||||
|
sampled.base_layer = 4;
|
||||||
|
Require("DepthFeedbackAspects", "overlapping range boundary",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eDepth,
|
||||||
|
"overlapping mip and layer boundaries missed depth feedback");
|
||||||
|
target.depth_write_enable = false;
|
||||||
|
target.depth_load_clear_enable = true;
|
||||||
|
Require("DepthFeedbackAspects", "depth clear only",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eDepth,
|
||||||
|
"a sampled depth attachment clear missed feedback");
|
||||||
|
target.depth_load_clear_enable = false;
|
||||||
|
target.stencil_clear_enable = true;
|
||||||
|
sampled.aspect = vk::ImageAspectFlagBits::eStencil;
|
||||||
|
Require("DepthFeedbackAspects", "stencil clear only",
|
||||||
|
feedback(sampled) == vk::ImageAspectFlagBits::eStencil,
|
||||||
|
"a sampled stencil attachment clear missed feedback");
|
||||||
|
std::printf("[host] %-32s ok\n", "DepthFeedbackAspects");
|
||||||
|
}
|
||||||
|
|
||||||
void CheckDynamicRenderingState() {
|
void CheckDynamicRenderingState() {
|
||||||
RenderState first{};
|
RenderState first{};
|
||||||
first.width = 64;
|
first.width = 64;
|
||||||
@@ -31130,10 +31329,10 @@ void CheckDynamicRenderingState() {
|
|||||||
vk::ImageLayout::eDepthStencilReadOnlyOptimal,
|
vk::ImageLayout::eDepthStencilReadOnlyOptimal,
|
||||||
"fully read-only depth/stencil used a writable layout");
|
"fully read-only depth/stencil used a writable layout");
|
||||||
attachment.depth_load_clear_enable = true;
|
attachment.depth_load_clear_enable = true;
|
||||||
Require("DynamicRenderingState", "read-only deferred depth clear",
|
Require("DynamicRenderingState", "deferred depth clear layout",
|
||||||
depth_attachment_layout(attachment) ==
|
depth_attachment_layout(attachment) ==
|
||||||
vk::ImageLayout::eDepthStencilReadOnlyOptimal,
|
vk::ImageLayout::eDepthAttachmentStencilReadOnlyOptimal,
|
||||||
"a load clear changed the guest depth-write layout");
|
"a depth load clear used a read-only attachment layout");
|
||||||
attachment.depth_test_enable = true;
|
attachment.depth_test_enable = true;
|
||||||
attachment.depth_write_enable = true;
|
attachment.depth_write_enable = true;
|
||||||
Require("DynamicRenderingState", "depth-write stencil-read layout",
|
Require("DynamicRenderingState", "depth-write stencil-read layout",
|
||||||
@@ -33153,6 +33352,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--image-overlap-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--image-overlap-only") == 0) {
|
||||||
CheckDepthAttachmentWrites();
|
CheckDepthAttachmentWrites();
|
||||||
|
CheckDepthFeedbackAspects();
|
||||||
CheckDynamicRenderingState();
|
CheckDynamicRenderingState();
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
vulkan.CheckRasterization(false);
|
vulkan.CheckRasterization(false);
|
||||||
@@ -33170,6 +33370,12 @@ int main(int argc, char **argv) {
|
|||||||
CheckEmbeddedFetchVertexOffset();
|
CheckEmbeddedFetchVertexOffset();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--depth-feedback-only") == 0) {
|
||||||
|
CheckDepthAttachmentWrites();
|
||||||
|
CheckDepthFeedbackAspects();
|
||||||
|
CheckDynamicRenderingState();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--polygon-mode-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--polygon-mode-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
vulkan.CheckRasterization(false);
|
vulkan.CheckRasterization(false);
|
||||||
@@ -33325,6 +33531,7 @@ int main(int argc, char **argv) {
|
|||||||
CheckPs5DepthRegisterDecoding();
|
CheckPs5DepthRegisterDecoding();
|
||||||
CheckDepthHtileStencilCompatibility();
|
CheckDepthHtileStencilCompatibility();
|
||||||
CheckDepthAttachmentWrites();
|
CheckDepthAttachmentWrites();
|
||||||
|
CheckDepthFeedbackAspects();
|
||||||
CheckDynamicRenderingState();
|
CheckDynamicRenderingState();
|
||||||
CheckDepthTargetFootprints();
|
CheckDepthTargetFootprints();
|
||||||
CheckSlotVectorLifetime();
|
CheckSlotVectorLifetime();
|
||||||
@@ -33334,6 +33541,7 @@ int main(int argc, char **argv) {
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
CheckShaderRecompilerFatalContracts();
|
CheckShaderRecompilerFatalContracts();
|
||||||
|
CheckDepthFeedbackAspects();
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
#endif
|
#endif
|
||||||
CheckImageSamplerSpecialization();
|
CheckImageSamplerSpecialization();
|
||||||
|
|||||||
Reference in New Issue
Block a user