mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-07 13:39:55 +00:00
Merge pull request #5113 from XairRrR/fix/agc-depth-store-back-any-storage
fix(agc): store a written storage image over a depth plane into the surface
This commit is contained in:
2 files changed
+79
-6
No files matched your search
@@ -213,7 +213,7 @@ public:
|
||||
if (plane.storage != nullptr) plane.replaced.push_back(plane.storage);
|
||||
plane.storage = StorageTexture::Create(context, *context.detiler, resource, 0);
|
||||
}
|
||||
copyPlane(plane, stencil, true);
|
||||
copyPlane(plane, plane.storage, stencil, true);
|
||||
return plane.storage;
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
for (const bool stencil : {false, true}) {
|
||||
auto& plane = stencil ? stencilPlane : depthPlane;
|
||||
if (plane.storage.get() == &candidate) {
|
||||
copyPlane(plane, stencil, false);
|
||||
copyPlane(plane, plane.storage, stencil, false);
|
||||
written = ++depthWrites;
|
||||
return true;
|
||||
}
|
||||
@@ -233,6 +233,18 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StoreBackCovering(const StorageTexture& candidate) {
|
||||
for (const bool stencil : {false, true}) {
|
||||
if (!CoversPlane(candidate, stencil)) continue;
|
||||
auto& plane = stencil ? stencilPlane : depthPlane;
|
||||
const auto source = std::const_pointer_cast<StorageTexture>(candidate.shared_from_this());
|
||||
copyPlane(plane, source, stencil, false);
|
||||
written = ++depthWrites;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Context context;
|
||||
const DepthTarget target;
|
||||
const VkFormat hostFormat;
|
||||
@@ -250,20 +262,30 @@ private:
|
||||
PlaneStorage depthPlane;
|
||||
PlaneStorage stencilPlane;
|
||||
|
||||
void copyPlane(PlaneStorage& plane, bool stencil, bool toStorage) {
|
||||
bool CoversPlane(const StorageTexture& storage, bool stencil) const {
|
||||
const auto& resource = storage.Descriptor();
|
||||
const auto address = stencil ? target.stencilAddress : target.address;
|
||||
if (address == 0 || resource.baseAddress != address || resource.width != target.extent.width || resource.height != target.extent.height || resource.baseLevel != 0 || resource.mipCount != 1) return false;
|
||||
if (resource.dimension != TextureDimension::k2D && (resource.dimension != TextureDimension::k2DArray || resource.baseArray != 0 || resource.depthOrLastArray != 0)) return false;
|
||||
if (target.samples != 1 || (!stencil && hostFormat != target.format)) return false;
|
||||
const bool d16 = target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT;
|
||||
return ResolveTextureFormat(resource.format) == (stencil ? VK_FORMAT_R8_UINT : d16 ? VK_FORMAT_R16_UNORM : VK_FORMAT_R32_SFLOAT);
|
||||
}
|
||||
|
||||
void copyPlane(PlaneStorage& plane, const std::shared_ptr<StorageTexture>& storage, bool stencil, bool toStorage) {
|
||||
auto* recorder = Recorder::Active();
|
||||
Require(recorder != nullptr, "depth surface storage copies need an active recorder");
|
||||
const bool d16 = target.format == VK_FORMAT_D16_UNORM || target.format == VK_FORMAT_D16_UNORM_S8_UINT;
|
||||
const auto bytes = static_cast<std::size_t>(target.extent.width) * target.extent.height * (stencil ? 1u : d16 ? 2u : 4u);
|
||||
if (plane.staging == nullptr) plane.staging = std::make_unique<DeviceBuffer>(context, bytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
|
||||
const auto commands = recorder->Commands();
|
||||
recorder->Keep(plane.storage);
|
||||
recorder->Keep(storage);
|
||||
const auto timing = recorder->BeginGpuTiming(Recorder::CommandClass::Copy);
|
||||
VkBufferImageCopy planeRegion{0, 0, 0, {stencil ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0, 1}, {0, 0, 0}, {target.extent.width, target.extent.height, 1}};
|
||||
VkBufferImageCopy colorRegion = planeRegion;
|
||||
colorRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
const auto sourceImage = toStorage ? image : plane.storage->Image();
|
||||
const auto destinationImage = toStorage ? plane.storage->Image() : image;
|
||||
const auto sourceImage = toStorage ? image : storage->Image();
|
||||
const auto destinationImage = toStorage ? storage->Image() : image;
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
context.Function<PFN_vkCmdCopyImageToBuffer>("vkCmdCopyImageToBuffer")(commands, sourceImage, VK_IMAGE_LAYOUT_GENERAL, plane.staging->Handle(), 1, toStorage ? &planeRegion : &colorRegion);
|
||||
RecordMemoryBarrier(context, commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT);
|
||||
@@ -941,6 +963,9 @@ bool DepthSurfaceStoreBack(const Context& context, const StorageTexture& storage
|
||||
for (const auto& surface : surfaces()) {
|
||||
if (surface->context.device == context.device && surface->StoreBack(storage)) return true;
|
||||
}
|
||||
for (auto surface = surfaces().rbegin(); surface != surfaces().rend(); ++surface) {
|
||||
if ((*surface)->context.device == context.device && (*surface)->StoreBackCovering(storage)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +246,52 @@ void Run(Context context, std::uint8_t* block) {
|
||||
ExpectFailure([&] { static_cast<void>(DepthSurfaceStorage(context, {}, layeredDepth, 0)); }, "with a layer pitch of", "a two-layer 2D array view of the depth plane with a layer pitch other than the depth slice size was accepted");
|
||||
layeredDepth.baseArray = 1;
|
||||
ExpectFailure([&] { static_cast<void>(DepthSurfaceStorage(context, {}, layeredDepth, 0)); }, "with a layer pitch of", "a 2D array view of layer 1 of the depth plane with a layer pitch other than the depth slice size was accepted");
|
||||
const auto own = StorageTexture::Create(context, *context.detiler, PlaneResource(address, Format32Float), 0);
|
||||
const std::array<std::uint32_t, 4> eighth{std::bit_cast<std::uint32_t>(0.125f), std::bit_cast<std::uint32_t>(0.125f), std::bit_cast<std::uint32_t>(0.125f), std::bit_cast<std::uint32_t>(0.125f)};
|
||||
Require(own->FillClear(eighth, StorageTexture::WholeImage, refusal), refusal != nullptr ? refusal : "the storage image could not be filled");
|
||||
Require(DepthSurfaceStoreBack(context, *own), "a storage image over the depth plane that the depth surface did not hand out was not stored back");
|
||||
submit(recorder);
|
||||
const auto reread = DepthSurfaceStorage(context, {}, PlaneResource(address, Format32Float), 0);
|
||||
Require(reread != nullptr, "the depth plane has no storage image");
|
||||
submit(recorder);
|
||||
readBack(*reread);
|
||||
Require(CountFloats(block, 0.125f) == Side * Side, "a storage image written over the depth plane did not reach the depth surface");
|
||||
Require(!DepthSurfaceStoreBack(context, *StorageTexture::Create(context, *context.detiler, PlaneResource(address, Format32Float, Side / 2), 0)), "a storage image of another extent over the depth memory was stored into the depth surface");
|
||||
}
|
||||
|
||||
void RunPairings(Context context, std::uint8_t* block) {
|
||||
const auto address = reinterpret_cast<std::uint64_t>(block);
|
||||
const auto submit = [&](Recorder& recorder) {
|
||||
recorder.Submit();
|
||||
Check(context.Function<PFN_vkQueueWaitIdle>("vkQueueWaitIdle")(context.queue), "vkQueueWaitIdle");
|
||||
};
|
||||
Recorder recorder(context);
|
||||
recorder.Activate();
|
||||
const auto readBack = [&](StorageTexture& texture) {
|
||||
texture.MarkDirty();
|
||||
texture.WriteBack();
|
||||
submit(recorder);
|
||||
};
|
||||
const DepthTarget first{address, address + BlockBytes / 2, {Side, Side}, VK_FORMAT_D32_SFLOAT_S8_UINT, 0.25f, 7};
|
||||
const DepthTarget second{address, address + BlockBytes / 2 + 8192, {Side, Side}, VK_FORMAT_D32_SFLOAT_S8_UINT, 0.5f, 3};
|
||||
Require(DepthSurfaceView(context, first) != VK_NULL_HANDLE && DepthSurfaceView(context, second) != VK_NULL_HANDLE, "the two pairings of the depth plane were not created");
|
||||
const auto depth = DepthSurfaceStorage(context, {}, PlaneResource(address, Format32Float), 0);
|
||||
Require(depth != nullptr, "the depth plane has no storage image");
|
||||
submit(recorder);
|
||||
const std::array<std::uint32_t, 4> pattern{std::bit_cast<std::uint32_t>(0.75f), std::bit_cast<std::uint32_t>(0.75f), std::bit_cast<std::uint32_t>(0.75f), std::bit_cast<std::uint32_t>(0.75f)};
|
||||
const char* refusal = nullptr;
|
||||
Require(depth->FillClear(pattern, StorageTexture::WholeImage, refusal), refusal != nullptr ? refusal : "the storage image could not be filled");
|
||||
Require(DepthSurfaceStoreBack(context, *depth), "the newest pairing's storage image was not stored back");
|
||||
submit(recorder);
|
||||
const auto reread = DepthSurfaceStorage(context, {}, PlaneResource(address, Format32Float), 0);
|
||||
Require(reread != nullptr, "the depth plane has no storage image");
|
||||
submit(recorder);
|
||||
readBack(*reread);
|
||||
Require(CountFloats(block, 0.75f) == Side * Side, "a storage image stored back went into an older pairing instead of the pairing that handed it out");
|
||||
auto layered = PlaneResource(address, Format32Float);
|
||||
layered.dimension = TextureDimension::k2DArray;
|
||||
Require(DepthSurfaceStorage(context, {}, layered, 0) != nullptr, "a one-layer 2D array view of the depth plane was not taken");
|
||||
ExpectFailure([&] { static_cast<void>(DepthSurfaceStoreBack(context, *depth)); }, "through a view that another view of the plane", "a store back through a replaced view was taken by an older pairing that covers the plane");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -269,6 +315,8 @@ int main() {
|
||||
std::lock_guard gpu(AgcDriver::GuestMemory::GpuMutex());
|
||||
Run(context, block);
|
||||
ClearDepthSurfaces(context.device);
|
||||
RunPairings(context, block);
|
||||
ClearDepthSurfaces(context.device);
|
||||
}
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
std::cout << "depth surface storage access tests passed\n";
|
||||
|
||||
Reference in new issue
Block a user