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
5 changes: 5 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,11 @@ if(BUILD_TESTING)
endif()
add_test(NAME agc_sparse_buffer_holes COMMAND agc_driver_graphics_tests --sparse-buffer-holes)
set_tests_properties(agc_driver_native_multisample_depth PROPERTIES TIMEOUT 30)
add_test(NAME agc_driver_native_depth_retirement COMMAND agc_driver_native_multisample_depth_tests --retirement)
set_tests_properties(agc_driver_native_depth_retirement PROPERTIES TIMEOUT 30 ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1" SKIP_RETURN_CODE 77 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
if(WIN32)
set_tests_properties(agc_driver_native_depth_retirement PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
set_tests_properties(agc_sparse_buffer_holes PROPERTIES TIMEOUT 30)
set_tests_properties(agc_driver_sparse_buffer_holes PROPERTIES TIMEOUT 30)
if(WIN32)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ std::uint64_t DepthSurfacesSerial();
std::uint64_t DepthSliceBytes(VkExtent2D extent, std::uint32_t bytesPerTexel);
std::uint64_t MultisampledDepthBytes_nid_no_patch(VkExtent2D extent, std::uint32_t bytesPerTexel, std::uint32_t samples);
void RequireNoResidentDepthRead_nid_no_patch(std::uint64_t address, std::size_t bytes);
bool HasResidentDepthGuards_nid_no_patch();
void RetireUnmappedDepth_nid_no_patch(std::uintptr_t address, std::size_t bytes);
void RequireNoNativeDepthFeedback_nid_no_patch(const Context& context, const DepthTarget& target, std::span<const std::shared_ptr<Texture>> sampled);
void ClearDepthSurfaces(VkDevice device);
void RetireDepthSurfaces(VkDevice device, std::uint64_t address, std::uint64_t bytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ bool MultisampledColorFillAbsorbs(std::uint64_t address, std::size_t bytes, std:
void NoteColorMetadataFill(std::uint64_t address, std::size_t bytes, std::uint32_t pattern);
void ClearMultisampleTargets(VkDevice device);
void InstallResidentImageReadGuard_nid_no_patch();
void UpdateResidentImageUnmapObserver_nid_no_patch();
void RequireNoMultisampleTarget(std::uint64_t address, std::size_t bytes, const char* access);

}
Expand Down
71 changes: 57 additions & 14 deletions core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include "prx/libc/include/GuestAllocations.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
#include "prx/libSceAgcDriver/Graphics/include/MultisampleTarget.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Resources.hpp"
Expand Down Expand Up @@ -46,6 +47,8 @@ struct DepthGuard {
VkDevice device;
std::uint64_t address;
std::size_t bytes;
std::shared_ptr<std::atomic<bool>> active;
std::vector<GuestMemory::UnchangedQuery> live;
};

std::shared_mutex& depthGuardMutex() {
Expand Down Expand Up @@ -196,6 +199,7 @@ class DepthSurface {

void CheckCurrent() const {
if (target.samples == 1u) return;
Require(active->load(std::memory_order_acquire), "the native multisample depth owner was released");
Require(sampling.refusal.empty(), sampling.refusal);
for (const auto& range : sampling.initial) {
Require(GuestMemory::Accessible(reinterpret_cast<const void*>(range.address), range.bytes) && GuestMemory::Watched(range.address, range.bytes), "native multisample depth requires watched accessible guest memory");
Expand Down Expand Up @@ -436,6 +440,7 @@ class DepthSurface {
VkImage image = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
std::shared_ptr<std::atomic<bool>> active = std::make_shared<std::atomic<bool>>(true);
bool sampleable = true;
bool samplingActive = false;
DepthSamplingState sampling;
Expand Down Expand Up @@ -822,7 +827,7 @@ PlaneOwners& stencilOwners() {
void takePlane(DepthSurface& surface, PlaneOwners& owners, std::uint64_t address, VkImageAspectFlagBits aspect) {
auto& entry = owners[{surface.context.device, address}];
auto* owner = entry.surface;
if (owner != nullptr && owner != &surface && owner->target.format == surface.target.format && owner->target.samples == surface.target.samples && owner->target.extent.width == surface.target.extent.width && owner->target.extent.height == surface.target.extent.height) {
if (owner != nullptr && owner->active->load(std::memory_order_acquire) && owner != &surface && owner->target.format == surface.target.format && owner->target.samples == surface.target.samples && owner->target.extent.width == surface.target.extent.width && owner->target.extent.height == surface.target.extent.height) {
if ((owner->pendingClear & aspect) != 0) surface.pendingClear |= aspect;
else surface.CopyAspectFrom(*owner, aspect);
}
Expand All @@ -837,23 +842,23 @@ void takePlanes(DepthSurface& surface) {
DepthSurface* depthSlice(VkDevice device, std::uint64_t address, const DepthTarget& base) {
if (const auto found = depthOwners().find({device, address}); found != depthOwners().end()) {
const auto& target = found->second.surface->target;
if (target.extent.width == base.extent.width && target.extent.height == base.extent.height && target.format == base.format) return found->second.surface;
if (found->second.surface->active->load(std::memory_order_acquire) && target.extent.width == base.extent.width && target.extent.height == base.extent.height && target.format == base.format) return found->second.surface;
}
const auto& list = surfaces();
const auto slice = std::find_if(list.rbegin(), list.rend(), [&](const auto& surface) { return surface->context.device == device && !surface->retired && surface->target.address == address && surface->target.extent.width == base.extent.width && surface->target.extent.height == base.extent.height && surface->target.format == base.format; });
const auto slice = std::find_if(list.rbegin(), list.rend(), [&](const auto& surface) { return surface->active->load(std::memory_order_acquire) && surface->context.device == device && !surface->retired && surface->target.address == address && surface->target.extent.width == base.extent.width && surface->target.extent.height == base.extent.height && surface->target.format == base.format; });
return slice == list.rend() ? nullptr : slice->get();
}

DepthSurface* planeSurface(VkDevice device, std::uint64_t address) {
const auto depth = depthOwners().find({device, address});
const auto stencil = stencilOwners().find({device, address});
const bool hasDepth = depth != depthOwners().end();
const bool hasStencil = stencil != stencilOwners().end();
const bool hasDepth = depth != depthOwners().end() && depth->second.surface->active->load(std::memory_order_acquire);
const bool hasStencil = stencil != stencilOwners().end() && stencil->second.surface->active->load(std::memory_order_acquire);
if (hasDepth && (!hasStencil || depth->second.serial > stencil->second.serial)) return depth->second.surface;
if (hasStencil) return stencil->second.surface;
const auto& list = surfaces();
const auto found = std::find_if(list.rbegin(), list.rend(), [&](const auto& surface) {
return surface->context.device == device && !surface->retired && (surface->target.address == address || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == address));
return surface->active->load(std::memory_order_acquire) && surface->context.device == device && !surface->retired && (surface->target.address == address || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == address));
});
return found == list.rend() ? nullptr : found->get();
}
Expand Down Expand Up @@ -917,6 +922,37 @@ void RequireNoResidentDepthRead_nid_no_patch(std::uint64_t address, std::size_t
for (const auto& range : depthGuards()) Require(address >= range.address + range.bytes || range.address >= address + bytes, "sample-preserving guest publication of native multisample depth is not implemented");
}

bool HasResidentDepthGuards_nid_no_patch() {
return anyDepthGuard().load(std::memory_order_acquire);
}

void RetireUnmappedDepth_nid_no_patch(std::uintptr_t address, std::size_t bytes) {
if (bytes == 0u || !HasResidentDepthGuards_nid_no_patch()) return;
Require(address <= std::numeric_limits<std::uint64_t>::max() - bytes, "native depth release range overflows");
const auto end = address + bytes;
std::unique_lock lock(depthGuardMutex());
for (auto& range : depthGuards()) {
std::vector<GuestMemory::UnchangedQuery> remaining;
remaining.reserve(range.live.size() + 1u);
for (const auto& part : range.live) {
const auto finish = part.address + part.bytes;
const auto first = std::max<std::uint64_t>(address, part.address);
const auto last = std::min<std::uint64_t>(end, finish);
if (first >= last) remaining.push_back(part);
else {
if (part.address < first) remaining.push_back({part.address, static_cast<std::size_t>(first - part.address), 0u});
if (last < finish) remaining.push_back({last, static_cast<std::size_t>(finish - last), 0u});
}
}
range.live = std::move(remaining);
}
for (const auto& range : depthGuards()) {
if (std::ranges::all_of(depthGuards(), [&](const auto& part) { return part.active != range.active || part.live.empty(); })) range.active->store(false, std::memory_order_release);
}
std::erase_if(depthGuards(), [](const auto& range) { return !range.active->load(std::memory_order_acquire); });
anyDepthGuard().store(!depthGuards().empty(), std::memory_order_release);
}

bool SampleLocationsCompatibleDepth(const Context& context, VkFormat format, std::uint32_t samples) {
if (samples <= 1 || (context.sampleLocationSampleCounts & samples) == 0) return false;
VkImageFormatProperties properties{};
Expand Down Expand Up @@ -959,15 +995,16 @@ VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target)
const bool cleared = takeClearedHtile(target);
DepthSurface* surface = nullptr;
for (const auto& candidate : surfaces()) {
if (candidate->context.device == context.device && sameSurface(candidate->target, target)) {
if (candidate->active->load(std::memory_order_acquire) && candidate->context.device == context.device && sameSurface(candidate->target, target)) {
surface = candidate.get();
break;
}
}
const bool created = surface == nullptr;
GuestAllocations::Lease creationLease;
if (created) {
for (const auto& surface : surfaces()) {
if (!surface->samplingActive || surface->context.device != context.device) continue;
if (!surface->active->load(std::memory_order_acquire) || !surface->samplingActive || surface->context.device != context.device) continue;
const auto bytes = target.samples == 1u ? DepthSliceBytes(target.extent, target.format == VK_FORMAT_D16_UNORM ? 2u : 4u) : MultisampledDepthBytes_nid_no_patch(target.extent, target.format == VK_FORMAT_D16_UNORM ? 2u : 4u, target.samples);
Require(target.address <= std::numeric_limits<std::uint64_t>::max() - bytes && target.htileAddress <= std::numeric_limits<std::uint64_t>::max() - HtileMetadataBytes(target.extent), "native depth attachment range overflows");
for (const auto& range : surface->sampling.initial) {
Expand All @@ -981,21 +1018,23 @@ VkImageView DepthSurfaceView(const Context& context, const DepthTarget& target)
}
lock.unlock();
auto sampling = target.samples == 1u ? DepthSamplingState{} : prepareDepthSampling(context, target);
creationLease = target.samples == 1u || !sampling.refusal.empty() ? GuestAllocations::Lease{} : GuestAllocations::GuestAllocationsAcquireAll_nid_postfix();
lock.lock();
surfacesSerial.fetch_add(1, std::memory_order_release);
surfaces().push_back(std::make_unique<DepthSurface>(context, target, std::move(sampling)));
auto& fresh = *surfaces().back();
if (target.samples != 1u && fresh.sampleable && fresh.sampling.refusal.empty()) {
std::unique_lock guardLock(depthGuardMutex());
for (const auto& range : fresh.sampling.initial) depthGuards().push_back({context.device, range.address, range.bytes});
for (const auto& range : fresh.sampling.initial) depthGuards().push_back({context.device, range.address, range.bytes, fresh.active, {{range.address, range.bytes, 0u}}});
anyDepthGuard().store(true, std::memory_order_release);
InstallResidentImageReadGuard_nid_no_patch();
fresh.samplingActive = true;
}
surface = surfaces().back().get();
}
surface->retired = false;
const bool inherits = depthOwners().contains({context.device, target.address});
const auto owner = depthOwners().find({context.device, target.address});
const bool inherits = owner != depthOwners().end() && owner->second.surface->active->load(std::memory_order_acquire) && !owner->second.surface->retired;
surface->clearDepth = target.clearDepth;
surface->clearStencil = target.clearStencil;
takePlanes(*surface);
Expand Down Expand Up @@ -1048,6 +1087,7 @@ void NoteHtileDepthClear(std::uint64_t htileAddress, std::size_t bytes) {
std::lock_guard lock(surfacesMutex());
bool existing = false;
for (const auto& surface : surfaces()) {
if (!surface->active->load(std::memory_order_acquire)) continue;
if (!HtileFillCovers(surface->target.htileAddress, surface->target.extent, htileAddress, bytes)) continue;
if (surface->target.samples != 1u) surface->sampling.refusal = "native multisample depth fast-clear transition is not implemented";
surface->pendingClear |= VK_IMAGE_ASPECT_DEPTH_BIT;
Expand All @@ -1069,11 +1109,12 @@ void ClearDepthSurfaces(VkDevice device) {
std::unique_lock guardLock(depthGuardMutex());
std::erase_if(depthGuards(), [&](const auto& range) { return range.device == device; });
anyDepthGuard().store(!depthGuards().empty(), std::memory_order_release);
UpdateResidentImageUnmapObserver_nid_no_patch();
}

std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components) {
const auto held = [&](const auto& surface) {
return surface->context.device == context.device && !surface->retired && (surface->target.address == resource.baseAddress || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == resource.baseAddress));
return surface->active->load(std::memory_order_acquire) && surface->context.device == context.device && !surface->retired && (surface->target.address == resource.baseAddress || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == resource.baseAddress));
};
{
std::lock_guard lock(surfacesMutex());
Expand Down Expand Up @@ -1155,6 +1196,7 @@ void RequireNoNativeDepthFeedback_nid_no_patch(const Context& context, const Dep
std::lock_guard gpu(GuestMemory::GpuMutex());
std::lock_guard lock(surfacesMutex());
for (const auto& surface : surfaces()) {
if (!surface->active->load(std::memory_order_acquire)) continue;
if (surface->context.device != context.device || !sameSurface(surface->target, target)) continue;
Require(std::none_of(sampled.begin(), sampled.end(), [&](const auto& texture) { return texture != nullptr && surface->Holds(texture.get()); }), "sampling a native multisampled depth target the draw attaches is not implemented");
}
Expand All @@ -1179,6 +1221,7 @@ bool HtileFillCovers(std::uint64_t htile, VkExtent2D extent, std::uint64_t addre
void NoteDepthMetadataFill(std::uint64_t address, std::size_t bytes, std::uint32_t pattern) {
std::lock_guard lock(surfacesMutex());
for (const auto& surface : surfaces()) {
if (!surface->active->load(std::memory_order_acquire)) continue;
const auto& target = surface->target;
if (target.samples != 1u && target.htileAddress != 0u && address < target.htileAddress + HtileMetadataBytes(target.extent) && target.htileAddress < address + bytes) surface->sampling.refusal = "native multisample depth metadata fill transition is not implemented";
if (!HtileFillCovers(target.htileAddress, target.extent, address, bytes)) continue;
Expand Down Expand Up @@ -1241,7 +1284,7 @@ std::shared_ptr<StorageTexture> DepthSurfaceStorage(const Context& context, std:
std::lock_guard lock(surfacesMutex());
const auto& list = surfaces();
const auto found = std::find_if(list.rbegin(), list.rend(), [&](const auto& surface) {
return surface->context.device == context.device && !surface->retired && (surface->target.address == resource.baseAddress || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == resource.baseAddress));
return surface->active->load(std::memory_order_acquire) && surface->context.device == context.device && !surface->retired && (surface->target.address == resource.baseAddress || (surface->target.stencilAddress != 0 && surface->target.stencilAddress == resource.baseAddress));
});
if (found == list.rend()) return nullptr;
auto& surface = **found;
Expand All @@ -1261,7 +1304,7 @@ bool DepthSurfaceStoreBack(const Context& context, const StorageTexture& storage
return true;
}
for (const auto& surface : surfaces()) {
if (surface->context.device == context.device && surface->StoreBack(storage)) return true;
if (surface->active->load(std::memory_order_acquire) && 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;
Expand All @@ -1271,7 +1314,7 @@ bool DepthSurfaceStoreBack(const Context& context, const StorageTexture& storage

bool DepthSurfaceAt(std::uint64_t address) {
std::lock_guard lock(surfacesMutex());
return std::any_of(surfaces().begin(), surfaces().end(), [&](const auto& surface) { return !surface->retired && (surface->target.address == address || surface->target.stencilAddress == address); });
return std::any_of(surfaces().begin(), surfaces().end(), [&](const auto& surface) { return surface->active->load(std::memory_order_acquire) && !surface->retired && (surface->target.address == address || surface->target.stencilAddress == address); });
}

void RetireDepthSurfaces(VkDevice device, std::uint64_t address, std::uint64_t bytes) {
Expand Down
Loading
Loading