mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 14:26:53 +01:00
gpu: create texture views before rebinding overlapping images
This commit is contained in:
+2
-1
@@ -714,7 +714,8 @@ ImageId TextureCache::ResolveDepthOverlap(const ImageInfo& requested, BindingTyp
|
|||||||
cached.info.data.size / cached.info.resources.layers &&
|
cached.info.data.size / cached.info.resources.layers &&
|
||||||
!requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() &&
|
!requested.HasStencil() && !cached.info.HasStencil() && !requested.HasMetadata() &&
|
||||||
!cached.info.HasMetadata();
|
!cached.info.HasMetadata();
|
||||||
bool recreate = cached.info.resources < requested.resources;
|
bool recreate = cached.info.resources < requested.resources ||
|
||||||
|
requested.IsVolume() != cached.info.IsVolume();
|
||||||
switch (binding) {
|
switch (binding) {
|
||||||
case BindingType::Texture:
|
case BindingType::Texture:
|
||||||
recreate |= requested.IsDepth() && !cached.info.IsDepth();
|
recreate |= requested.IsDepth() && !cached.info.IsDepth();
|
||||||
|
|||||||
@@ -876,6 +876,7 @@ void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
|||||||
auto& images = prepared.images;
|
auto& images = prepared.images;
|
||||||
EXIT_IF(images.size() != program.info.images.size());
|
EXIT_IF(images.size() != program.info.images.size());
|
||||||
auto& texture_cache = m_context.GetTextureCache();
|
auto& texture_cache = m_context.GetTextureCache();
|
||||||
|
// Acquire each view before a later overlapping descriptor can replace its image.
|
||||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
||||||
const auto old_image = texture_cache.m_slot_images.try_get(images[i].image_id);
|
const auto old_image = texture_cache.m_slot_images.try_get(images[i].image_id);
|
||||||
if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
|
if (old_image == nullptr || (!old_image->registered && !old_image->info.data.Empty()) ||
|
||||||
@@ -887,8 +888,6 @@ void RenderExecutor::RebindImages(PreparedBindings& prepared) {
|
|||||||
BindImage(images[i].image_id,
|
BindImage(images[i].image_id,
|
||||||
images[i].desc.type == TextureCache::BindingType::Storage);
|
images[i].desc.type == TextureCache::BindingType::Storage);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < program.info.images.size(); i++) {
|
|
||||||
auto& binding = images[i];
|
auto& binding = images[i];
|
||||||
binding.mip_views.clear();
|
binding.mip_views.clear();
|
||||||
const auto& resource = program.info.images[i];
|
const auto& resource = program.info.images[i];
|
||||||
|
|||||||
@@ -11507,7 +11507,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto buffer_program = make_buffer_program(ShaderType::Compute, {.read = true});
|
const auto buffer_program = make_buffer_program(ShaderType::Compute, {.read = true, .written = true});
|
||||||
constexpr uint64_t buffer_address = base + 0xe0002;
|
constexpr uint64_t buffer_address = base + 0xe0002;
|
||||||
ShaderBufferResource descriptor{};
|
ShaderBufferResource descriptor{};
|
||||||
descriptor.UpdateAddress48(buffer_address);
|
descriptor.UpdateAddress48(buffer_address);
|
||||||
@@ -11532,6 +11532,90 @@ public:
|
|||||||
"native binding lost the byte adjustment or rounded the final halfword range");
|
"native binding lost the byte adjustment or rounded the final halfword range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto format : {Prospero::BufferFormat::k8UNorm,
|
||||||
|
Prospero::BufferFormat::k16UNorm}) {
|
||||||
|
const uint64_t alias_address = base + 0xe00000 +
|
||||||
|
Prospero::NumBytesPerElement(format) * 0x10000;
|
||||||
|
constexpr uint8_t texel = 0x7f;
|
||||||
|
Libs::LibKernel::Memory::WriteBacking(alias_address, &texel, sizeof(texel));
|
||||||
|
u32 expected = texel;
|
||||||
|
if (format == Prospero::BufferFormat::k16UNorm) {
|
||||||
|
auto depth_desc = MakeLinearDesc(alias_address, 256, vk::Format::eD16Unorm,
|
||||||
|
format, Prospero::ImageType::kColor2D, {1, 1, 1}, 1, 2, 1);
|
||||||
|
depth_desc.info.pitch = 128;
|
||||||
|
depth_desc.info.mip_layout[0] = {0, 256, 128, 1};
|
||||||
|
depth_desc.type = BindingType::DepthTarget;
|
||||||
|
depth_desc.view_info.aspect = vk::ImageAspectFlagBits::eDepth;
|
||||||
|
depth_desc.view_info.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
||||||
|
const auto depth_id = texture_cache.FindImage(depth_desc);
|
||||||
|
auto &depth = texture_cache.GetImage(depth_id);
|
||||||
|
depth.Transit(vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
vk::AccessFlagBits2::eTransferWrite, {}, scheduler.Current().Handle());
|
||||||
|
const vk::ImageSubresourceRange range{vk::ImageAspectFlagBits::eDepth, 0, 1, 0, 1};
|
||||||
|
scheduler.Current().Handle().clearDepthStencilImage(depth.backing.image,
|
||||||
|
vk::ImageLayout::eTransferDstOptimal, vk::ClearDepthStencilValue{1.f, 0}, range);
|
||||||
|
texture_cache.MarkGpuWritten(depth_id);
|
||||||
|
expected = 0xffff;
|
||||||
|
}
|
||||||
|
ShaderRecompiler::IR::CompiledShaderInfo program{};
|
||||||
|
program.stage = ShaderType::Compute;
|
||||||
|
ShaderRecompiler::IR::ResourceSnapshot snapshot;
|
||||||
|
// PPSA24156 binds one-texel R8/R16 allocations as 3D, then 2D.
|
||||||
|
for (const auto type : {Prospero::ImageType::kColor3D,
|
||||||
|
Prospero::ImageType::kColor2D}) {
|
||||||
|
ShaderRecompiler::IR::ImageResource resource{};
|
||||||
|
resource.resource_class = ShaderRecompiler::IR::ImageResourceClass::Sampled;
|
||||||
|
resource.read = true;
|
||||||
|
resource.numeric_class = Prospero::TextureNumericClass::Float;
|
||||||
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim2D;
|
||||||
|
if (type == Prospero::ImageType::kColor3D) {
|
||||||
|
resource.dimension = ShaderRecompiler::Decoder::ImageDimension::Dim3D;
|
||||||
|
}
|
||||||
|
program.info.images.push_back(resource);
|
||||||
|
auto &value = snapshot.images.emplace_back();
|
||||||
|
value.dword_count = 8;
|
||||||
|
value.dwords = {static_cast<u32>(alias_address >> 8u),
|
||||||
|
static_cast<u32>(format) << 20u, 0,
|
||||||
|
DstSel(4, 4, 4, 1) | (static_cast<u32>(type) << 28u),
|
||||||
|
0, 0x00700000u, 0, 0};
|
||||||
|
}
|
||||||
|
ShaderStageRuntime runtime{&program, &snapshot};
|
||||||
|
PreparedBindings bindings;
|
||||||
|
executor.PrepareBindings(runtime, bindings);
|
||||||
|
Require(name, "overlapping dimension discovery",
|
||||||
|
!texture_cache.GetImage(bindings.images[0].image_id).registered,
|
||||||
|
"the 2D descriptor did not replace its earlier 3D alias");
|
||||||
|
executor.RebindImages(bindings);
|
||||||
|
auto output = CreateHostBuffer(name, 8, vk::BufferUsageFlagBits::eTransferDst, {0, 0});
|
||||||
|
constexpr std::array image_types{vk::ImageType::e3D, vk::ImageType::e2D};
|
||||||
|
for (u32 i = 0; i < bindings.images.size(); ++i) {
|
||||||
|
const auto &binding = bindings.images[i];
|
||||||
|
auto &image = texture_cache.GetImage(binding.image_id);
|
||||||
|
Require(name, "overlapping dimension views", binding.image_view != nullptr &&
|
||||||
|
image.backing.image_type == image_types[i],
|
||||||
|
"rediscovery lost a live view or the descriptor's image dimension");
|
||||||
|
image.Transit(vk::ImageLayout::eTransferSrcOptimal,
|
||||||
|
vk::AccessFlagBits2::eTransferRead, {}, scheduler.Current().Handle());
|
||||||
|
vk::BufferImageCopy copy{};
|
||||||
|
copy.bufferOffset = i * sizeof(u32);
|
||||||
|
copy.imageSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
|
||||||
|
copy.imageExtent = {1, 1, 1};
|
||||||
|
scheduler.Current().Handle().copyImageToBuffer(image.backing.image,
|
||||||
|
vk::ImageLayout::eTransferSrcOptimal, output.buffer, 1, ©);
|
||||||
|
}
|
||||||
|
vk::MemoryBarrier barrier{};
|
||||||
|
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||||
|
barrier.dstAccessMask = vk::AccessFlagBits::eHostRead;
|
||||||
|
scheduler.Current().Handle().pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
|
||||||
|
vk::PipelineStageFlagBits::eHost, {}, 1, &barrier, 0, nullptr, 0, nullptr);
|
||||||
|
RenderExecutorTestAccess::ResetBindings(executor);
|
||||||
|
scheduler.Finish();
|
||||||
|
Require(name, "overlapping dimension GPU contents",
|
||||||
|
ReadBuffer(name, output, 2) == std::vector<u32>{expected, expected},
|
||||||
|
"an alias replacement retired image contents before queued GPU reads");
|
||||||
|
DestroyBuffer(&output);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto stencil_format = Prospero::BufferFormat::k8UInt;
|
constexpr auto stencil_format = Prospero::BufferFormat::k8UInt;
|
||||||
constexpr auto linear = Prospero::TileMode::kLinear;
|
constexpr auto linear = Prospero::TileMode::kLinear;
|
||||||
TileSizeAlign stencil_layout{};
|
TileSizeAlign stencil_layout{};
|
||||||
@@ -39529,6 +39613,11 @@ int main(int argc, char **argv) {
|
|||||||
CheckImageTransitionState(vulkan.RuntimeRenderer());
|
CheckImageTransitionState(vulkan.RuntimeRenderer());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--image-rebind-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
vulkan.CheckRenderExecutorStencilBindingDiscovery();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-death") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--reverse-rt-death") == 0) {
|
||||||
RunReverseRenderTargetDeathCase();
|
RunReverseRenderTargetDeathCase();
|
||||||
|
|||||||
Reference in New Issue
Block a user