Implement 0x12 CopyData, sampled-to-depth fix, stencil detailing

This commit is contained in:
nmzik
2026-07-16 19:03:31 +02:00
parent ceb7c6765e
commit 0d7c7510d7
17 changed files with 843 additions and 502 deletions
@@ -1207,6 +1207,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
(vaddr & (TRACKER_PAGE_SIZE - 1)) == 0 && (size & (TRACKER_PAGE_SIZE - 1)) == 0);
}
FaultSafeCacheLock lock(this, m_mutex);
const bool cpu_dirty = m_memory_tracker.IsRegionCpuModified(vaddr, size);
auto use_coherent_guest_backing = [&](const CachedBuffer& overlap) {
const bool gpu_modified = m_memory_tracker.IsRegionGpuModified(vaddr, size);
const auto dirty_ranges = m_gpu_modified_ranges.Intersections(vaddr, size);
@@ -1219,7 +1220,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
// A clean/CPU-current image range may coexist with a partial cached-buffer view because
// guest backing is authoritative. The PS5 detiler consumes that backing at the existing
// Tiler seam.
return BufferImageCopySource {nullptr, 0, vaddr, size, true};
return BufferImageCopySource {nullptr, 0, vaddr, size, true, cpu_dirty};
};
auto it = m_buffers.upper_bound(vaddr);
if (it == m_buffers.begin()) {
@@ -1227,7 +1228,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
PageOverlaps(vaddr, size, it->second->vaddr, it->second->size)) {
return use_coherent_guest_backing(*it->second);
}
return {nullptr, 0, vaddr, size, true};
return {nullptr, 0, vaddr, size, true, cpu_dirty};
}
--it;
auto& cached = *it->second;
@@ -1241,7 +1242,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
PageOverlaps(vaddr, size, next->second->vaddr, next->second->size)) {
return use_coherent_guest_backing(*next->second);
}
return {nullptr, 0, vaddr, size, true};
return {nullptr, 0, vaddr, size, true, cpu_dirty};
}
if (cached.ctx == nullptr || cached.buffer == nullptr || cached.buffer->buffer == nullptr) {
EXIT("BufferCache: inconsistent image source, addr=0x%016" PRIx64 " size=0x%016" PRIx64
@@ -1250,7 +1251,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
static_cast<const void*>(cached.buffer.get()));
}
const bool gpu_modified = m_memory_tracker.IsRegionGpuModified(vaddr, size);
const bool cpu_modified = m_memory_tracker.IsRegionCpuModified(vaddr, size);
const bool cpu_modified = cpu_dirty;
if (gpu_modified && cpu_modified) {
EXIT("BufferCache: image source is both CPU- and GPU-modified, addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
@@ -1333,7 +1334,7 @@ BufferImageCopySource BufferCache::ObtainBufferForImage(uint64_t vaddr, uint64_t
" size=0x%016" PRIx64 "\n",
vaddr, size);
}
return {cached.buffer.get(), offset, vaddr, size, true};
return {cached.buffer.get(), offset, vaddr, size, true, cpu_dirty};
}
namespace {
@@ -26,6 +26,9 @@ struct BufferImageCopySource {
uint64_t address = 0;
uint64_t size = 0;
bool cpu_current = false;
// True when the guest range was CPU-dirty before coherence resolution. ObtainBufferForImage
// may consume that tracker state while publishing the same bytes to a cached buffer.
bool cpu_dirty = false;
};
struct BufferCacheRange {
@@ -340,6 +340,8 @@ void ResolveRenderDepthTarget(uint64_t submit_id, CommandBuffer* buffer, const H
(r->stencil_test_enable &&
(stencil_face_accesses_attachment(r->stencil_static_front, r->stencil_dynamic_front) ||
stencil_face_accesses_attachment(r->stencil_static_back, r->stencil_dynamic_back)));
info.stencil_htile_compressed =
has_stencil && has_htile && !z.stencil_info.tile_stencil_disable;
r->vulkan_buffer = cache->FindDepthTarget(buffer, g_render_ctx->GetGraphicCtx(), info);
if (meta_clear && !cache->TouchMeta(z.htile_data_base_addr, z.depth_view.slice_start, false)) {
DepthFatal("failed to consume HTile clear state");
+37 -1
View File
@@ -86,6 +86,7 @@ struct DepthTargetInfo {
bool depth_load_clear = false;
bool stencil_load_clear = false;
bool stencil_access = false;
bool stencil_htile_compressed = false;
};
enum class VideoOutCompression : uint8_t { Uncompressed, Dcc256_64_64, Unsupported };
@@ -171,6 +172,7 @@ struct VideoOutPixelFormatInfo {
}
enum class DepthOverlap : uint8_t { None, RetireSampled, Unsupported };
enum class DepthTransitionSource : uint8_t { None, Guest, Native };
enum class RenderTargetOverlap : uint8_t { None, RetireSampled, RetireTarget, Unsupported };
enum class SampledOverlap : uint8_t { None, ReadOnlyAlias, Unsupported };
enum class StorageSampledOverlap : uint8_t { None, ExactImage, Unsupported };
@@ -178,6 +180,19 @@ enum class HostWriteOverlap : uint8_t { None, InvalidateImage, Unsupported };
enum class BufferImageAlias : uint8_t { None, VideoOutWrite, RenderTargetWrite, Unsupported };
enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported };
[[nodiscard]] inline constexpr DepthTransitionSource
SelectDepthTransitionSource(bool depth_load_clear, bool sampled_native_available,
bool sampled_cpu_dirty, bool sampled_buffer_modified,
bool buffer_overlap, bool buffer_cpu_dirty) noexcept {
if (depth_load_clear) {
return DepthTransitionSource::None;
}
return sampled_native_available && !sampled_cpu_dirty && !sampled_buffer_modified &&
!(buffer_overlap && buffer_cpu_dirty)
? DepthTransitionSource::Native
: DepthTransitionSource::Guest;
}
[[nodiscard]] inline MetaImageOverlap ClassifyMetaImageOverlap(bool sampled, bool render_target,
bool gpu_modified,
bool buffer_modified) {
@@ -281,12 +296,17 @@ enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported
}
[[nodiscard]] inline bool CanLoadStencilAttachment(const DepthTargetInfo& target,
bool stencil_initialized) {
bool stencil_initialized) {
const bool has_stencil = target.stencil_address != 0 || target.stencil_size != 0;
return !has_stencil || !target.stencil_access || target.stencil_load_clear ||
stencil_initialized;
}
[[nodiscard]] inline bool CanLoadRawStencilPlane(const DepthTargetInfo& target) {
const bool has_stencil = target.stencil_address != 0 || target.stencil_size != 0;
return has_stencil && !target.stencil_htile_compressed;
}
[[nodiscard]] inline bool IsDepthTargetRangeCompatible(const DepthTargetInfo& target,
uint64_t address, uint64_t size) {
if (address == 0 || size == 0 || address > UINT64_MAX - size) {
@@ -414,6 +434,22 @@ ClassifyBufferImageAlias(uint64_t buffer_address, uint64_t buffer_size, uint64_t
return DepthOverlap::None;
}
const bool has_stencil = depth.stencil_address != 0 || depth.stencil_size != 0;
const bool exact_depth_format =
sampled.format == depth.guest_format &&
((depth.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k16UNorm) &&
depth.format == VK_FORMAT_D16_UNORM && depth.bytes_per_element == 2) ||
(depth.guest_format == Prospero::GpuEnumValue(Prospero::BufferFormat::k32Float) &&
depth.format == VK_FORMAT_D32_SFLOAT && depth.bytes_per_element == 4));
const bool exact_depth_load =
!has_stencil && !depth.depth_load_clear && sampled.address == depth.address &&
sampled.size == depth.size && sampled.width == depth.width && sampled.height == depth.height &&
sampled.pitch == depth.pitch && sampled.base_level == 0 && sampled.levels == 1 &&
sampled.view_levels == 1 && sampled.tile == depth.tile_mode && sampled.depth == 1 &&
sampled.type == Prospero::GpuEnumValue(Prospero::ImageType::kColor2D) &&
sampled.base_array == 0 && exact_depth_format;
if (!sampled_gpu_modified && exact_depth_load) {
return DepthOverlap::RetireSampled;
}
if (sampled.address == depth.address && !sampled_gpu_modified && depth.depth_load_clear &&
(!has_stencil ||
(depth.stencil_address != 0 && depth.stencil_size != 0 && depth.stencil_load_clear))) {
@@ -88,6 +88,7 @@ namespace Libs::Graphics {
switch (swizzle) {
case DstSel(4, 4, 4, 4): return VulkanImage::VIEW_DEPTH_TEXTURE;
case DstSel(4, 0, 0, 0): return VulkanImage::VIEW_R000;
case DstSel(4, 0, 0, 1): return VulkanImage::VIEW_R001;
default: break;
}
}
+4
View File
@@ -127,6 +127,10 @@ void RenderDispatchDirect(uint64_t submit_id, CommandBuffer* buffer, HW::Context
void GraphicsRenderInit();
void GraphicsRenderCreateContext();
[[nodiscard]] bool GraphicsScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency,
uint64_t* value);
[[nodiscard]] uint64_t GraphicsRenderReadReferenceClock();
[[nodiscard]] bool ResolveComputeImageClear(const ShaderComputeInputInfo& input, uint32_t group_x,
uint32_t group_y, uint32_t group_z, uint32_t mode,
ShaderBufferResource* descriptor,
+38 -2
View File
@@ -14,11 +14,47 @@
#include "libs/errno.h"
#include <cstring>
#include <limits>
namespace Libs::Graphics {
constexpr int GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT = 0x00;
constexpr int GRAPHICS_EVENT_EOP = 0x40;
constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000;
bool GraphicsScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t* value) {
if (host_frequency == 0 || value == nullptr) {
return false;
}
const auto whole_seconds = host_ticks / host_frequency;
const auto remainder = host_ticks % host_frequency;
constexpr auto MAX_VALUE = std::numeric_limits<uint64_t>::max();
if (whole_seconds > MAX_VALUE / GRAPHICS_REFERENCE_CLOCK_FREQUENCY ||
remainder > MAX_VALUE / GRAPHICS_REFERENCE_CLOCK_FREQUENCY) {
return false;
}
const auto whole_value = whole_seconds * GRAPHICS_REFERENCE_CLOCK_FREQUENCY;
const auto fractional_value =
(remainder * GRAPHICS_REFERENCE_CLOCK_FREQUENCY) / host_frequency;
if (whole_value > MAX_VALUE - fractional_value) {
return false;
}
*value = whole_value + fractional_value;
return true;
}
uint64_t GraphicsRenderReadReferenceClock() {
const auto host_frequency = LibKernel::KernelGetTscFrequency();
const auto host_ticks = LibKernel::KernelReadTsc();
uint64_t value = 0;
if (!GraphicsScaleReferenceClock(host_ticks, host_frequency, &value)) {
EXIT("cannot scale host clock, ticks=0x%016" PRIx64 " frequency=%" PRIu64 "\n",
host_ticks, host_frequency);
}
return value;
}
static void SubmitLabel32(CommandBuffer* buffer, uint32_t* dst, uint32_t value,
LabelCallback callback_1 = nullptr, LabelCallback callback_2 = nullptr,
@@ -158,7 +194,7 @@ void GraphicsRenderWriteAtEndOfPipeClockCounter(uint64_t submit_id, CommandBuffe
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWrite), submit_id, 8, 0, 0,
0, reinterpret_cast<uint64_t>(dst_gpu_addr));
const auto value = LibKernel::KernelReadTsc();
const auto value = GraphicsRenderReadReferenceClock();
PublishImmediateFence(dst_gpu_addr, value);
LOGF_COLOR(Log::Color::BrightGreen,
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
@@ -176,7 +212,7 @@ void GraphicsRenderWriteAtEndOfPipeClockCounterWithWriteBack(uint64_t subm
buffer->SetDebugInfo(static_cast<uint32_t>(CommandBufferDebugOp::EopWriteBack), submit_id, 8, 0,
0, 0, reinterpret_cast<uint64_t>(dst_gpu_addr));
const auto value = LibKernel::KernelReadTsc();
const auto value = GraphicsRenderReadReferenceClock();
PublishImmediateFence(dst_gpu_addr, value);
LOGF_COLOR(Log::Color::BrightGreen,
"EndOfPipe Signal!!! [0x%016" PRIx64 "] <- Clock: 0x%016" PRIx64 "\n",
+91 -32
View File
@@ -591,7 +591,8 @@ bool Equal(const DepthTargetInfo& left, const DepthTargetInfo& right) {
left.htile_size == right.htile_size && left.format == right.format &&
left.guest_format == right.guest_format && left.width == right.width &&
left.height == right.height && left.pitch == right.pitch &&
left.bytes_per_element == right.bytes_per_element && left.tile_mode == right.tile_mode;
left.bytes_per_element == right.bytes_per_element && left.tile_mode == right.tile_mode &&
left.stencil_htile_compressed == right.stencil_htile_compressed;
}
[[nodiscard]] bool IsCoherentGuestImageSource(const BufferImageCopySource& source,
@@ -863,6 +864,11 @@ void CreateDepthViews(GraphicContext* ctx, DepthStencilVulkanImage* image) {
{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO},
0, 0, 1, 1);
UtilCreateImageView(ctx, image, VulkanImage::VIEW_R001, VK_IMAGE_VIEW_TYPE_2D,
VK_IMAGE_ASPECT_DEPTH_BIT,
{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE},
0, 0, 1, 1);
}
DepthStencilVulkanImage* CreateDepthTarget(GraphicContext* ctx, const DepthTargetInfo& info,
@@ -1840,6 +1846,7 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
PageOverlaps(info.address, info.size, info.htile_address, info.htile_size) ||
(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) &&
@@ -1871,14 +1878,23 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
" elements=0x%016" PRIx64 "\n",
info.stencil_size, elements);
}
if (has_stencil && !info.stencil_load_clear && !CanLoadRawStencilPlane(info)) {
EXIT("TextureCache: HTile-compressed stencil load is unsupported, addr=0x%016" PRIx64
" size=0x%016" PRIx64 " htile=0x%016" PRIx64 "+0x%016" PRIx64 "\n",
info.stencil_address, info.stencil_size, info.htile_address, info.htile_size);
}
if (has_htile) {
RegisterMeta(info.htile_address, info.htile_size);
}
std::lock_guard transaction(m_resource_mutex);
const auto depth_source = m_buffer_cache.ObtainBufferForImage(info.address, info.size);
if (has_stencil) {
(void)m_buffer_cache.ObtainBufferForImage(info.stencil_address, info.stencil_size);
}
// BufferCache treats an untracked guest range as CPU-current. That is useful when
// uploading from guest memory, but it is not evidence that a clean native image is
// stale. Only a genuinely overlapping buffer participates in transition selection.
const bool depth_buffer_overlap = m_buffer_cache.HasPageOverlap(info.address, info.size);
const auto depth_source = m_buffer_cache.ObtainBufferForImage(info.address, info.size);
const auto stencil_source =
has_stencil ? m_buffer_cache.ObtainBufferForImage(info.stencil_address, info.stencil_size)
: BufferImageCopySource {};
FaultSafeTextureLock lock(this, m_lock);
RequireNoMetaOverlapLocked(info.address, info.size);
if (has_stencil) {
@@ -1900,37 +1916,32 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
if (has_stencil && info.stencil_load_clear) {
match->stencil_initialized = true;
}
if (!match->gpu_modified && m_memory_tracker.IsRegionCpuModified(info.address, info.size)) {
if (has_stencil && match->stencil_initialized && !info.stencil_load_clear) {
EXIT("TextureCache: depth refresh would discard initialized stencil, "
"addr=0x%016" PRIx64 "\n",
info.address);
}
if (!match->gpu_modified && depth_source.cpu_dirty) {
m_memory_tracker.ForEachUploadRange(
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
[&]() noexcept {
m_tiler.DetileImage(ctx,
static_cast<DepthStencilVulkanImage*>(match->image),
match->depth, depth_source, true);
static_cast<DepthStencilVulkanImage*>(match->image),
match->depth, depth_source, true);
});
}
if (!match->gpu_modified && has_stencil &&
m_memory_tracker.IsRegionCpuModified(info.stencil_address, info.stencil_size)) {
if (!info.stencil_load_clear) {
if (info.stencil_access) {
EXIT("TextureCache: stencil refresh from guest memory is unsupported, "
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
info.stencil_address, info.stencil_size);
}
} else {
m_memory_tracker.ForEachUploadRange(
info.stencil_address, info.stencil_size, false,
[](uint64_t, uint64_t) noexcept {}, []() noexcept {});
}
if (!match->gpu_modified && has_stencil && stencil_source.cpu_dirty) {
m_memory_tracker.ForEachUploadRange(
info.stencil_address, info.stencil_size, false,
[](uint64_t, uint64_t) noexcept {},
[&]() noexcept {
if (!info.stencil_load_clear) {
m_tiler.DetileStencil(
ctx, static_cast<DepthStencilVulkanImage*>(match->image), match->depth,
stencil_source, true);
match->stencil_initialized = true;
}
});
}
return static_cast<DepthStencilVulkanImage*>(match->image);
}
std::vector<CachedImage*> retire;
std::shared_ptr<CachedImage> sampled_depth_source;
for (const auto& entry: m_images) {
auto& cached = *entry;
const bool overlaps =
@@ -1947,6 +1958,9 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
info.address, info.size, static_cast<uint32_t>(cached.kind), cached.Address(),
cached.Size());
}
if (!info.depth_load_clear && sampled_depth_source == nullptr) {
sampled_depth_source = entry;
}
retire.push_back(&cached);
}
std::vector<ImageRetirementRange> ranges;
@@ -1979,19 +1993,64 @@ DepthStencilVulkanImage* TextureCache::FindDepthTarget(CommandBuffer* command, G
cached->ctx = ctx;
cached->stencil_initialized = !has_stencil || info.stencil_load_clear;
cached->image = CreateDepthTarget(ctx, info, &cached->memory);
if (sampled_depth_source != nullptr &&
(sampled_depth_source->image->type != VulkanImageType::Texture ||
sampled_depth_source->image->format != Prospero::SurfaceFormat(info.guest_format) ||
sampled_depth_source->image->extent.width != info.width ||
sampled_depth_source->image->extent.height != info.height)) {
EXIT("TextureCache: sampled-depth native source is inconsistent, format=%d/%d "
"extent=%ux%u/%ux%u type=%u\n",
static_cast<int>(sampled_depth_source->image->format),
static_cast<int>(Prospero::SurfaceFormat(info.guest_format)),
sampled_depth_source->image->extent.width,
sampled_depth_source->image->extent.height, info.width, info.height,
static_cast<uint32_t>(sampled_depth_source->image->type));
}
const auto transition_source = SelectDepthTransitionSource(
info.depth_load_clear, sampled_depth_source != nullptr,
sampled_depth_source != nullptr && sampled_depth_source->info.IsCpuDirty(),
sampled_depth_source != nullptr && sampled_depth_source->buffer_modified,
depth_buffer_overlap, depth_source.cpu_dirty);
LOGF("TextureCache: depth transition source=%u sampled=%d sampled_cpu_dirty=%d "
"sampled_buffer_dirty=%d buffer_overlap=%d buffer_cpu_dirty=%d addr=0x%016" PRIx64
" size=0x%016" PRIx64 "\n",
static_cast<uint32_t>(transition_source), sampled_depth_source != nullptr,
sampled_depth_source != nullptr && sampled_depth_source->info.IsCpuDirty(),
sampled_depth_source != nullptr && sampled_depth_source->buffer_modified,
depth_buffer_overlap, depth_source.cpu_dirty, info.address, info.size);
m_memory_tracker.ForEachUploadRange(
info.address, info.size, false, [](uint64_t, uint64_t) noexcept {},
[&]() noexcept {
if (!info.depth_load_clear) {
m_tiler.DetileImage(ctx,
static_cast<DepthStencilVulkanImage*>(cached->image),
info, depth_source, false);
switch (transition_source) {
case DepthTransitionSource::None: break;
case DepthTransitionSource::Guest:
m_tiler.DetileImage(ctx, static_cast<DepthStencilVulkanImage*>(cached->image),
info, depth_source, false);
break;
case DepthTransitionSource::Native:
command->RetainResourceUntilFence(sampled_depth_source);
UtilCopyImageWithBuffer(
command, ctx, sampled_depth_source->image, VK_IMAGE_ASPECT_COLOR_BIT,
cached->image, VK_IMAGE_ASPECT_DEPTH_BIT, info.bytes_per_element,
static_cast<uint64_t>(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));
LOGF("TextureCache: preserved sampled depth through native buffer copy, "
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n",
info.address, info.size);
break;
}
});
if (has_stencil) {
m_memory_tracker.ForEachUploadRange(
info.stencil_address, info.stencil_size, false, [](uint64_t, uint64_t) noexcept {},
[]() noexcept {});
info.stencil_address, info.stencil_size, false,
[](uint64_t, uint64_t) noexcept {},
[&]() noexcept {
if (!info.stencil_load_clear) {
m_tiler.DetileStencil(
ctx, static_cast<DepthStencilVulkanImage*>(cached->image), info,
stencil_source, false);
}
});
cached->stencil_initialized = true;
}
auto* image = static_cast<DepthStencilVulkanImage*>(cached->image);
m_images.push_back(std::move(cached));
+50 -3
View File
@@ -50,8 +50,8 @@ void Tiler::DetileImage(GraphicContext* ctx, GpuTextureVulkanImage* image,
}
void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh) const {
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh) 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 =
@@ -80,7 +80,54 @@ void Tiler::DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
TileConvertTiledToLinearDepth(linear.Data(), reinterpret_cast<const void*>(source.address),
info.guest_format, info.width, info.height, info.pitch,
info.size);
UtilFillDepthImage(ctx, image, linear.Data(), info.size, info.pitch);
UtilFillImage(ctx, image, linear.Data(), info.size, info.pitch, VK_IMAGE_ASPECT_DEPTH_BIT);
}
void Tiler::DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh) const {
TileSizeAlign stencil_size {};
TileSizeAlign htile_size {};
TileSizeAlign depth_size {};
const auto stencil_format = Prospero::GpuEnumValue(Prospero::BufferFormat::k8UInt);
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),
Prospero::GpuEnumValue(Prospero::StencilFormat::k8UInt),
info.htile_address != 0, &stencil_size, &htile_size, &depth_size) &&
stencil_size.size == info.stencil_size && stencil_size.align == 65536 &&
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 ||
info.tile_mode != Prospero::GpuEnumValue(Prospero::TileMode::kDepth) ||
info.stencil_htile_compressed || !supported_layout || !source.cpu_current ||
source.address != info.stencil_address ||
source.size != info.stencil_size || (source.buffer == nullptr && source.offset != 0)) {
EXIT("Tiler: unsupported stencil detile, ctx=%p image=%p source_buffer=%p "
"source=0x%016" PRIx64 "+0x%016" PRIx64 " offset=0x%016" PRIx64
" current=%d stencil=0x%016" PRIx64 "+0x%016" PRIx64
" extent=%ux%u depth_pitch=%u stencil_pitch=%u tile=%u format=%d guest_format=%u "
"bpe=%u\n",
static_cast<const void*>(ctx), static_cast<const void*>(image),
static_cast<const void*>(source.buffer), source.address, source.size, source.offset,
source.cpu_current, info.stencil_address, info.stencil_size, info.width, info.height,
info.pitch, stencil_pitch, info.tile_mode, static_cast<int>(info.format),
info.guest_format, info.bytes_per_element);
}
if (refresh) {
VulkanDeviceWaitIdle(ctx);
}
UtilScratchBuffer linear(info.stencil_size);
TileConvertTiledToLinearDepth(linear.Data(), reinterpret_cast<const void*>(source.address),
stencil_format, info.width, info.height, stencil_pitch,
info.stencil_size);
UtilFillImage(ctx, image, linear.Data(), info.stencil_size, stencil_pitch,
VK_IMAGE_ASPECT_STENCIL_BIT);
}
void Tiler::TileImage(void* dst, const void* src, const RenderTargetInfo& info) const {
+3
View File
@@ -21,6 +21,9 @@ public:
void DetileImage(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh) const;
void DetileStencil(GraphicContext* ctx, DepthStencilVulkanImage* image,
const DepthTargetInfo& info, const BufferImageCopySource& source,
bool refresh) const;
void TileImage(void* dst, const void* src, const RenderTargetInfo& info) const;
void TileImage(void* dst, const void* src, const DepthTargetInfo& info) const;
};