Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,15 @@ class DepthSurface {
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;
}

bool StoreBack(const StorageTexture& candidate) {
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;
}
Expand All @@ -233,6 +233,18 @@ class DepthSurface {
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;
Expand All @@ -250,20 +262,30 @@ class DepthSurface {
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);
Expand Down Expand Up @@ -917,6 +939,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;
}

Expand Down
48 changes: 48 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

}
Expand All @@ -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";
Expand Down
Loading