mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
Synchronize GPU-owned VideoOut with formatted buffers
This commit is contained in:
@@ -330,6 +330,7 @@ enum class BufferImageWrite : uint8_t {
|
|||||||
InvalidateTexture,
|
InvalidateTexture,
|
||||||
InvalidateVideoOut,
|
InvalidateVideoOut,
|
||||||
SynchronizeRenderTarget,
|
SynchronizeRenderTarget,
|
||||||
|
SynchronizeVideoOut,
|
||||||
Unsupported
|
Unsupported
|
||||||
};
|
};
|
||||||
enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported };
|
enum class MetaImageOverlap : uint8_t { RetainSampled, RetireTarget, Unsupported };
|
||||||
@@ -613,9 +614,11 @@ ClassifyBufferImageWrite(uint64_t buffer_address, uint64_t buffer_size, uint64_t
|
|||||||
? BufferImageWrite::InvalidateTexture
|
? BufferImageWrite::InvalidateTexture
|
||||||
: BufferImageWrite::Unsupported;
|
: BufferImageWrite::Unsupported;
|
||||||
case BufferImageBinding::VideoOut:
|
case BufferImageBinding::VideoOut:
|
||||||
return exact && buffer_formatted && !image_gpu_modified
|
if (!exact || !buffer_page_aligned || !buffer_formatted) {
|
||||||
? BufferImageWrite::InvalidateVideoOut
|
return BufferImageWrite::Unsupported;
|
||||||
: BufferImageWrite::Unsupported;
|
}
|
||||||
|
return image_gpu_modified ? BufferImageWrite::SynchronizeVideoOut
|
||||||
|
: BufferImageWrite::InvalidateVideoOut;
|
||||||
case BufferImageBinding::RenderTarget:
|
case BufferImageBinding::RenderTarget:
|
||||||
return exact && buffer_page_aligned && buffer_formatted && image_gpu_modified
|
return exact && buffer_page_aligned && buffer_formatted && image_gpu_modified
|
||||||
? BufferImageWrite::SynchronizeRenderTarget
|
? BufferImageWrite::SynchronizeRenderTarget
|
||||||
|
|||||||
@@ -3098,11 +3098,26 @@ void TextureCache::PrepareHostWrite(uint64_t vaddr, uint64_t size) {
|
|||||||
MarkSampledAliasesCpuDirtyLocked(vaddr, size);
|
MarkSampledAliasesCpuDirtyLocked(vaddr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
void TextureCache::SynchronizeColorImageToBufferLocked(CachedImage& cached) {
|
||||||
const auto& target = cached.target;
|
const bool render_target = cached.kind == CachedImage::Kind::RenderTarget;
|
||||||
|
const bool video_out = cached.kind == CachedImage::Kind::VideoOut;
|
||||||
|
RenderTargetInfo target {};
|
||||||
|
if (render_target) {
|
||||||
|
target = cached.target;
|
||||||
|
} else if (video_out) {
|
||||||
|
const auto& info = cached.video_out;
|
||||||
|
target.address = info.address;
|
||||||
|
target.size = info.size;
|
||||||
|
target.format = info.format;
|
||||||
|
target.width = info.width;
|
||||||
|
target.height = info.height;
|
||||||
|
target.pitch = info.pitch;
|
||||||
|
target.bytes_per_element = info.bytes_per_element;
|
||||||
|
target.tile_mode = info.tile_mode;
|
||||||
|
}
|
||||||
const bool linear = target.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
const bool linear = target.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kLinear);
|
||||||
const bool tiled = IsTiledRenderTarget(target);
|
const bool tiled = IsTiledRenderTarget(target);
|
||||||
const auto rows = static_cast<uint64_t>(target.height - 1);
|
const auto rows = static_cast<uint64_t>(target.height - 1);
|
||||||
TileSizeAlign exact {};
|
TileSizeAlign exact {};
|
||||||
bool single_slice = false;
|
bool single_slice = false;
|
||||||
if (IsSupportedStandard64RenderTarget(target)) {
|
if (IsSupportedStandard64RenderTarget(target)) {
|
||||||
@@ -3116,13 +3131,18 @@ void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
|||||||
single_slice = TileGetRenderTargetSize(target.width, target.height, target.pitch,
|
single_slice = TileGetRenderTargetSize(target.width, target.height, target.pitch,
|
||||||
target.bytes_per_element, &exact);
|
target.bytes_per_element, &exact);
|
||||||
}
|
}
|
||||||
const bool layered_size = target.layers != 0 && single_slice &&
|
const bool layered_size = target.layers != 0 && single_slice &&
|
||||||
exact.size <= UINT64_MAX / target.layers &&
|
exact.size <= UINT64_MAX / target.layers &&
|
||||||
exact.size * target.layers == target.size;
|
exact.size * target.layers == target.size;
|
||||||
const bool exact_tiled = tiled && exact.align == 65536 && layered_size;
|
const bool exact_tiled = tiled && exact.align == 65536 && layered_size;
|
||||||
const bool valid_cache = cached.kind == CachedImage::Kind::RenderTarget &&
|
const bool valid_video_out =
|
||||||
cached.gpu_modified && !cached.buffer_modified &&
|
video_out && cached.video_out.compression == VideoOutCompression::Uncompressed &&
|
||||||
cached.ctx != nullptr && cached.image != nullptr;
|
cached.video_out.metadata_address == 0 && cached.video_out.dcc_control == 0 &&
|
||||||
|
target.tile_mode == Prospero::GpuEnumValue(Prospero::TileMode::kRenderTarget) &&
|
||||||
|
target.bytes_per_element == 4 && (target.address & 0xffffu) == 0;
|
||||||
|
const bool valid_cache = (render_target || valid_video_out) && cached.gpu_modified &&
|
||||||
|
!cached.buffer_modified && cached.ctx != nullptr &&
|
||||||
|
cached.image != nullptr;
|
||||||
const bool valid_target =
|
const bool valid_target =
|
||||||
target.address != 0 && target.size != 0 && target.width != 0 && target.height != 0 &&
|
target.address != 0 && target.size != 0 && target.width != 0 && target.height != 0 &&
|
||||||
target.pitch >= target.width && target.bytes_per_element != 0 && target.layers != 0 &&
|
target.pitch >= target.width && target.bytes_per_element != 0 && target.layers != 0 &&
|
||||||
@@ -3130,18 +3150,20 @@ void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
|||||||
rows <= (UINT64_MAX - target.width) / target.pitch;
|
rows <= (UINT64_MAX - target.width) / target.pitch;
|
||||||
const bool valid_image = cached.image != nullptr && cached.image->layers == target.layers;
|
const bool valid_image = cached.image != nullptr && cached.image->layers == target.layers;
|
||||||
if (!valid_cache || !valid_target || (!linear && !exact_tiled) || !valid_image) {
|
if (!valid_cache || !valid_target || (!linear && !exact_tiled) || !valid_image) {
|
||||||
EXIT("TextureCache: unsupported render-target buffer synchronization, "
|
EXIT("TextureCache: unsupported color-image buffer synchronization, "
|
||||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
"addr=0x%016" PRIx64 " size=0x%016" PRIx64
|
||||||
" extent=%ux%u pitch=%u bpe=%u levels=%u layers=%u/%u tile=%u"
|
" extent=%ux%u pitch=%u bpe=%u levels=%u layers=%u/%u tile=%u"
|
||||||
" gpu_modified=%d buffer_modified=%d\n",
|
" kind=%u compression=%u gpu_modified=%d buffer_modified=%d\n",
|
||||||
target.address, target.size, target.width, target.height, target.pitch,
|
target.address, target.size, target.width, target.height, target.pitch,
|
||||||
target.bytes_per_element, target.levels, target.layers,
|
target.bytes_per_element, target.levels, target.layers,
|
||||||
cached.image == nullptr ? 0 : cached.image->layers, target.tile_mode,
|
cached.image == nullptr ? 0 : cached.image->layers, target.tile_mode,
|
||||||
|
static_cast<uint32_t>(cached.kind),
|
||||||
|
video_out ? static_cast<uint32_t>(cached.video_out.compression) : 0,
|
||||||
cached.gpu_modified, cached.buffer_modified);
|
cached.gpu_modified, cached.buffer_modified);
|
||||||
}
|
}
|
||||||
const auto linear_elements = rows * target.pitch + target.width;
|
const auto linear_elements = rows * target.pitch + target.width;
|
||||||
if (linear_elements > UINT64_MAX / target.bytes_per_element) {
|
if (linear_elements > UINT64_MAX / target.bytes_per_element) {
|
||||||
EXIT("TextureCache: render-target buffer synchronization size overflow\n");
|
EXIT("TextureCache: color-image buffer synchronization size overflow\n");
|
||||||
}
|
}
|
||||||
const auto linear_size = linear_elements * target.bytes_per_element;
|
const auto linear_size = linear_elements * target.bytes_per_element;
|
||||||
const auto slice_size = target.size / target.layers;
|
const auto slice_size = target.size / target.layers;
|
||||||
@@ -3150,7 +3172,7 @@ void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
|||||||
cached.image->extent.height != target.height ||
|
cached.image->extent.height != target.height ||
|
||||||
(tiled && !IsSupportedRenderTargetElementSize(target.bytes_per_element)) ||
|
(tiled && !IsSupportedRenderTargetElementSize(target.bytes_per_element)) ||
|
||||||
HasMetaOverlapLocked(target.address, target.size)) {
|
HasMetaOverlapLocked(target.address, target.size)) {
|
||||||
EXIT("TextureCache: render-target buffer synchronization storage mismatch, "
|
EXIT("TextureCache: color-image buffer synchronization storage mismatch, "
|
||||||
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 " linear=0x%016" PRIx64 "\n",
|
"addr=0x%016" PRIx64 " size=0x%016" PRIx64 " linear=0x%016" PRIx64 "\n",
|
||||||
target.address, target.size, linear_size);
|
target.address, target.size, linear_size);
|
||||||
}
|
}
|
||||||
@@ -3178,7 +3200,7 @@ void TextureCache::SynchronizeRenderTargetToBufferLocked(CachedImage& cached) {
|
|||||||
m_memory_tracker.ForEachDownloadRange<true>(target.address, target.size,
|
m_memory_tracker.ForEachDownloadRange<true>(target.address, target.size,
|
||||||
[](uint64_t, uint64_t) noexcept {});
|
[](uint64_t, uint64_t) noexcept {});
|
||||||
if (m_memory_tracker.IsRegionGpuModified(target.address, target.size)) {
|
if (m_memory_tracker.IsRegionGpuModified(target.address, target.size)) {
|
||||||
EXIT("TextureCache: render-target buffer synchronization retained GPU ownership\n");
|
EXIT("TextureCache: color-image buffer synchronization retained GPU ownership\n");
|
||||||
}
|
}
|
||||||
m_buffer_cache.PublishImageBacking(target.address, target.size);
|
m_buffer_cache.PublishImageBacking(target.address, target.size);
|
||||||
cached.gpu_modified = false;
|
cached.gpu_modified = false;
|
||||||
@@ -3240,7 +3262,18 @@ bool TextureCache::InvalidateMemoryFromGPU(uint64_t vaddr, uint64_t size,
|
|||||||
case BufferImageWrite::InvalidateTexture:
|
case BufferImageWrite::InvalidateTexture:
|
||||||
case BufferImageWrite::InvalidateVideoOut: cached.buffer_modified = true; return true;
|
case BufferImageWrite::InvalidateVideoOut: cached.buffer_modified = true; return true;
|
||||||
case BufferImageWrite::SynchronizeRenderTarget:
|
case BufferImageWrite::SynchronizeRenderTarget:
|
||||||
SynchronizeRenderTargetToBufferLocked(cached);
|
if (cached.kind != CachedImage::Kind::RenderTarget) {
|
||||||
|
EXIT("TextureCache: render-target synchronization action has kind=%u\n",
|
||||||
|
static_cast<uint32_t>(cached.kind));
|
||||||
|
}
|
||||||
|
SynchronizeColorImageToBufferLocked(cached);
|
||||||
|
return true;
|
||||||
|
case BufferImageWrite::SynchronizeVideoOut:
|
||||||
|
if (cached.kind != CachedImage::Kind::VideoOut) {
|
||||||
|
EXIT("TextureCache: video-out synchronization action has kind=%u\n",
|
||||||
|
static_cast<uint32_t>(cached.kind));
|
||||||
|
}
|
||||||
|
SynchronizeColorImageToBufferLocked(cached);
|
||||||
return true;
|
return true;
|
||||||
case BufferImageWrite::None:
|
case BufferImageWrite::None:
|
||||||
case BufferImageWrite::Unsupported:
|
case BufferImageWrite::Unsupported:
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ private:
|
|||||||
uint64_t address, uint64_t size) const;
|
uint64_t address, uint64_t size) const;
|
||||||
void RetireImages(const std::vector<CachedImage*>& retire,
|
void RetireImages(const std::vector<CachedImage*>& retire,
|
||||||
const CachedImage* native_image_source = nullptr);
|
const CachedImage* native_image_source = nullptr);
|
||||||
void SynchronizeRenderTargetToBufferLocked(CachedImage& cached);
|
void SynchronizeColorImageToBufferLocked(CachedImage& cached);
|
||||||
|
|
||||||
Common::Mutex m_dummy_mutex;
|
Common::Mutex m_dummy_mutex;
|
||||||
std::array<VulkanImage*, 4> m_dummy_sampled_textures {};
|
std::array<VulkanImage*, 4> m_dummy_sampled_textures {};
|
||||||
|
|||||||
@@ -10648,10 +10648,19 @@ void CheckBufferImageWrites() {
|
|||||||
BufferImageWrite::Unsupported},
|
BufferImageWrite::Unsupported},
|
||||||
Case{"video GPU-owned", video, video_size, video, video_size,
|
Case{"video GPU-owned", video, video_size, video, video_size,
|
||||||
BufferImageBinding::VideoOut, true, true,
|
BufferImageBinding::VideoOut, true, true,
|
||||||
BufferImageWrite::Unsupported},
|
BufferImageWrite::SynchronizeVideoOut},
|
||||||
Case{"video unformatted", video, video_size, video, video_size,
|
Case{"video unformatted", video, video_size, video, video_size,
|
||||||
BufferImageBinding::VideoOut, false, false,
|
BufferImageBinding::VideoOut, false, false,
|
||||||
BufferImageWrite::Unsupported},
|
BufferImageWrite::Unsupported},
|
||||||
|
Case{"video GPU-owned unformatted", video, video_size, video, video_size,
|
||||||
|
BufferImageBinding::VideoOut, true, false,
|
||||||
|
BufferImageWrite::Unsupported},
|
||||||
|
Case{"video GPU-owned partial", video, video_size - 4, video, video_size,
|
||||||
|
BufferImageBinding::VideoOut, true, true,
|
||||||
|
BufferImageWrite::Unsupported},
|
||||||
|
Case{"video unaligned", video + 0x100, video_size, video + 0x100,
|
||||||
|
video_size, BufferImageBinding::VideoOut, true, true,
|
||||||
|
BufferImageWrite::Unsupported},
|
||||||
Case{"target exact", target, target_size, target, target_size,
|
Case{"target exact", target, target_size, target, target_size,
|
||||||
BufferImageBinding::RenderTarget, true, true,
|
BufferImageBinding::RenderTarget, true, true,
|
||||||
BufferImageWrite::SynchronizeRenderTarget},
|
BufferImageWrite::SynchronizeRenderTarget},
|
||||||
@@ -10682,6 +10691,11 @@ void CheckBufferImageWrites() {
|
|||||||
TileGetRenderTargetSize(1920, 1080, 1920, 4, &storage) &&
|
TileGetRenderTargetSize(1920, 1080, 1920, 4, &storage) &&
|
||||||
storage.align == 0x10000 && storage.size == target_size,
|
storage.align == 0x10000 && storage.size == target_size,
|
||||||
"render-target write fixture has an invalid tiled layout");
|
"render-target write fixture has an invalid tiled layout");
|
||||||
|
Require("BufferImageWrite", "PPSA02721 video layout",
|
||||||
|
TileGetRenderTargetPitch(3840, 4) == 3840 &&
|
||||||
|
TileGetRenderTargetSize(3840, 2160, 3840, 4, &storage) &&
|
||||||
|
storage.align == 0x10000 && storage.size == video_size,
|
||||||
|
"4K video-out ownership fixture lost its exact tiled layout");
|
||||||
std::printf("[host] %-32s ok\n", "BufferImageWrite");
|
std::printf("[host] %-32s ok\n", "BufferImageWrite");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user