mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 05:16:56 +01:00
graphics: execute DB_RENDER_OVERRIDE depth and stencil copies
This commit is contained in:
@@ -315,8 +315,17 @@ static void HwCtxSetDepthBoundsRegister(CommandProcessor& cp, uint32_t cmd_offse
|
||||
}
|
||||
}
|
||||
|
||||
static void HwCtxIgnoreDepthMetadataRegister([[maybe_unused]] uint32_t cmd_offset,
|
||||
[[maybe_unused]] uint32_t value) {}
|
||||
static void HwCtxSetDepthMetadataRegister(CommandProcessor& cp, uint32_t cmd_offset,
|
||||
uint32_t value) {
|
||||
if (cmd_offset == Pm4::DB_RENDER_OVERRIDE) {
|
||||
HW::DepthRenderOverride control;
|
||||
control.force_z_valid = (value & 0x20000000u) != 0;
|
||||
control.force_z_dirty = (value & 0x08000000u) != 0;
|
||||
control.force_stencil_valid = (value & 0x40000000u) != 0;
|
||||
control.force_stencil_dirty = (value & 0x10000000u) != 0;
|
||||
cp.GetCtx().SetDepthRenderOverride(control);
|
||||
}
|
||||
}
|
||||
|
||||
static void HwCtxIgnoreFovWindow([[maybe_unused]] uint32_t value) {}
|
||||
|
||||
@@ -389,7 +398,7 @@ KYTY_HW_CTX_PARSER(HwCtxSetDepthMetadataRegisters) {
|
||||
auto num_values = KYTY_PM4_LEN(cmd_id) - 2u;
|
||||
|
||||
for (uint32_t i = 0; i < num_values; i++) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset + i, buffer[i]);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset + i, buffer[i]);
|
||||
}
|
||||
|
||||
return num_values;
|
||||
@@ -3003,28 +3012,28 @@ void GraphicsInitJmpTablesCxIndirect() {
|
||||
HwCtxIgnoreCbDccControl(value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::DB_COUNT_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
for (auto cmd_offset = Pm4::DB_SRESULTS_COMPARE_STATE0;
|
||||
cmd_offset <= Pm4::DB_SRESULTS_COMPARE_STATE1; cmd_offset++) {
|
||||
g_hw_ctx_indirect_func[cmd_offset] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
}
|
||||
g_hw_ctx_indirect_func[Pm4::DB_RENDER_OVERRIDE] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::DB_RENDER_OVERRIDE2] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::DB_DFSM_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::DB_RMI_L2_CACHE_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::CB_RMI_GL2_CACHE_CONTROL] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreDepthMetadataRegister(cmd_offset, value);
|
||||
HwCtxSetDepthMetadataRegister(cp, cmd_offset, value);
|
||||
};
|
||||
g_hw_ctx_indirect_func[Pm4::TA_BC_BASE_ADDR] = [](KYTY_HW_CTX_INDIRECT_ARGS) {
|
||||
HwCtxIgnoreBorderColorTableAddr(cmd_offset, value);
|
||||
|
||||
@@ -202,6 +202,13 @@ struct RenderControl {
|
||||
uint8_t copy_sample = 0;
|
||||
};
|
||||
|
||||
struct DepthRenderOverride {
|
||||
bool force_z_valid = false;
|
||||
bool force_z_dirty = false;
|
||||
bool force_stencil_valid = false;
|
||||
bool force_stencil_dirty = false;
|
||||
};
|
||||
|
||||
struct GdsOaCounter {
|
||||
uint32_t counter = 0;
|
||||
uint32_t address = 0;
|
||||
@@ -809,6 +816,12 @@ public:
|
||||
void SetClipControl(const ClipControl& control) { m_clip_control = control; }
|
||||
[[nodiscard]] const RenderControl& GetRenderControl() const { return m_render_control; }
|
||||
void SetRenderControl(const RenderControl& control) { m_render_control = control; }
|
||||
[[nodiscard]] const DepthRenderOverride& GetDepthRenderOverride() const {
|
||||
return m_depth_render_override;
|
||||
}
|
||||
void SetDepthRenderOverride(const DepthRenderOverride& control) {
|
||||
m_depth_render_override = control;
|
||||
}
|
||||
[[nodiscard]] const DepthControl& GetDepthControl() const { return m_depth_control; }
|
||||
void SetDepthControl(const DepthControl& control) { m_depth_control = control; }
|
||||
[[nodiscard]] const ModeControl& GetModeControl() const { return m_mode_control; }
|
||||
@@ -904,15 +917,16 @@ private:
|
||||
|
||||
uint32_t m_shader_stages = 0;
|
||||
|
||||
DepthRenderTarget m_depth_render_target;
|
||||
RenderControl m_render_control;
|
||||
DepthControl m_depth_control;
|
||||
StencilControl m_stencil_control;
|
||||
StencilMask m_stencil_mask;
|
||||
float m_depth_clear_value = 0.0f;
|
||||
float m_depth_bounds_min = 0.0f;
|
||||
float m_depth_bounds_max = 1.0f;
|
||||
uint8_t m_stencil_clear_value = 0;
|
||||
DepthRenderTarget m_depth_render_target;
|
||||
RenderControl m_render_control;
|
||||
DepthRenderOverride m_depth_render_override;
|
||||
DepthControl m_depth_control;
|
||||
StencilControl m_stencil_control;
|
||||
StencilMask m_stencil_mask;
|
||||
float m_depth_clear_value = 0.0f;
|
||||
float m_depth_bounds_min = 0.0f;
|
||||
float m_depth_bounds_max = 1.0f;
|
||||
uint8_t m_stencil_clear_value = 0;
|
||||
|
||||
ModeControl m_mode_control;
|
||||
PolyOffset m_poly_offset;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/guest_gpu/tile.h"
|
||||
#include "graphics/host_gpu/graphicContext.h"
|
||||
#include "graphics/host_gpu/renderer/commandScheduler.h"
|
||||
#include "graphics/host_gpu/renderer/debug.h"
|
||||
#include "graphics/host_gpu/renderer/image/imageView.h"
|
||||
#include "graphics/host_gpu/renderer/image/textureCommon.h"
|
||||
@@ -96,51 +97,17 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
|
||||
return vk::Format::eUndefined;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepthInfo& r) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
const auto& hw = buffer.GetRegisters();
|
||||
const auto& z = hw.GetDepthRenderTarget();
|
||||
const auto& rc = hw.GetRenderControl();
|
||||
const auto& dc = hw.GetDepthControl();
|
||||
const auto& sc = hw.GetStencilControl();
|
||||
const auto& sm = hw.GetStencilMask();
|
||||
const bool has_stencil = z.stencil_info.format != Prospero::StencilFormat::kInvalid;
|
||||
const bool depth_active = dc.z_enable || dc.depth_bounds_enable ||
|
||||
rc.depth_clear_enable || rc.copy_depth_to_color;
|
||||
const bool stencil_active =
|
||||
has_stencil && (dc.stencil_enable || rc.stencil_clear_enable || rc.copy_stencil_to_color);
|
||||
if (!depth_active && !stencil_active) {
|
||||
return;
|
||||
}
|
||||
static TextureCache::ImageDesc MakeDepthTargetDesc(const CommandBuffer& buffer,
|
||||
const HW::DepthRenderTarget& z,
|
||||
bool write_buffer = false) {
|
||||
const bool has_stencil = z.stencil_info.format != Prospero::StencilFormat::kInvalid;
|
||||
const auto depth_address = write_buffer ? z.z_write_base_addr : z.z_read_base_addr;
|
||||
const auto stencil_address =
|
||||
write_buffer ? z.stencil_write_base_addr : z.stencil_read_base_addr;
|
||||
if (!z.z_info.HasValidTextureCompatibility() ||
|
||||
!z.stencil_info.HasValidTextureCompatibility()) {
|
||||
DepthFatal("invalid PS5 depth texture-compatibility encoding");
|
||||
}
|
||||
const bool attachment_unbound =
|
||||
z.z_info.format == Prospero::DepthFormat::kInvalid &&
|
||||
z.stencil_info.format == Prospero::StencilFormat::kInvalid && z.z_info.num_samples == 0 &&
|
||||
z.z_info.texture_compatibility == Prospero::TextureCompatiblePlaneCompression::kDisable &&
|
||||
!z.z_info.expclear_enabled && !z.z_info.partially_resident && z.z_info.max_mip_level == 0 &&
|
||||
z.stencil_info.texture_compatibility == Prospero::TextureCompatibleStencil::kDisable &&
|
||||
!z.stencil_info.expclear_enabled && !z.stencil_info.partially_resident &&
|
||||
z.depth_view.slice_start == 0 && z.depth_view.slice_max == 0 &&
|
||||
z.depth_view.current_mip_level == 0 && !z.depth_view.depth_write_disable &&
|
||||
!z.depth_view.stencil_write_disable && z.z_read_base_addr == 0 && z.z_write_base_addr == 0 &&
|
||||
z.stencil_read_base_addr == 0 && z.stencil_write_base_addr == 0 &&
|
||||
z.htile_data_base_addr == 0 &&
|
||||
// DB_DEPTH_SIZE_XY is independent state and may remain programmed after the attachment
|
||||
// formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its
|
||||
// presence alone must not manufacture a depth attachment.
|
||||
!z.z_info.htile_acceleration && z.shading_rate_encoding == 0 && z.size.x_max == 0 &&
|
||||
z.size.y_max == 0;
|
||||
if (attachment_unbound) {
|
||||
static std::atomic_bool logged = false;
|
||||
if (!logged.exchange(true, std::memory_order_relaxed)) {
|
||||
LOGF("DepthTarget: ignoring enabled depth/stencil state without a bound attachment\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
const bool has_htile = z.z_info.htile_acceleration;
|
||||
const bool unsupported_shading_rate_encoding =
|
||||
z.shading_rate_encoding > 1 || (z.shading_rate_encoding != 0 && !has_htile);
|
||||
@@ -158,23 +125,16 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth
|
||||
DepthFatal("invalid depth view: base=%u last=%u", z.depth_view.slice_start,
|
||||
z.depth_view.slice_max);
|
||||
}
|
||||
if (rc.copy_depth_to_color || rc.copy_stencil_to_color || rc.copy_centroid ||
|
||||
rc.copy_sample != 0 || z.z_info.expclear_enabled ||
|
||||
z.stencil_info.expclear_enabled || z.z_info.partially_resident ||
|
||||
if (z.z_info.expclear_enabled || z.stencil_info.expclear_enabled ||
|
||||
z.z_info.partially_resident ||
|
||||
z.stencil_info.partially_resident || z.z_info.max_mip_level != 0 ||
|
||||
z.depth_view.current_mip_level != 0 || unsupported_shading_rate_encoding ||
|
||||
z.z_read_base_addr == 0 ||
|
||||
(!z.depth_view.depth_write_disable && z.z_write_base_addr != z.z_read_base_addr) ||
|
||||
(z.z_read_base_addr & 0xffffu) != 0 ||
|
||||
dc.zfunc > static_cast<uint8_t>(vk::CompareOp::eAlways)) {
|
||||
depth_address == 0 || (depth_address & 0xffffu) != 0) {
|
||||
DepthFatal("unsupported depth register state");
|
||||
}
|
||||
if (has_stencil) {
|
||||
if (z.stencil_info.format != Prospero::StencilFormat::k8UInt || !htile_stencil_compat ||
|
||||
z.stencil_read_base_addr == 0 ||
|
||||
(!z.depth_view.stencil_write_disable &&
|
||||
z.stencil_write_base_addr != z.stencil_read_base_addr) ||
|
||||
(z.stencil_read_base_addr & 0xffffu) != 0) {
|
||||
stencil_address == 0 || (stencil_address & 0xffffu) != 0) {
|
||||
DepthFatal("unsupported stencil attachment state");
|
||||
}
|
||||
} else if (z.stencil_read_base_addr != 0 || z.stencil_write_base_addr != 0) {
|
||||
@@ -227,11 +187,92 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth
|
||||
const auto depth_backing_size = depth_size.size * view.image_layers;
|
||||
const auto stencil_backing_size = stencil_size.size * view.image_layers;
|
||||
const auto htile_backing_size = htile_size.size * view.image_layers;
|
||||
if (!GuestRange {z.z_read_base_addr, depth_backing_size}.Valid() ||
|
||||
(has_stencil && !GuestRange {z.stencil_read_base_addr, stencil_backing_size}.Valid()) ||
|
||||
if (!GuestRange {depth_address, depth_backing_size}.Valid() ||
|
||||
(has_stencil && !GuestRange {stencil_address, stencil_backing_size}.Valid()) ||
|
||||
(has_htile && !GuestRange {z.htile_data_base_addr, htile_backing_size}.Valid())) {
|
||||
DepthFatal("layered depth backing range is invalid");
|
||||
}
|
||||
TextureCache::ImageDesc desc {};
|
||||
desc.type = TextureCache::BindingType::DepthTarget;
|
||||
desc.info.data = {depth_address, depth_backing_size};
|
||||
desc.info.stencil =
|
||||
has_stencil ? GuestRange {stencil_address, stencil_backing_size} : GuestRange {};
|
||||
desc.info.pixel_format = format;
|
||||
desc.info.guest_format = guest_format;
|
||||
desc.info.type = Prospero::ImageType::kColor2D;
|
||||
desc.info.extent = {width, height, 1};
|
||||
desc.info.resources = {1, view.image_layers};
|
||||
desc.info.pitch = pitch;
|
||||
desc.info.bytes_per_block = bytes;
|
||||
desc.info.samples = samples;
|
||||
desc.info.tile_mode = Prospero::TileMode::kDepth;
|
||||
desc.info.mip_layout[0] = {0, depth_backing_size, pitch, height};
|
||||
desc.info.metadata.range =
|
||||
has_htile ? GuestRange {z.htile_data_base_addr, htile_backing_size} : GuestRange {};
|
||||
desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None;
|
||||
desc.info.metadata.stencil_compressed =
|
||||
has_stencil && has_htile && !z.stencil_info.htile_stencil_disabled;
|
||||
desc.view_info.format = format;
|
||||
desc.view_info.type =
|
||||
view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray;
|
||||
desc.view_info.aspect = ImageViewOps::DepthAspectMask(format);
|
||||
desc.view_info.base_level = 0;
|
||||
desc.view_info.level_count = 1;
|
||||
desc.view_info.base_layer = view.base_layer;
|
||||
desc.view_info.layer_count = view.layer_count;
|
||||
desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
return desc;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepthInfo& r) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
const auto& hw = buffer.GetRegisters();
|
||||
const auto& z = hw.GetDepthRenderTarget();
|
||||
const auto& rc = hw.GetRenderControl();
|
||||
const auto& dc = hw.GetDepthControl();
|
||||
const auto& sc = hw.GetStencilControl();
|
||||
const auto& sm = hw.GetStencilMask();
|
||||
const bool has_stencil = z.stencil_info.format != Prospero::StencilFormat::kInvalid;
|
||||
const bool depth_active = dc.z_enable || dc.depth_bounds_enable ||
|
||||
rc.depth_clear_enable || rc.copy_depth_to_color;
|
||||
const bool stencil_active =
|
||||
has_stencil && (dc.stencil_enable || rc.stencil_clear_enable || rc.copy_stencil_to_color);
|
||||
if (!depth_active && !stencil_active) {
|
||||
return;
|
||||
}
|
||||
const bool attachment_unbound =
|
||||
z.z_info.format == Prospero::DepthFormat::kInvalid &&
|
||||
z.stencil_info.format == Prospero::StencilFormat::kInvalid && z.z_info.num_samples == 0 &&
|
||||
z.z_info.texture_compatibility == Prospero::TextureCompatiblePlaneCompression::kDisable &&
|
||||
!z.z_info.expclear_enabled && !z.z_info.partially_resident && z.z_info.max_mip_level == 0 &&
|
||||
z.stencil_info.texture_compatibility == Prospero::TextureCompatibleStencil::kDisable &&
|
||||
!z.stencil_info.expclear_enabled && !z.stencil_info.partially_resident &&
|
||||
z.depth_view.slice_start == 0 && z.depth_view.slice_max == 0 &&
|
||||
z.depth_view.current_mip_level == 0 && !z.depth_view.depth_write_disable &&
|
||||
!z.depth_view.stencil_write_disable && z.z_read_base_addr == 0 && z.z_write_base_addr == 0 &&
|
||||
z.stencil_read_base_addr == 0 && z.stencil_write_base_addr == 0 &&
|
||||
z.htile_data_base_addr == 0 &&
|
||||
// DB_DEPTH_SIZE_XY is independent state and may remain programmed after the attachment
|
||||
// formats and addresses are unbound. A zero encoding is the valid 1x1 value, so its
|
||||
// presence alone must not manufacture a depth attachment.
|
||||
!z.z_info.htile_acceleration && z.shading_rate_encoding == 0 && z.size.x_max == 0 &&
|
||||
z.size.y_max == 0;
|
||||
if (attachment_unbound) {
|
||||
static std::atomic_bool logged = false;
|
||||
if (!logged.exchange(true, std::memory_order_relaxed)) {
|
||||
LOGF("DepthTarget: ignoring enabled depth/stencil state without a bound attachment\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (rc.copy_depth_to_color || rc.copy_stencil_to_color || rc.copy_centroid ||
|
||||
rc.copy_sample != 0 || dc.zfunc > static_cast<uint8_t>(vk::CompareOp::eAlways) ||
|
||||
(!z.depth_view.depth_write_disable && z.z_write_base_addr != z.z_read_base_addr) ||
|
||||
(has_stencil && !z.depth_view.stencil_write_disable &&
|
||||
z.stencil_write_base_addr != z.stencil_read_base_addr)) {
|
||||
DepthFatal("unsupported depth register state");
|
||||
}
|
||||
r.desc = MakeDepthTargetDesc(buffer, z);
|
||||
r.depth_clear_enable = rc.depth_clear_enable;
|
||||
r.depth_load_clear_enable = r.depth_clear_enable;
|
||||
r.depth_clear_value = hw.GetDepthClearValue();
|
||||
@@ -282,41 +323,73 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth
|
||||
r.stencil_dynamic_back = r.stencil_dynamic_front;
|
||||
}
|
||||
}
|
||||
TextureCache::ImageDesc desc {};
|
||||
desc.type = TextureCache::BindingType::DepthTarget;
|
||||
desc.info.data = {z.z_read_base_addr, depth_backing_size};
|
||||
desc.info.stencil =
|
||||
has_stencil ? GuestRange {z.stencil_read_base_addr, stencil_backing_size} : GuestRange {};
|
||||
desc.info.pixel_format = format;
|
||||
desc.info.guest_format = guest_format;
|
||||
desc.info.type = Prospero::ImageType::kColor2D;
|
||||
desc.info.extent = {width, height, 1};
|
||||
desc.info.resources = {1, view.image_layers};
|
||||
desc.info.pitch = pitch;
|
||||
desc.info.bytes_per_block = bytes;
|
||||
desc.info.samples = samples;
|
||||
desc.info.tile_mode = Prospero::TileMode::kDepth;
|
||||
desc.info.mip_layout[0] = {0, depth_backing_size, pitch, height};
|
||||
desc.info.metadata.range =
|
||||
has_htile ? GuestRange {z.htile_data_base_addr, htile_backing_size} : GuestRange {};
|
||||
desc.info.metadata.kind = has_htile ? ImageMetadataKind::Htile : ImageMetadataKind::None;
|
||||
desc.info.metadata.stencil_compressed =
|
||||
has_stencil && has_htile && !z.stencil_info.htile_stencil_disabled;
|
||||
desc.view_info.format = format;
|
||||
desc.view_info.type =
|
||||
view.layer_count == 1 ? vk::ImageViewType::e2D : vk::ImageViewType::e2DArray;
|
||||
desc.view_info.aspect = ImageViewOps::DepthAspectMask(format);
|
||||
desc.view_info.base_level = 0;
|
||||
desc.view_info.level_count = 1;
|
||||
desc.view_info.base_layer = view.base_layer;
|
||||
desc.view_info.layer_count = view.layer_count;
|
||||
desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||
r.desc = std::move(desc);
|
||||
auto& cache = m_context.GetTextureCache();
|
||||
r.image_id = cache.FindImage(r.desc);
|
||||
auto& cache = m_context.GetTextureCache();
|
||||
r.image_id = cache.FindImage(r.desc);
|
||||
BindRenderTarget(r.image_id);
|
||||
}
|
||||
|
||||
bool RenderExecutor::DepthStencilCopy(CommandBuffer& buffer) {
|
||||
const auto& hw = buffer.GetRegisters();
|
||||
const auto& z = hw.GetDepthRenderTarget();
|
||||
const auto& override = hw.GetDepthRenderOverride();
|
||||
if (hw.GetColorControl().mode != 0) {
|
||||
return false;
|
||||
}
|
||||
const bool depth_copy = override.force_z_dirty && override.force_z_valid &&
|
||||
z.z_info.format != Prospero::DepthFormat::kInvalid &&
|
||||
z.z_read_base_addr != 0 && z.z_write_base_addr != 0 &&
|
||||
z.z_read_base_addr != z.z_write_base_addr;
|
||||
const bool stencil_copy = override.force_stencil_dirty && override.force_stencil_valid &&
|
||||
z.stencil_info.format != Prospero::StencilFormat::kInvalid &&
|
||||
z.stencil_read_base_addr != 0 && z.stencil_write_base_addr != 0 &&
|
||||
z.stencil_read_base_addr != z.stencil_write_base_addr;
|
||||
if (!depth_copy && !stencil_copy) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto read_desc = MakeDepthTargetDesc(buffer, z);
|
||||
auto write_desc = MakeDepthTargetDesc(buffer, z, true);
|
||||
auto& cache = m_context.GetTextureCache();
|
||||
const auto read_id = cache.FindImage(read_desc);
|
||||
BindRenderTarget(read_id);
|
||||
const auto write_id = cache.FindImage(write_desc);
|
||||
BindRenderTarget(write_id);
|
||||
cache.UpdateImage(read_id);
|
||||
cache.UpdateImage(write_id);
|
||||
cache.MarkGpuWritten(write_id);
|
||||
auto& source = cache.GetImage(read_id);
|
||||
auto& destination = cache.GetImage(write_id);
|
||||
EXIT_IF(read_id == write_id || source.backing.format != destination.backing.format);
|
||||
|
||||
auto& scheduler = m_context.GetCommandScheduler();
|
||||
scheduler.EndRendering();
|
||||
const auto command = scheduler.Current().Handle();
|
||||
const ImageSubresourceRange range {read_desc.view_info.base_level, 1,
|
||||
read_desc.view_info.base_layer,
|
||||
read_desc.view_info.layer_count};
|
||||
source.Transit(vk::ImageLayout::eTransferSrcOptimal, vk::AccessFlagBits2::eTransferRead,
|
||||
range, command);
|
||||
destination.Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite,
|
||||
range, command);
|
||||
std::array<vk::ImageCopy, 2> regions {};
|
||||
uint32_t count = 0;
|
||||
for (const auto aspect: {vk::ImageAspectFlagBits::eDepth, vk::ImageAspectFlagBits::eStencil}) {
|
||||
if ((aspect == vk::ImageAspectFlagBits::eDepth && !depth_copy) ||
|
||||
(aspect == vk::ImageAspectFlagBits::eStencil && !stencil_copy)) {
|
||||
continue;
|
||||
}
|
||||
auto& region = regions[count++];
|
||||
region.srcSubresource = {aspect, range.base_level, range.base_layer,
|
||||
range.layer_count};
|
||||
region.dstSubresource = region.srcSubresource;
|
||||
region.extent = write_desc.info.extent;
|
||||
}
|
||||
command.copyImage(source.backing.image, vk::ImageLayout::eTransferSrcOptimal,
|
||||
destination.backing.image, vk::ImageLayout::eTransferDstOptimal,
|
||||
count, regions.data());
|
||||
return true;
|
||||
}
|
||||
|
||||
vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
|
||||
const auto format = desc.view_info.format;
|
||||
if (format == vk::Format::eUndefined) {
|
||||
|
||||
@@ -183,6 +183,7 @@ private:
|
||||
uint32_t render_target_slice_offset, uint32_t render_target_slot,
|
||||
bool ignore_target_mask = false, bool exact_format = false);
|
||||
void ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepthInfo& target);
|
||||
[[nodiscard]] bool DepthStencilCopy(CommandBuffer& buffer);
|
||||
[[nodiscard]] bool PrepareDrawRenderState(CommandBuffer& buffer,
|
||||
const DrawCallInfo& draw,
|
||||
uint32_t render_target_slice_offset,
|
||||
|
||||
@@ -1238,7 +1238,7 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumeMetadataColorOperation(buffer)) {
|
||||
if (ConsumeMetadataColorOperation(buffer) || DepthStencilCopy(buffer)) {
|
||||
ResetBindings();
|
||||
return;
|
||||
}
|
||||
@@ -1354,7 +1354,7 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumeMetadataColorOperation(buffer)) {
|
||||
if (ConsumeMetadataColorOperation(buffer) || DepthStencilCopy(buffer)) {
|
||||
ResetBindings();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -504,6 +504,10 @@ struct RenderExecutorTestAccess {
|
||||
executor.ResolveRenderDepthTarget(buffer, depth);
|
||||
}
|
||||
|
||||
static bool DepthStencilCopy(RenderExecutor &executor, CommandBuffer &buffer) {
|
||||
return executor.DepthStencilCopy(buffer);
|
||||
}
|
||||
|
||||
static void ResolveRenderColorTarget(RenderExecutor &executor,
|
||||
CommandBuffer &buffer,
|
||||
RenderColorInfo &color, uint32_t slot) {
|
||||
@@ -8941,7 +8945,7 @@ public:
|
||||
void CheckRenderExecutorStencilBindingDiscovery() {
|
||||
constexpr const char *name = "RenderExecutorStencilBindingDiscovery";
|
||||
constexpr uintptr_t base = 0x0000000203600000ull;
|
||||
constexpr uint64_t allocation_size = 0x180000;
|
||||
constexpr uint64_t allocation_size = 0x200000;
|
||||
constexpr uint64_t allocation_alignment = 0x10000;
|
||||
constexpr uint64_t depth_address = base + 0x40000;
|
||||
constexpr uint64_t stencil_address = base + 0x70000;
|
||||
@@ -10087,6 +10091,261 @@ public:
|
||||
DestroyBuffer(&bounds_readback);
|
||||
registers.SetDepthClearValue(0.0f);
|
||||
|
||||
// DB override copies run with depth and stencil tests disabled.
|
||||
constexpr uint64_t copy_source_depth = base + 0x180000;
|
||||
constexpr uint64_t copy_source_stencil = base + 0x1a0000;
|
||||
constexpr uint64_t copy_destination_depth = base + 0x1c0000;
|
||||
constexpr uint64_t copy_destination_stencil = base + 0x1e0000;
|
||||
constexpr uint32_t copy_side = 8;
|
||||
constexpr uint32_t copy_layer_texels = copy_side * copy_side;
|
||||
constexpr uint32_t copy_depth_bytes =
|
||||
copy_layer_texels * 2 * sizeof(uint32_t);
|
||||
constexpr uint32_t copy_readback_stride =
|
||||
copy_depth_bytes + copy_layer_texels * 2;
|
||||
HW::DepthRenderTarget copy_target{};
|
||||
copy_target.z_info.format = Prospero::DepthFormat::kZ32F;
|
||||
copy_target.z_info.texture_compatibility =
|
||||
Prospero::TextureCompatiblePlaneCompression::kEnable;
|
||||
copy_target.stencil_info.format = Prospero::StencilFormat::k8UInt;
|
||||
copy_target.stencil_info.texture_compatibility =
|
||||
Prospero::TextureCompatibleStencil::kEnable;
|
||||
copy_target.stencil_info.htile_stencil_disabled = true;
|
||||
copy_target.depth_view.slice_max = 1;
|
||||
copy_target.size = {copy_side - 1, copy_side - 1, true};
|
||||
HW::DepthControl copy_seed_control{};
|
||||
copy_seed_control.z_enable = true;
|
||||
copy_seed_control.z_write_enable = true;
|
||||
copy_seed_control.stencil_enable = true;
|
||||
registers.SetDepthControl(copy_seed_control);
|
||||
registers.SetRenderControl({});
|
||||
const auto make_copy_target = [&](uint64_t depth, uint64_t stencil) {
|
||||
auto target = copy_target;
|
||||
target.z_read_base_addr = depth;
|
||||
target.z_write_base_addr = depth;
|
||||
target.stencil_read_base_addr = stencil;
|
||||
target.stencil_write_base_addr = stencil;
|
||||
registers.SetDepthRenderTarget(target);
|
||||
RenderDepthInfo resolved{};
|
||||
RenderExecutorTestAccess::ResolveRenderDepthTarget(
|
||||
executor, scheduler.Current(), resolved);
|
||||
(void)texture_cache.FindDepthTarget(resolved.image_id, resolved.desc);
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
return resolved;
|
||||
};
|
||||
const auto copy_source =
|
||||
make_copy_target(copy_source_depth, copy_source_stencil);
|
||||
const auto copy_destination =
|
||||
make_copy_target(copy_destination_depth, copy_destination_stencil);
|
||||
const auto clear_copy_target = [&](ImageId id, bool source) {
|
||||
auto &image = texture_cache.GetImage(id);
|
||||
image.Transit(vk::ImageLayout::eTransferDstOptimal,
|
||||
vk::AccessFlagBits2::eTransferWrite, {},
|
||||
scheduler.Current().Handle());
|
||||
for (uint32_t layer = 0; layer < 2; ++layer) {
|
||||
const vk::ClearDepthStencilValue clear{
|
||||
source ? (layer == 0 ? 0.75f : 0.25f)
|
||||
: (layer == 0 ? 0.875f : 0.625f),
|
||||
source ? (layer == 0 ? 0xa3u : 0x5au)
|
||||
: (layer == 0 ? 0x31u : 0xc4u)};
|
||||
const vk::ImageSubresourceRange range{
|
||||
vk::ImageAspectFlagBits::eDepth |
|
||||
vk::ImageAspectFlagBits::eStencil,
|
||||
0, 1, layer, 1};
|
||||
scheduler.Current().Handle().clearDepthStencilImage(
|
||||
image.backing.image, vk::ImageLayout::eTransferDstOptimal, &clear,
|
||||
1, &range);
|
||||
}
|
||||
texture_cache.MarkGpuWritten(id);
|
||||
};
|
||||
struct CopyCase {
|
||||
const char *label;
|
||||
HW::DepthRenderOverride override;
|
||||
uint32_t color_mode;
|
||||
bool depth;
|
||||
bool stencil;
|
||||
};
|
||||
constexpr std::array copy_cases{
|
||||
CopyCase{"no override", {}, 0, false, false},
|
||||
CopyCase{
|
||||
"depth valid only", {true, false, false, false}, 0, false, false},
|
||||
CopyCase{
|
||||
"depth dirty only", {false, true, false, false}, 0, false, false},
|
||||
CopyCase{"stencil valid only",
|
||||
{false, false, true, false},
|
||||
0,
|
||||
false,
|
||||
false},
|
||||
CopyCase{"stencil dirty only",
|
||||
{false, false, false, true},
|
||||
0,
|
||||
false,
|
||||
false},
|
||||
CopyCase{
|
||||
"unpaired aspects", {true, false, false, true}, 0, false, false},
|
||||
CopyCase{"color enabled", {true, true, true, true}, 1, false, false},
|
||||
CopyCase{"depth only", {true, true, false, false}, 0, true, false},
|
||||
CopyCase{"stencil only", {false, false, true, true}, 0, false, true},
|
||||
CopyCase{
|
||||
"depth and stencil", {true, true, true, true}, 0, true, true}};
|
||||
auto copy_readback =
|
||||
CreateHostBuffer(name, copy_cases.size() * copy_readback_stride,
|
||||
vk::BufferUsageFlagBits::eTransferDst, {});
|
||||
copy_target.z_read_base_addr = copy_source_depth;
|
||||
copy_target.z_write_base_addr = copy_destination_depth;
|
||||
copy_target.stencil_read_base_addr = copy_source_stencil;
|
||||
copy_target.stencil_write_base_addr = copy_destination_stencil;
|
||||
copy_target.depth_view.slice_start = 1;
|
||||
registers.SetDepthRenderTarget(copy_target);
|
||||
registers.SetDepthControl({});
|
||||
RenderDepthInfo copy_disabled_depth{};
|
||||
RenderExecutorTestAccess::ResolveRenderDepthTarget(
|
||||
executor, scheduler.Current(), copy_disabled_depth);
|
||||
Require(name, "copy without attachment tests",
|
||||
!copy_disabled_depth.image_id,
|
||||
"disabled depth/stencil tests acquired a regular attachment");
|
||||
for (size_t index = 0; index < copy_cases.size(); ++index) {
|
||||
const auto &test = copy_cases[index];
|
||||
clear_copy_target(copy_source.image_id, true);
|
||||
clear_copy_target(copy_destination.image_id, false);
|
||||
registers.SetDepthRenderOverride(test.override);
|
||||
auto color_control = registers.GetColorControl();
|
||||
color_control.mode = test.color_mode;
|
||||
registers.SetColorControl(color_control);
|
||||
Require(name, test.label,
|
||||
RenderExecutorTestAccess::DepthStencilCopy(
|
||||
executor, scheduler.Current()) ==
|
||||
(test.depth || test.stencil),
|
||||
"DB override copy did not honor paired flags and disabled "
|
||||
"color output");
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
const auto offset = index * copy_readback_stride;
|
||||
const std::array<vk::BufferImageCopy, 2> copies{
|
||||
{{offset,
|
||||
0,
|
||||
0,
|
||||
{vk::ImageAspectFlagBits::eDepth, 0, 0, 2},
|
||||
{},
|
||||
copy_destination.desc.info.extent},
|
||||
{offset + copy_depth_bytes,
|
||||
0,
|
||||
0,
|
||||
{vk::ImageAspectFlagBits::eStencil, 0, 0, 2},
|
||||
{},
|
||||
copy_destination.desc.info.extent}}};
|
||||
texture_cache.GetImage(copy_destination.image_id)
|
||||
.Download(copies, copy_readback.buffer, 0, copy_readback.size);
|
||||
}
|
||||
scheduler.Current().Handle().pipelineBarrier2(bounds_dependency);
|
||||
scheduler.Finish();
|
||||
const auto copy_result = ReadBuffer(
|
||||
name, copy_readback,
|
||||
copy_cases.size() * copy_readback_stride / sizeof(uint32_t));
|
||||
for (size_t index = 0; index < copy_cases.size(); ++index) {
|
||||
const auto &test = copy_cases[index];
|
||||
const auto *depth = copy_result.data() +
|
||||
index * copy_readback_stride / sizeof(uint32_t);
|
||||
const auto *stencil =
|
||||
reinterpret_cast<const uint8_t *>(depth) + copy_depth_bytes;
|
||||
for (uint32_t layer = 0; layer < 2; ++layer) {
|
||||
const auto expected_depth =
|
||||
std::bit_cast<uint32_t>(layer == 0 ? 0.875f
|
||||
: test.depth ? 0.25f
|
||||
: 0.625f);
|
||||
const auto expected_stencil = layer == 0 ? 0x31u
|
||||
: test.stencil ? 0x5au
|
||||
: 0xc4u;
|
||||
for (uint32_t texel = 0; texel < copy_layer_texels; ++texel) {
|
||||
const auto position = layer * copy_layer_texels + texel;
|
||||
Require(name, test.label,
|
||||
depth[position] == expected_depth &&
|
||||
stencil[position] == expected_stencil,
|
||||
"DB override copy changed an unselected layer/aspect or "
|
||||
"missed copied texels");
|
||||
}
|
||||
}
|
||||
}
|
||||
DestroyBuffer(©_readback);
|
||||
|
||||
ShaderTextureResource copy_sample_descriptor{};
|
||||
copy_sample_descriptor.fields[0] =
|
||||
static_cast<uint32_t>(copy_destination_depth >> 8u);
|
||||
copy_sample_descriptor.fields[1] =
|
||||
static_cast<uint32_t>(copy_destination_depth >> 40u) |
|
||||
(static_cast<uint32_t>(Prospero::BufferFormat::k32Float) << 20u) |
|
||||
(((copy_side - 1u) & 3u) << 30u);
|
||||
copy_sample_descriptor.fields[2] =
|
||||
((copy_side - 1u) >> 2u) | ((copy_side - 1u) << 14u);
|
||||
copy_sample_descriptor.fields[3] =
|
||||
DstSel(4, 4, 4, 4) |
|
||||
(static_cast<uint32_t>(Prospero::TileMode::kDepth) << 20u) |
|
||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2DArray) << 28u);
|
||||
copy_sample_descriptor.fields[4] = 1;
|
||||
copy_sample_descriptor.fields[5] = 0x00700000u;
|
||||
TestCase copy_sample_test;
|
||||
copy_sample_test.name = "DepthOverrideR32Sampling";
|
||||
copy_sample_test.has_user_data = true;
|
||||
copy_sample_test.image_descriptor_swizzle =
|
||||
copy_sample_descriptor.DstSelXYZW();
|
||||
std::copy_n(copy_sample_descriptor.fields, 8,
|
||||
copy_sample_test.user_data.begin());
|
||||
copy_sample_test.user_data[50] = 2 * sizeof(uint32_t);
|
||||
copy_sample_test.opcodes = {
|
||||
ShaderOpcode::V_MOV_B32, ShaderOpcode::IMAGE_SAMPLE,
|
||||
ShaderOpcode::BUFFER_STORE_DWORD, ShaderOpcode::S_ENDPGM};
|
||||
copy_sample_test.required_spirv = {"OpImageSampleExplicitLod"};
|
||||
for (uint32_t layer = 0; layer < 2; ++layer) {
|
||||
AppendVMovLiteral(©_sample_test.code, 20,
|
||||
std::bit_cast<uint32_t>(0.5f));
|
||||
AppendVMovLiteral(©_sample_test.code, 21,
|
||||
std::bit_cast<uint32_t>(0.5f));
|
||||
AppendVMovLiteral(©_sample_test.code, 22,
|
||||
std::bit_cast<uint32_t>(static_cast<float>(layer)));
|
||||
copy_sample_test.code.push_back(EncodeMimg0(0x20, 1, 0, false, 5));
|
||||
copy_sample_test.code.push_back(EncodeMimg1(0, 20, 0, 2));
|
||||
AppendStoreVgpr(©_sample_test.code, 0, layer);
|
||||
copy_sample_test.expected.push_back(
|
||||
std::bit_cast<uint32_t>(layer == 0 ? 0.875f : 0.25f));
|
||||
}
|
||||
AppendEnd(©_sample_test.code);
|
||||
const auto copy_sample_program =
|
||||
CompileCase(copy_sample_test, SubgroupSize());
|
||||
ShaderRecompiler::IR::DescriptorValue copy_sample_value{};
|
||||
copy_sample_value.dword_count = 8;
|
||||
std::copy_n(copy_sample_descriptor.fields, 8,
|
||||
copy_sample_value.dwords.begin());
|
||||
const auto copy_sample_binding = RenderExecutorTestAccess::ResolveTexture(
|
||||
executor, copy_sample_program.program.info.images[0],
|
||||
copy_sample_value);
|
||||
const auto copy_sample_view = texture_cache.FindTexture(
|
||||
copy_sample_binding.image_id, copy_sample_binding.desc);
|
||||
Require(
|
||||
name, "copied depth sampled owner",
|
||||
copy_sample_binding.image_id == copy_destination.image_id &&
|
||||
copy_sample_binding.desc.info.pixel_format ==
|
||||
vk::Format::eR32Sfloat,
|
||||
"R32 sampling did not reuse the GPU-written depth-copy destination");
|
||||
auto ©_sample_image = texture_cache.GetImage(copy_destination.image_id);
|
||||
copy_sample_image.Transit(vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
vk::AccessFlagBits2::eShaderRead, {},
|
||||
scheduler.Current().Handle());
|
||||
Image copied_depth_sample;
|
||||
copied_depth_sample.view = copy_sample_view;
|
||||
copied_depth_sample.layout = copy_sample_image.backing.state.layout;
|
||||
scheduler.Finish();
|
||||
auto copy_sample_output = CreateStorageBuffer(name, {}, 2);
|
||||
const auto copy_sampler = CreateNearestSampler(name);
|
||||
Dispatch(copy_sample_test, copy_sample_program, copy_sample_output,
|
||||
nullptr, &copied_depth_sample, nullptr, nullptr, copy_sampler);
|
||||
Require(
|
||||
name, "copied depth R32 samples",
|
||||
ReadBuffer(name, copy_sample_output, 2) == copy_sample_test.expected,
|
||||
"R32 post-effect sampling saw stale depth after the override copy");
|
||||
m_device.destroySampler(copy_sampler);
|
||||
DestroyBuffer(©_sample_output);
|
||||
RenderExecutorTestAccess::ResetBindings(executor);
|
||||
registers.SetDepthRenderOverride({});
|
||||
registers.SetColorControl({});
|
||||
|
||||
auto shared_depth_descriptor = sampled_depth_descriptor;
|
||||
shared_depth_descriptor.fields[0] =
|
||||
static_cast<uint32_t>(phased_depth_address >> 8u);
|
||||
@@ -13118,6 +13377,17 @@ private:
|
||||
m_runtime_context.queue = m_queue;
|
||||
m_runtime_context.attachment_feedback_loop_enabled = true;
|
||||
m_runtime_context.provoking_vertex_last_enabled = true;
|
||||
const vk::PhysicalDeviceImageFormatInfo2 block_texel_view_info{
|
||||
.format = vk::Format::eBc1RgbaUnormBlock,
|
||||
.type = vk::ImageType::e2D,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eSampled,
|
||||
.flags = vk::ImageCreateFlagBits::eBlockTexelViewCompatible,
|
||||
};
|
||||
const auto block_texel_view_props =
|
||||
m_physical_device.getImageFormatProperties2(block_texel_view_info);
|
||||
m_runtime_context.supports_block_texel_view =
|
||||
block_texel_view_props.result == vk::Result::eSuccess;
|
||||
|
||||
VmaVulkanFunctions functions{};
|
||||
functions.vkGetInstanceProcAddr =
|
||||
@@ -27947,6 +28217,49 @@ void CheckPm4DepthControlHighBits(RenderContext &renderer) {
|
||||
std::printf("[host] %-32s ok\n", "Pm4DepthControlHighBits");
|
||||
}
|
||||
|
||||
void CheckPm4DepthRenderOverride(RenderContext &renderer) {
|
||||
constexpr const char *name = "Pm4DepthRenderOverride";
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer, 0);
|
||||
struct Case {
|
||||
uint32_t value;
|
||||
HW::DepthRenderOverride expected;
|
||||
};
|
||||
constexpr std::array cases{Case{0x28000000u, {true, true, false, false}},
|
||||
Case{0x50000000u, {false, false, true, true}},
|
||||
Case{0x18000000u, {false, true, false, true}},
|
||||
Case{0x60000000u, {true, false, true, false}},
|
||||
Case{0xf8000000u, {true, true, true, true}},
|
||||
Case{0x82001a0fu, {false, false, false, false}}};
|
||||
for (const bool indirect : {false, true}) {
|
||||
for (const auto &test : cases) {
|
||||
std::array<uint32_t, 2> registers{Pm4::DB_RENDER_OVERRIDE, test.value};
|
||||
const auto address = reinterpret_cast<uint64_t>(registers.data());
|
||||
const std::array<uint32_t, 3> direct_packet{
|
||||
KYTY_PM4(3, Pm4::IT_SET_CONTEXT_REG, Pm4::R_ZERO),
|
||||
Pm4::DB_RENDER_OVERRIDE, test.value};
|
||||
const std::array<uint32_t, 5> indirect_packet{
|
||||
KYTY_PM4(5, Pm4::IT_SET_CONTEXT_REG_INDIRECT, Pm4::R_ZERO),
|
||||
static_cast<uint32_t>(address), static_cast<uint32_t>(address >> 32u),
|
||||
0x80000000u, 1u};
|
||||
Pm4Execution execution;
|
||||
const auto result = processor.Process(
|
||||
execution, indirect ? std::span<const uint32_t>{indirect_packet}
|
||||
: std::span<const uint32_t>{direct_packet});
|
||||
const auto &actual = processor.GetCtx().GetDepthRenderOverride();
|
||||
Require(
|
||||
name, indirect ? "indirect register" : "direct register",
|
||||
result == Pm4ProcessResult::Complete &&
|
||||
actual.force_z_valid == test.expected.force_z_valid &&
|
||||
actual.force_z_dirty == test.expected.force_z_dirty &&
|
||||
actual.force_stencil_valid == test.expected.force_stencil_valid &&
|
||||
actual.force_stencil_dirty == test.expected.force_stencil_dirty,
|
||||
"DB_RENDER_OVERRIDE lost, exchanged, or retained force flags");
|
||||
}
|
||||
}
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckAgcShaderFusion() {
|
||||
struct Case {
|
||||
bool gs;
|
||||
@@ -28721,6 +29034,7 @@ int main(int argc, char **argv) {
|
||||
CheckPm4BlendColorRegisterRanges(vulkan.RuntimeRenderer());
|
||||
CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer());
|
||||
CheckPm4DepthControlHighBits(vulkan.RuntimeRenderer());
|
||||
CheckPm4DepthRenderOverride(vulkan.RuntimeRenderer());
|
||||
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
|
||||
return 0;
|
||||
}
|
||||
@@ -28931,6 +29245,7 @@ int main(int argc, char **argv) {
|
||||
CheckPm4BlendColorRegisterRanges(vulkan.RuntimeRenderer());
|
||||
CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer());
|
||||
CheckPm4DepthControlHighBits(vulkan.RuntimeRenderer());
|
||||
CheckPm4DepthRenderOverride(vulkan.RuntimeRenderer());
|
||||
CheckAgcShaderFusion();
|
||||
CheckAgcWaitPackets(vulkan.RuntimeRenderer());
|
||||
CheckAgcDrawIndirectMultiPacket(vulkan.RuntimeRenderer());
|
||||
|
||||
Reference in New Issue
Block a user