D16S8 support

This commit is contained in:
nmzik
2026-07-17 08:39:57 +02:00
parent 13499502c9
commit dd58deae15
8 changed files with 469 additions and 124 deletions
@@ -23,6 +23,7 @@
#include <cstdarg>
#include <cstdio>
#include <limits>
#include <mutex>
#include <vulkan/vk_enum_string_helper.h>
namespace Libs::Graphics {
@@ -59,6 +60,38 @@ static bool UsesStencilOpValue(uint8_t fail, uint8_t pass, uint8_t depth_fail) {
depth_fail == Prospero::GpuEnumValue(Prospero::StencilOp::kReplaceOp);
}
[[nodiscard]] static VkFormat ResolveHostDepthAttachmentFormat(GraphicContext* ctx,
const DepthFormatPolicy& policy,
bool has_stencil) {
if (!has_stencil) {
return policy.depth_attachment_format;
}
switch (policy.depth_format) {
case Prospero::DepthFormat::kZ32F: return policy.stencil_attachment_formats.front();
case Prospero::DepthFormat::kZ16: {
if (ctx == nullptr) {
return VK_FORMAT_UNDEFINED;
}
// Kyty selects one physical device. Query its optional D16S8-compatible formats once.
static std::once_flag once;
static VkFormat selected = VK_FORMAT_UNDEFINED;
std::call_once(once, [&] {
for (const auto format: policy.stencil_attachment_formats) {
VkImageFormatProperties properties {};
if (vkGetPhysicalDeviceImageFormatProperties(
ctx->physical_device, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
DepthTargetImageUsage(), 0, &properties) == VK_SUCCESS) {
selected = format;
break;
}
}
});
return selected;
}
default: return VK_FORMAT_UNDEFINED;
}
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const HW::Context& hw,
RenderDepthInfo* r) {
@@ -200,26 +233,21 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
(z.pitch_div8_minus1 != 0 || z.height_div8_minus1 != 0 || z.slice_div64_minus1 != 0))) {
DepthFatal("inconsistent depth extent or encoded layout");
}
uint32_t guest_format = 0;
uint32_t bytes = 0;
switch (static_cast<Prospero::DepthFormat>(z.z_info.format)) {
case Prospero::DepthFormat::kZ16:
if (has_stencil) {
DepthFatal("Z16 plus stencil is unsupported");
}
r->format = VK_FORMAT_D16_UNORM;
guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm);
bytes = 2;
break;
case Prospero::DepthFormat::kZ32F:
r->format = has_stencil ? VK_FORMAT_D32_SFLOAT_S8_UINT : VK_FORMAT_D32_SFLOAT;
guest_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
bytes = 4;
break;
default: DepthFatal("unsupported depth format");
const auto* policy = FindDepthFormatPolicy(z.z_info.format);
if (policy == nullptr) {
DepthFatal("unsupported depth/stencil format pair");
}
const auto pitch = TileGetTexturePitch(guest_format, width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
const auto ideal_format = DepthAttachmentFormat(*policy, has_stencil);
r->format =
ResolveHostDepthAttachmentFormat(g_render_ctx->GetGraphicCtx(), *policy, has_stencil);
if (r->format == VK_FORMAT_UNDEFINED) {
DepthFatal("no host depth/stencil format supports required usage for %s",
string_VkFormat(ideal_format));
}
const uint32_t guest_format = Prospero::GpuEnumValue(policy->guest_format);
const uint32_t bytes = policy->bytes_per_element;
const auto pitch = TileGetTexturePitch(guest_format, width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
if (z.pitch_height_valid && ((static_cast<uint64_t>(z.pitch_div8_minus1) + 1u) * 8u != pitch ||
(static_cast<uint64_t>(z.height_div8_minus1) + 1u) * 8u !=
((static_cast<uint64_t>(height) + 7u) & ~7ull))) {
@@ -276,18 +276,6 @@ ResolveTargetTextureView(const ShaderRecompiler::IR::ImageResource& resource,
}
}
static bool IsSupportedSampledDepthFormat(VkFormat image_format, uint32_t guest_format,
VkFormat view_format) {
const bool d16 = image_format == VK_FORMAT_D16_UNORM &&
guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
view_format == VK_FORMAT_R16_UNORM;
const bool d32 =
(image_format == VK_FORMAT_D32_SFLOAT || image_format == VK_FORMAT_D32_SFLOAT_S8_UINT) &&
guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
view_format == VK_FORMAT_R32_SFLOAT;
return d16 || d32;
}
bool IsSupportedDepthTargetDescriptor(const ShaderTextureResource& descriptor,
const VulkanImage& image) {
const auto width = static_cast<uint32_t>(descriptor.Width5()) + 1u;
+140 -6
View File
@@ -5,6 +5,7 @@
#include "graphics/guest_gpu/gpu_defs.h"
#include "graphics/host_gpu/regionDefinitions.h"
#include <array>
#include <bit>
#include <cmath>
#include <cstdint>
@@ -91,6 +92,139 @@ struct DepthTargetInfo {
bool stencil_htile_compressed = false;
};
struct DepthFormatPolicy {
Prospero::DepthFormat depth_format;
Prospero::BufferFormat guest_format;
uint32_t bytes_per_element;
VkFormat sampled_view_format;
VkFormat depth_attachment_format;
std::array<VkFormat, 3> stencil_attachment_formats;
};
inline constexpr std::array<DepthFormatPolicy, 2> DEPTH_FORMAT_POLICIES {{
{Prospero::DepthFormat::kZ16,
Prospero::BufferFormat::k16UNorm,
2,
VK_FORMAT_R16_UNORM,
VK_FORMAT_D16_UNORM,
{VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT}},
{Prospero::DepthFormat::kZ32F,
Prospero::BufferFormat::k32Float,
4,
VK_FORMAT_R32_SFLOAT,
VK_FORMAT_D32_SFLOAT,
{VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED}},
}};
[[nodiscard]] inline constexpr const DepthFormatPolicy*
FindDepthFormatPolicy(uint32_t depth_format) noexcept {
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
if (Prospero::GpuEnumValue(policy.depth_format) == depth_format) {
return &policy;
}
}
return nullptr;
}
[[nodiscard]] inline constexpr const DepthFormatPolicy*
FindGuestDepthFormatPolicy(uint32_t guest_format) noexcept {
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
if (Prospero::GpuEnumValue(policy.guest_format) == guest_format) {
return &policy;
}
}
return nullptr;
}
[[nodiscard]] inline constexpr bool IsStencilAttachmentFormat(const DepthFormatPolicy& policy,
VkFormat format) noexcept {
for (const auto candidate: policy.stencil_attachment_formats) {
if (candidate != VK_FORMAT_UNDEFINED && candidate == format) {
return true;
}
}
return false;
}
[[nodiscard]] inline constexpr VkFormat DepthAttachmentFormat(const DepthFormatPolicy& policy,
bool has_stencil) noexcept {
return has_stencil ? policy.stencil_attachment_formats.front() : policy.depth_attachment_format;
}
[[nodiscard]] inline constexpr VkFormat DepthAttachmentFormat(uint32_t depth_format,
uint32_t stencil_format) noexcept {
bool has_stencil = false;
switch (static_cast<Prospero::StencilFormat>(stencil_format)) {
case Prospero::StencilFormat::kInvalid: break;
case Prospero::StencilFormat::k8UInt: has_stencil = true; break;
default: return VK_FORMAT_UNDEFINED;
}
const auto* policy = FindDepthFormatPolicy(depth_format);
return policy == nullptr ? VK_FORMAT_UNDEFINED : DepthAttachmentFormat(*policy, has_stencil);
}
[[nodiscard]] inline constexpr VkImageUsageFlags DepthTargetImageUsage() noexcept {
return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}
[[nodiscard]] inline constexpr VkFormat DepthAspectTransferFormat(VkFormat format) noexcept {
switch (format) {
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_D16_UNORM_S8_UINT: return VK_FORMAT_D16_UNORM;
case VK_FORMAT_D24_UNORM_S8_UINT: return VK_FORMAT_X8_D24_UNORM_PACK32;
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT: return VK_FORMAT_D32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
}
}
[[nodiscard]] inline constexpr uint32_t DepthAspectTransferBytes(VkFormat format) noexcept {
switch (DepthAspectTransferFormat(format)) {
case VK_FORMAT_D16_UNORM: return 2;
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT: return 4;
default: return 0;
}
}
[[nodiscard]] inline constexpr uint32_t EncodeD16AsD24(uint16_t value) noexcept {
// Preserve the guest UNORM value when widening 16 bits to the 24-bit transfer plane.
return static_cast<uint32_t>((static_cast<uint64_t>(value) * 0x00ffffffu + 0x7fffu) / 0xffffu);
}
[[nodiscard]] inline uint32_t EncodeD16AsD32(uint16_t value) noexcept {
return std::bit_cast<uint32_t>(static_cast<float>(value) / 65535.0f);
}
[[nodiscard]] inline constexpr bool IsSupportedSampledDepthFormat(VkFormat image_format,
uint32_t guest_format,
VkFormat view_format) noexcept {
const auto* policy = FindGuestDepthFormatPolicy(guest_format);
return policy != nullptr && view_format == policy->sampled_view_format &&
(image_format == policy->depth_attachment_format ||
IsStencilAttachmentFormat(*policy, image_format));
}
[[nodiscard]] inline constexpr bool IsSupportedSampledDepthFormat(VkFormat image_format,
VkFormat view_format) noexcept {
for (const auto& policy: DEPTH_FORMAT_POLICIES) {
if (IsSupportedSampledDepthFormat(image_format, Prospero::GpuEnumValue(policy.guest_format),
view_format)) {
return true;
}
}
return false;
}
[[nodiscard]] inline constexpr bool IsSupportedDepthTargetFormat(const DepthTargetInfo& info) {
const bool has_stencil = info.stencil_address != 0 || info.stencil_size != 0;
const auto* policy = FindGuestDepthFormatPolicy(info.guest_format);
return policy != nullptr && info.bytes_per_element == policy->bytes_per_element &&
(has_stencil ? IsStencilAttachmentFormat(*policy, info.format)
: info.format == policy->depth_attachment_format);
}
enum class VideoOutCompression : uint8_t { Uncompressed, Dcc256_64_64, Unsupported };
struct VideoOutInfo {
@@ -205,13 +339,13 @@ SelectStorageSampledViewShape(uint32_t type, uint32_t depth, uint32_t backing_la
switch (static_cast<Prospero::ImageType>(type)) {
case Prospero::ImageType::kColor2D:
return depth == 1 && backing_layers == 1 ? StorageSampledViewShape::Image2D
: StorageSampledViewShape::Unsupported;
: StorageSampledViewShape::Unsupported;
case Prospero::ImageType::kColor2DArray:
return depth != 0 && depth == backing_layers ? StorageSampledViewShape::Image2DArray
: StorageSampledViewShape::Unsupported;
: StorageSampledViewShape::Unsupported;
case Prospero::ImageType::kColor3D:
return depth != 0 && backing_layers == 1 ? StorageSampledViewShape::Image3D
: StorageSampledViewShape::Unsupported;
: StorageSampledViewShape::Unsupported;
default: return StorageSampledViewShape::Unsupported;
}
}
@@ -443,12 +577,12 @@ ClassifyBufferImageWrite(uint64_t buffer_address, uint64_t buffer_size, uint64_t
return BufferImageWrite::None;
}
const bool exact = buffer_address == image_address && buffer_size == image_size;
const auto offset = buffer_address >= image_address ? buffer_address - image_address : UINT64_MAX;
const auto offset =
buffer_address >= image_address ? buffer_address - image_address : UINT64_MAX;
const bool contained = offset <= image_size && buffer_size <= image_size - offset;
const bool buffer_page_aligned =
((buffer_address | buffer_size) & (TRACKER_PAGE_SIZE - 1)) == 0;
const bool image_page_aligned =
((image_address | image_size) & (TRACKER_PAGE_SIZE - 1)) == 0;
const bool image_page_aligned = ((image_address | image_size) & (TRACKER_PAGE_SIZE - 1)) == 0;
switch (binding) {
case BufferImageBinding::Texture:
return contained && image_page_aligned && !image_gpu_modified
+14 -19
View File
@@ -3,21 +3,22 @@
#include "common/assert.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/renderer/imageInfo.h"
#include "graphics/shader/recompiler/ShaderIR.h"
#include "graphics/shader/shader.h"
namespace Libs::Graphics {
[[nodiscard]] inline bool IsSupportedStorageSwizzle(uint32_t format, uint32_t swizzle) noexcept {
const bool single_channel = format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16Float) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
const bool single_channel =
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UNorm) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32UInt) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16Float) ||
format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float);
return swizzle == DstSel(4, 5, 6, 7) ||
(single_channel &&
(swizzle == DstSel(4, 0, 0, 0) || swizzle == DstSel(4, 0, 0, 1))) ||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) || swizzle == DstSel(4, 0, 0, 1))) ||
(format == Prospero::GpuEnumValue(Prospero::BufferFormat::k8_8_8_8UNorm) &&
(swizzle == DstSel(4, 5, 6, 1) || swizzle == DstSel(6, 5, 4, 7))) ||
(format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32_32_32_32Float) &&
@@ -91,11 +92,7 @@ namespace Libs::Graphics {
[[nodiscard]] inline int SelectSampledDepthView(VkFormat image_format, VkFormat view_format,
uint32_t swizzle) noexcept {
const bool d16 = image_format == VK_FORMAT_D16_UNORM && view_format == VK_FORMAT_R16_UNORM;
const bool d32 =
(image_format == VK_FORMAT_D32_SFLOAT || image_format == VK_FORMAT_D32_SFLOAT_S8_UINT) &&
view_format == VK_FORMAT_R32_SFLOAT;
if (d16 || d32) {
if (IsSupportedSampledDepthFormat(image_format, view_format)) {
switch (swizzle) {
case DstSel(4, 4, 4, 4): return VulkanImage::VIEW_DEPTH_TEXTURE;
case DstSel(4, 0, 0, 0): return VulkanImage::VIEW_R000;
@@ -117,12 +114,10 @@ IsSupportedSampledDepthResource(const ShaderRecompiler::IR::ImageResource& resou
[[nodiscard]] inline int SelectStorageColorView(VkFormat image_format, VkFormat view_format,
uint32_t swizzle) noexcept {
const bool single_channel = view_format == VK_FORMAT_R8_UNORM ||
view_format == VK_FORMAT_R8_UINT ||
view_format == VK_FORMAT_R16_UINT ||
view_format == VK_FORMAT_R32_UINT ||
view_format == VK_FORMAT_R16_SFLOAT ||
view_format == VK_FORMAT_R32_SFLOAT;
const bool single_channel =
view_format == VK_FORMAT_R8_UNORM || view_format == VK_FORMAT_R8_UINT ||
view_format == VK_FORMAT_R16_UINT || view_format == VK_FORMAT_R32_UINT ||
view_format == VK_FORMAT_R16_SFLOAT || view_format == VK_FORMAT_R32_SFLOAT;
const bool swizzle_ok =
swizzle == DstSel(4, 5, 6, 7) ||
(single_channel && (swizzle == DstSel(4, 0, 0, 0) || swizzle == DstSel(4, 0, 0, 1))) ||
@@ -14,6 +14,7 @@
#include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/descriptorCache.h"
#include "graphics/host_gpu/renderer/framebufferCache.h"
#include "graphics/host_gpu/renderer/imageInfo.h"
#include "graphics/host_gpu/renderer/pipelineCache.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
@@ -59,22 +60,19 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
*resolved = {};
const bool has_stencil =
z.stencil_info.format != Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid);
const bool depth_format_supported =
z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16) ||
z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F);
const bool msaa_compat = depth_msaa_single_sample_compatible(z.z_info.num_samples);
const bool supported_depth_state =
z.z_info.tile_surface_enable && depth_format_supported &&
!(z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16) && has_stencil) &&
z.z_info.tile_mode_index == 0 && (z.z_info.num_samples == 0 || msaa_compat) &&
z.z_info.zrange_precision <= 1 && !z.z_info.expclear_enabled &&
!z.z_info.embedded_sample_locations && !z.z_info.partially_resident &&
z.z_info.num_mip_levels == 0 && z.z_info.plane_compression == 0 &&
z.depth_view.current_mip_level == 0 && z.depth_view.slice_start == 0 &&
z.depth_view.slice_max == 0 && z.depth_info.addr5_swizzle_mask == 0 &&
z.depth_info.array_mode == 0 && z.depth_info.pipe_config == 0 &&
z.depth_info.bank_width == 0 && z.depth_info.bank_height == 0 &&
z.depth_info.macro_tile_aspect == 0 && z.depth_info.num_banks == 0;
const auto* depth_policy = FindDepthFormatPolicy(z.z_info.format);
const bool msaa_compat = depth_msaa_single_sample_compatible(z.z_info.num_samples);
const bool supported_depth_state =
z.z_info.tile_surface_enable && depth_policy != nullptr && z.z_info.tile_mode_index == 0 &&
(z.z_info.num_samples == 0 || msaa_compat) && z.z_info.zrange_precision <= 1 &&
!z.z_info.expclear_enabled && !z.z_info.embedded_sample_locations &&
!z.z_info.partially_resident && z.z_info.num_mip_levels == 0 &&
z.z_info.plane_compression == 0 && z.depth_view.current_mip_level == 0 &&
z.depth_view.slice_start == 0 && z.depth_view.slice_max == 0 &&
z.depth_info.addr5_swizzle_mask == 0 && z.depth_info.array_mode == 0 &&
z.depth_info.pipe_config == 0 && z.depth_info.bank_width == 0 &&
z.depth_info.bank_height == 0 && z.depth_info.macro_tile_aspect == 0 &&
z.depth_info.num_banks == 0;
const bool supported_stencil_state =
z.stencil_info.tile_mode_index == 0 && z.stencil_info.tile_split == 0 &&
!z.stencil_info.expclear_enabled &&
@@ -138,10 +136,8 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
return false;
}
const bool z16 = z.z_info.format == Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16);
const uint32_t guest_format = Prospero::GpuEnumValue(z16 ? Prospero::BufferFormat::k16UNorm
: Prospero::BufferFormat::k32Float);
const uint32_t bytes = z16 ? 2u : 4u;
const uint32_t guest_format = Prospero::GpuEnumValue(depth_policy->guest_format);
const uint32_t bytes = depth_policy->bytes_per_element;
const uint32_t pitch = TileGetTexturePitch(guest_format, width, 1,
Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
if (z.pitch_height_valid && ((static_cast<uint64_t>(z.pitch_div8_minus1) + 1u) * 8u != pitch ||
@@ -149,7 +145,7 @@ bool ResolveHtileClearTarget(const HW::DepthRenderTarget& z, uint64_t descriptor
((static_cast<uint64_t>(height) + 7u) & ~7ull))) {
return false;
}
const uint32_t block_width = z16 ? 256u : 128u;
const uint32_t block_width = bytes == 2 ? 256u : 128u;
const uint64_t padded_width =
(static_cast<uint64_t>(pitch) + block_width - 1u) & ~(block_width - 1u);
const uint64_t padded_height = (static_cast<uint64_t>(height) + 127u) & ~127ull;
+12 -12
View File
@@ -1109,10 +1109,9 @@ DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTarge
create.format = info.format;
create.tiling = VK_IMAGE_TILING_OPTIMAL;
create.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
create.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
create.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
create.samples = VK_SAMPLE_COUNT_1_BIT;
create.usage = DepthTargetImageUsage();
create.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
create.samples = VK_SAMPLE_COUNT_1_BIT;
VkImageFormatProperties properties {};
if (vkGetPhysicalDeviceImageFormatProperties(ctx->physical_device, info.format,
VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
@@ -2299,12 +2298,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
(has_stencil && PageOverlaps(info.stencil_address, info.stencil_size, info.htile_address,
info.htile_size)))) ||
(info.stencil_htile_compressed && (!has_stencil || !has_htile)) ||
!(info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm)
? !has_stencil && info.format == VK_FORMAT_D16_UNORM && info.bytes_per_element == 2
: info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
info.bytes_per_element == 4 &&
info.format ==
(has_stencil ? VK_FORMAT_D32_SFLOAT_S8_UINT : VK_FORMAT_D32_SFLOAT))) {
!IsSupportedDepthTargetFormat(info)) {
EXIT("TextureCache: unsupported depth target, command=%p ctx=%p depth=0x%016" PRIx64
"+0x%016" PRIx64 " stencil=0x%016" PRIx64 "+0x%016" PRIx64 " htile=0x%016" PRIx64
"+0x%016" PRIx64 " extent=%ux%u pitch=%u tile=%u format=%d guest_format=%u bpe=%u\n",
@@ -2449,8 +2443,14 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
}
RequireRetirementIsolation(retire, "depth target", info.address, info.size);
RetireImages(retire, native_depth_source.get());
if (!CanLoadStencilAttachment(info, native_depth_source != nullptr &&
native_depth_source->stencil_initialized)) {
const bool coherent_guest_stencil =
has_stencil &&
IsCoherentGuestImageSource(stencil_source, info.stencil_address, info.stencil_size);
// Native expansion must preserve old layers. Guest data initializes only a wholly new image.
const bool stencil_contents_available = native_depth_source != nullptr
? native_depth_source->stencil_initialized
: coherent_guest_stencil;
if (!CanLoadStencilAttachment(info, stencil_contents_available)) {
EXIT("TextureCache: new stencil target requires a clear before stencil access, "
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
info.stencil_address, info.stencil_size);
+61 -19
View File
@@ -12,6 +12,46 @@
namespace Libs::Graphics {
template <uint32_t (*Encode)(uint16_t)>
static void UploadPromotedD16Depth(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
uint32_t base_layer) {
const uint64_t slice_size = info.size / info.layers;
const uint64_t texels = static_cast<uint64_t>(info.pitch) * info.height;
const uint64_t host_slice_size = texels * sizeof(uint32_t);
const uint64_t host_upload_size = host_slice_size * info.layers;
if (slice_size % sizeof(uint16_t) != 0 || texels > slice_size / sizeof(uint16_t) ||
host_upload_size > UINT32_MAX) {
EXIT("Tiler: invalid D16 host-promotion footprint, guest_slice=0x%016" PRIx64
" host_slice=0x%016" PRIx64 " layers=%u\n",
slice_size, host_slice_size, info.layers);
}
UtilScratchBuffer host_linear(host_upload_size);
std::vector<uint16_t> guest_linear(slice_size / sizeof(uint16_t));
std::vector<BufferImageCopy> regions;
regions.reserve(info.layers);
for (uint32_t layer = 0; layer < info.layers; layer++) {
auto* guest_slice = reinterpret_cast<const uint8_t*>(source.address) + slice_size * layer;
TileConvertTiledToLinearDepth(guest_linear.data(), guest_slice, info.guest_format,
info.width, info.height, info.pitch, slice_size);
auto* host_slice = reinterpret_cast<uint32_t*>(static_cast<uint8_t*>(host_linear.Data()) +
host_slice_size * layer);
for (uint64_t texel = 0; texel < texels; texel++) {
host_slice[texel] = Encode(guest_linear[texel]);
}
BufferImageCopy region {};
region.offset = static_cast<uint32_t>(host_slice_size * layer);
region.pitch = info.pitch;
region.width = info.width;
region.height = info.height;
region.dst_layer = base_layer + layer;
region.aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
regions.push_back(region);
}
UtilFillImage(ctx, image, host_linear.Data(), host_upload_size, regions,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const ImageInfo& info,
const BufferImageCopySource& source, bool refresh, bool storage) const {
if (ctx == nullptr || image == nullptr || info.address == 0 || info.size == 0 ||
@@ -53,19 +93,13 @@ void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image, const
void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh, uint32_t base_layer) const {
const bool d16 =
info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
info.format == VK_FORMAT_D16_UNORM && info.bytes_per_element == 2;
const bool d32 =
info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
(info.format == VK_FORMAT_D32_SFLOAT || info.format == VK_FORMAT_D32_SFLOAT_S8_UINT) &&
info.bytes_per_element == 4;
if (ctx == nullptr || image == nullptr || info.address == 0 || info.size == 0 ||
info.width == 0 || info.height == 0 || info.pitch < info.width || info.layers == 0 ||
info.size % info.layers != 0 || base_layer > image->layers ||
info.layers > image->layers - base_layer || info.size > UINT32_MAX ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) || (!d16 && !d32) ||
!source.cpu_current || source.address != info.address || source.size != info.size ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) ||
!IsSupportedDepthTargetFormat(info) || !source.cpu_current ||
source.address != info.address || source.size != info.size ||
(source.buffer == nullptr && source.offset != 0)) {
EXIT("Tiler: unsupported depth detile, ctx=%p image=%p source_buffer=%p "
"source=0x%016" PRIx64 "+0x%016" PRIx64 " offset=0x%016" PRIx64
@@ -80,6 +114,19 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
if (refresh) {
VulkanDeviceWaitIdle(ctx);
}
if (DepthAspectTransferBytes(info.format) != info.bytes_per_element) {
switch (info.format) {
case VK_FORMAT_D24_UNORM_S8_UINT:
UploadPromotedD16Depth<EncodeD16AsD24>(ctx, image, info, source, base_layer);
return;
case VK_FORMAT_D32_SFLOAT_S8_UINT:
UploadPromotedD16Depth<EncodeD16AsD32>(ctx, image, info, source, base_layer);
return;
default:
EXIT("Tiler: unsupported depth transfer conversion, format=%d guest_bpe=%u\n",
static_cast<int>(info.format), info.bytes_per_element);
}
}
const auto slice_size = info.size / info.layers;
UtilScratchBuffer linear(info.size);
std::vector<BufferImageCopy> regions;
@@ -109,11 +156,12 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
TileSizeAlign htile_size {};
TileSizeAlign depth_size {};
const auto stencil_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt);
const auto* policy = FindGuestDepthFormatPolicy(info.guest_format);
const auto stencil_pitch = TileGetTexturePitch(
stencil_format, info.width, 1, Prospero::GpuEnumValue(Prospero::TileMode::kDepth));
const bool supported_layout =
TileGetDepthSize(info.width, info.height, 0,
Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F),
policy != nullptr && IsSupportedDepthTargetFormat(info) &&
TileGetDepthSize(info.width, info.height, 0, Prospero::GpuEnumValue(policy->depth_format),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt),
info.htile_address != 0, &stencil_size, &htile_size, &depth_size) &&
info.layers != 0 && info.stencil_size % info.layers == 0 &&
@@ -121,9 +169,7 @@ void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
stencil_pitch != 0;
if (ctx == nullptr || image == nullptr || info.address == 0 || info.size == 0 ||
info.stencil_address == 0 || info.stencil_size == 0 || info.width == 0 ||
info.height == 0 || info.format != VK_FORMAT_D32_SFLOAT_S8_UINT ||
info.guest_format != Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) ||
info.bytes_per_element != 4 || base_layer > image->layers ||
info.height == 0 || base_layer > image->layers ||
info.layers > image->layers - base_layer || info.stencil_size > UINT32_MAX ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) ||
info.stencil_htile_compressed || !supported_layout || !source.cpu_current ||
@@ -187,11 +233,7 @@ void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info)
}
void Tiler::TileImage(void* dst, const void* src, const DepthTargetInfo& info) const {
const bool supported_format =
(info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
info.format == VK_FORMAT_D16_UNORM && info.bytes_per_element == 2) ||
(info.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
info.format == VK_FORMAT_D32_SFLOAT && info.bytes_per_element == 4);
const bool supported_format = IsSupportedDepthTargetFormat(info);
if (dst == nullptr || src == nullptr || info.address == 0 || info.size == 0 ||
info.stencil_address != 0 || info.stencil_size != 0 || info.width == 0 ||
info.height == 0 || info.pitch < info.width ||
+178 -16
View File
@@ -8710,8 +8710,8 @@ bool CacheFault(void *opaque, PageFaultAccess access, uint64_t vaddr,
VK_FORMAT_A2R10G10B10_UNORM_PACK32,
DstSel(6, 5, 4, 7));
} else if (std::strcmp(kind, "sampled-depth-format") == 0) {
(void)SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_R16_UNORM, DstSel(4, 4, 4, 4));
(void)SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_R32_SFLOAT, DstSel(4, 4, 4, 4));
} else if (std::strcmp(kind, "sampled-depth-swizzle") == 0) {
(void)SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_R32_SFLOAT, DstSel(4, 5, 6, 7));
@@ -8806,6 +8806,21 @@ void CheckSampledColorViews() {
DstSel(4, 0, 0, 0)) ==
VulkanImage::VIEW_R000,
"D16 depth target did not select its R000 depth-aspect view");
Require("SampledColorViews", "D16S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) ==
VulkanImage::VIEW_R001,
"D16S8 depth target did not select its R001 depth-aspect view");
Require("SampledColorViews", "promoted D24S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) ==
VulkanImage::VIEW_R001,
"D24S8 host fallback did not preserve the guest R16 depth view");
Require("SampledColorViews", "promoted D32S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_R16_UNORM,
DstSel(4, 0, 0, 1)) ==
VulkanImage::VIEW_R001,
"D32S8 host fallback did not preserve the guest R16 depth view");
Require("SampledColorViews", "D32S8 R001 depth target",
SelectSampledDepthView(VK_FORMAT_D32_SFLOAT_S8_UINT,
VK_FORMAT_R32_SFLOAT,
@@ -11094,20 +11109,38 @@ void CheckImageOverlapResolution() {
mismatched_depth) ==
DepthOverlap::Unsupported,
"mipmapped or format-mismatched depth load was admitted");
Require("ImageOverlapResolution", "depth transition source",
SelectDepthTransitionSource(true, true, false, false, false, true) ==
DepthTransitionSource::None &&
SelectDepthTransitionSource(false, true, false, false, false, true) ==
DepthTransitionSource::Native &&
SelectDepthTransitionSource(false, false, false, false, false, false) ==
DepthTransitionSource::Guest &&
SelectDepthTransitionSource(false, true, true, false, false, false) ==
DepthTransitionSource::Guest &&
SelectDepthTransitionSource(false, true, false, true, false, false) ==
DepthTransitionSource::Guest &&
SelectDepthTransitionSource(false, true, false, false, true, true) ==
DepthTransitionSource::Guest,
"clear, clean-native, or overlapping dirty-buffer depth preservation policy regressed");
struct DepthTransitionCase {
const char *name;
bool clear;
bool native;
bool sampled_cpu_dirty;
bool sampled_buffer_modified;
bool buffer_overlap;
bool buffer_cpu_dirty;
DepthTransitionSource expected;
};
constexpr DepthTransitionCase transition_cases[] = {
{"clear", true, true, false, false, false, true,
DepthTransitionSource::None},
{"clean native", false, true, false, false, false, true,
DepthTransitionSource::Native},
{"missing native", false, false, false, false, false, false,
DepthTransitionSource::Guest},
{"CPU-dirty native", false, true, true, false, false, false,
DepthTransitionSource::Guest},
{"buffer-modified native", false, true, false, true, false, false,
DepthTransitionSource::Guest},
{"dirty overlapping buffer", false, true, false, false, true, true,
DepthTransitionSource::Guest},
};
for (const auto &test : transition_cases) {
Require("ImageOverlapResolution", test.name,
SelectDepthTransitionSource(
test.clear, test.native, test.sampled_cpu_dirty,
test.sampled_buffer_modified, test.buffer_overlap,
test.buffer_cpu_dirty) == test.expected,
"depth preservation source changed");
}
depth.depth_load_clear = true;
depth.stencil_address = sampled.address + 0x6000;
depth.stencil_size = 0x2000;
@@ -11136,6 +11169,7 @@ void CheckImageOverlapResolution() {
Require("ImageOverlapResolution", "stencil clear initializes",
CanLoadStencilAttachment(depth, false),
"stencil clear did not initialize the attachment");
depth.stencil_load_clear = false;
depth.stencil_htile_compressed = false;
Require("ImageOverlapResolution", "raw stencil load",
CanLoadRawStencilPlane(depth),
@@ -11253,6 +11287,122 @@ void CheckDepthTargetFootprints() {
TileSizeAlign stencil{};
TileSizeAlign htile{};
TileSizeAlign depth{};
struct AttachmentFormatCase {
const char *name;
uint32_t depth_format;
uint32_t stencil_format;
VkFormat expected;
};
constexpr AttachmentFormatCase attachment_cases[] = {
{"Z16", Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16),
Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid),
VK_FORMAT_D16_UNORM},
{"Z16S8", Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt),
VK_FORMAT_D16_UNORM_S8_UINT},
{"Z32", Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F),
Prospero::GpuEnumValue(Prospero::StencilFormat::kInvalid),
VK_FORMAT_D32_SFLOAT},
{"Z32S8", Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt),
VK_FORMAT_D32_SFLOAT_S8_UINT},
{"invalid depth", 2,
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt),
VK_FORMAT_UNDEFINED},
{"invalid stencil", Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16),
2, VK_FORMAT_UNDEFINED},
};
for (const auto &test : attachment_cases) {
Require("DepthTargetFootprints", test.name,
DepthAttachmentFormat(test.depth_format, test.stencil_format) ==
test.expected,
"PS5 depth/stencil attachment mapping changed");
}
Require("DepthTargetFootprints", "1920x1080 Z16S8 without HTile",
TileGetDepthSize(1920, 1080, 0,
Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), false,
&stencil, &htile, &depth) &&
depth.size == 0x480000 && depth.align == 0x10000 &&
stencil.size == 0x280000 && stencil.align == 0x10000 && htile.size == 0,
"captured Z16S8 footprint disagrees with Prospero block rules");
struct TargetFormatCase {
const char *name;
VkFormat host_format;
uint32_t guest_format;
uint32_t bytes_per_element;
bool stencil;
bool supported;
};
constexpr TargetFormatCase target_cases[] = {
{"D16", VK_FORMAT_D16_UNORM,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, false, true},
{"D16S8", VK_FORMAT_D16_UNORM_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, true, true},
{"D16 via D24S8", VK_FORMAT_D24_UNORM_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, true, true},
{"D16 via D32S8", VK_FORMAT_D32_SFLOAT_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, true, true},
{"D32", VK_FORMAT_D32_SFLOAT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 4, false, true},
{"D32S8", VK_FORMAT_D32_SFLOAT_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 4, true, true},
{"D16 plus stencil mismatch", VK_FORMAT_D16_UNORM,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, true, false},
{"fallback without stencil", VK_FORMAT_D24_UNORM_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 2, false, false},
{"D32 guest via D24", VK_FORMAT_D24_UNORM_S8_UINT,
Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float), 4, true, false},
{"D16 byte mismatch", VK_FORMAT_D16_UNORM,
Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm), 4, false, false},
};
for (const auto &test : target_cases) {
DepthTargetInfo target{};
target.format = test.host_format;
target.guest_format = test.guest_format;
target.bytes_per_element = test.bytes_per_element;
target.stencil_address = test.stencil ? 0x10000 : 0;
target.stencil_size = test.stencil ? 0x10000 : 0;
Require("DepthTargetFootprints", test.name,
IsSupportedDepthTargetFormat(target) == test.supported,
"host/guest depth format policy changed");
}
struct TransferPlaneCase {
const char *name;
VkFormat attachment;
VkFormat transfer;
uint32_t bytes;
};
constexpr TransferPlaneCase transfer_cases[] = {
{"D16S8 transfer", VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D16_UNORM, 2},
{"D24S8 transfer", VK_FORMAT_D24_UNORM_S8_UINT,
VK_FORMAT_X8_D24_UNORM_PACK32, 4},
{"D32S8 transfer", VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D32_SFLOAT, 4},
{"invalid transfer", VK_FORMAT_R16_UNORM, VK_FORMAT_UNDEFINED, 0},
};
for (const auto &test : transfer_cases) {
Require("DepthTargetFootprints", test.name,
DepthAspectTransferFormat(test.attachment) == test.transfer &&
DepthAspectTransferBytes(test.attachment) == test.bytes,
"combined depth transfer-plane layout changed");
}
struct PromotionCase {
const char *name;
uint16_t source;
uint32_t d24;
uint32_t d32;
};
constexpr PromotionCase promotion_cases[] = {
{"zero", 0, 0, 0},
{"midpoint", 0x8000, 0x00800080, 0x3f000080},
{"maximum", 0xffff, 0x00ffffff, 0x3f800000},
};
for (const auto &test : promotion_cases) {
Require("DepthTargetFootprints", test.name,
EncodeD16AsD24(test.source) == test.d24 &&
EncodeD16AsD32(test.source) == test.d32,
"D16 host promotion changed the represented depth value");
}
Require("DepthTargetFootprints", "640x360 Z32S8 without HTile",
TileGetDepthSize(640, 360, 0, Prospero::GpuEnumValue(Prospero::DepthFormat::kZ32F),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt), false,
@@ -11396,6 +11546,18 @@ void CheckHtileClearTargetResolution() {
resolved.address == derived_z16.htile_data_base_addr &&
resolved.size == htile_size.size,
"extent-derived Z16 depth-only HTile target was rejected");
auto derived_z16s8 = derived;
derived_z16s8.z_info.format = Prospero::GpuEnumValue(Prospero::DepthFormat::kZ16);
Require("HtileClearTargetResolution", "derived Z16S8 target",
TileGetDepthSize(960, 540, 0, derived_z16s8.z_info.format,
derived_z16s8.stencil_info.format, true, &stencil_size,
&htile_size, &depth_size) &&
stencil_size.size != 0 && stencil_size.align == 0x10000 &&
ResolveHtileClearTarget(derived_z16s8, htile_size.size, &resolved) &&
resolved.address == derived_z16s8.htile_data_base_addr &&
resolved.size == htile_size.size,
"extent-derived Z16S8 HTile target was rejected");
std::printf("[host] %-32s ok\n", "HtileClearTargetResolution");
}