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
6 changes: 6 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2141,6 +2141,12 @@ if(BUILD_TESTING)
set_tests_properties(agc_driver_rcp_hardware_exact PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
add_test(NAME agc_driver_depth_plane_sampling_evicting COMMAND agc_driver_depth_plane_sampling_tests --evicting)
set_tests_properties(agc_driver_depth_plane_sampling_evicting PROPERTIES ENVIRONMENT "APS5_DEPTH_PLANE_COPY_MIB=1" SKIP_RETURN_CODE 77 TIMEOUT 120)
if(WIN32)
set_tests_properties(agc_driver_depth_plane_sampling_evicting PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
foreach(agcExecutionTestName IN LISTS ANYPS5_AGC_EXECUTION_TESTS)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/execution/${agcExecutionTestName}.cpp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ VkImageAspectFlags HtileFillClears(std::uint32_t pattern, bool stencilInHtile);
std::uint64_t HtileMetadataBytes(VkExtent2D extent);
bool HtileFillCovers(std::uint64_t htile, VkExtent2D extent, std::uint64_t address, std::size_t bytes);
std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components, VkImageViewType multisampleViewType = VK_IMAGE_VIEW_TYPE_2D);
std::size_t DepthPlaneCopyCount();
VkFormat HostDepthFormat(const Context& context, VkFormat format);
float HostDepthBiasConstant(const Context& context, VkFormat format, float constant);
std::shared_ptr<StorageTexture> DepthSurfaceStorage(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, std::uint32_t mip);
Expand Down
84 changes: 62 additions & 22 deletions core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1218,8 +1218,8 @@ class DepthPlaneCopy {
allocation.memoryTypeIndex = context.MemoryType(requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
memory = AllocateImageMemory(context, allocation, requirements.memoryTypeBits, "vkAllocateMemory depth plane copy");
Check(context.Function<PFN_vkBindImageMemory>("vkBindImageMemory")(context.device, image, memory, 0), "vkBindImageMemory depth plane copy");
stagingSize = static_cast<std::size_t>(sliceBytes()) * layers;
staging = std::make_unique<DeviceBuffer>(context, stagingSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
imageBytes = requirements.size;
owned = std::make_shared<OwnedImage>(context, image, memory);
} catch (...) {
release();
throw;
Expand All @@ -1238,12 +1238,7 @@ class DepthPlaneCopy {
std::snprintf(text, sizeof(text), "AGC graphics: depth plane copy geometry does not match its layers (copy %ux%u, %u layers, %llu bytes a slice; texture %ux%u guest format %u, dimension %d, tile mode %u, %u layers, %llu bytes a slice, %zu mips)", extent.width, extent.height, layers, static_cast<unsigned long long>(sliceBytes()), resource.width, resource.height, resource.format, static_cast<int>(resource.dimension), resource.tileMode, geometry.layers, static_cast<unsigned long long>(geometry.sliceLinearBytes), geometry.mips.size());
throw std::runtime_error(text);
}
const auto stagingBytes = static_cast<std::size_t>(geometry.sliceLinearBytes) * layers;
if (stagingBytes > stagingSize) {
retiredStaging.push_back(std::move(staging));
staging = std::make_unique<DeviceBuffer>(context, stagingBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
stagingSize = stagingBytes;
}
const auto stagingBytes = std::max<std::size_t>(static_cast<std::size_t>(geometry.sliceLinearBytes), static_cast<std::size_t>(sliceBytes())) * layers;
std::vector<std::shared_ptr<Buffer>> uploads;
std::vector<std::uint32_t> uploadLayers;
std::vector<std::uint32_t> copiedLayers;
Expand All @@ -1269,11 +1264,14 @@ class DepthPlaneCopy {
uploadLayers.push_back(layer);
held = current;
}
if (!copiedLayers.empty() || !uploads.empty()) record(slices, resource, geometry, copiedLayers, uploads, uploadLayers);
if (!copiedLayers.empty() || !uploads.empty()) {
if (staging == nullptr || stagingBytes > staging->Size()) staging = std::make_shared<DeviceBuffer>(context, stagingBytes, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
record(slices, resource, geometry, copiedLayers, uploads, uploadLayers, staging);
}
const std::array<std::uint32_t, 6> key{static_cast<std::uint32_t>(components.r), static_cast<std::uint32_t>(components.g), static_cast<std::uint32_t>(components.b), static_cast<std::uint32_t>(components.a), static_cast<std::uint32_t>(viewType), baseLayer};
auto& texture = textures[key];
if (texture == nullptr) {
texture = std::make_shared<Texture>(context, image, format, aspect(), components, viewType, baseLayer);
texture = std::make_shared<Texture>(context, image, format, aspect(), components, viewType, baseLayer, owned);
texture->MarkRefreshedPerUse();
}
return texture;
Expand All @@ -1283,6 +1281,9 @@ class DepthPlaneCopy {
const VkExtent2D extent;
const VkFormat format;
const std::uint32_t layers;
VkDeviceSize imageBytes = 0;
std::uint64_t lastUse = 0;
VkDeviceSize HeldBytes() const { return imageBytes + (staging != nullptr ? staging->Size() : 0u); }

private:
struct GuestLayer {
Expand All @@ -1295,15 +1296,14 @@ class DepthPlaneCopy {

VkImage image = VK_NULL_HANDLE;
VkDeviceMemory memory = VK_NULL_HANDLE;
std::unique_ptr<DeviceBuffer> staging;
std::size_t stagingSize = 0;
std::vector<std::unique_ptr<DeviceBuffer>> retiredStaging;
std::shared_ptr<OwnedImage> owned;
std::shared_ptr<DeviceBuffer> staging;
std::map<std::array<std::uint32_t, 6>, std::shared_ptr<Texture>> textures;
std::vector<GuestLayer> guestLayers;
std::vector<DepthPlaneSlice> surfaceLayers;
bool filled = false;

void record(std::span<const DepthPlaneSlice> slices, const GuestTextureResource& resource, const SurfaceGeometry& geometry, std::span<const std::uint32_t> copiedLayers, std::span<const std::shared_ptr<Buffer>> uploads, std::span<const std::uint32_t> uploadLayers) {
void record(std::span<const DepthPlaneSlice> slices, const GuestTextureResource& resource, const SurfaceGeometry& geometry, std::span<const std::uint32_t> copiedLayers, std::span<const std::shared_ptr<Buffer>> uploads, std::span<const std::uint32_t> uploadLayers, const std::shared_ptr<DeviceBuffer>& staging) {
if (!uploads.empty()) {
Require(context.detiler != nullptr, "depth plane copy requires a texture detiler");
context.detiler->BeginBatch();
Expand Down Expand Up @@ -1360,7 +1360,11 @@ class DepthPlaneCopy {
barrier(commands, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &toGeneral);
filled = true;
if (batch) batch->SubmitAndWait();
else Recorder::CountBarriers(Recorder::CommandClass::Draw, 3);
else {
Recorder::CountBarriers(Recorder::CommandClass::Draw, 3);
recorder->Keep(staging, staging->Size());
if (owned != nullptr) recorder->Keep(owned);
}
}

VkDeviceSize sliceBytes() const {
Expand All @@ -1374,8 +1378,11 @@ class DepthPlaneCopy {
void release() noexcept {
textures.clear();
staging.reset();
if (image) context.Function<PFN_vkDestroyImage>("vkDestroyImage")(context.device, image, nullptr);
if (memory) context.Function<PFN_vkFreeMemory>("vkFreeMemory")(context.device, memory, nullptr);
if (owned != nullptr) owned.reset();
else {
if (image) context.Function<PFN_vkDestroyImage>("vkDestroyImage")(context.device, image, nullptr);
if (memory) context.Function<PFN_vkFreeMemory>("vkFreeMemory")(context.device, memory, nullptr);
}
image = VK_NULL_HANDLE;
memory = VK_NULL_HANDLE;
}
Expand All @@ -1386,6 +1393,32 @@ std::map<std::tuple<VkDevice, std::uint64_t, std::uint32_t, std::uint32_t, VkFor
return *copies;
}

std::uint64_t& planeCopyClock() {
static std::uint64_t clock = 0;
return clock;
}

void evictPlaneCopies(const std::tuple<VkDevice, std::uint64_t, std::uint32_t, std::uint32_t, VkFormat, std::uint32_t>& keep) {
static const VkDeviceSize budget = [] {
const char* text = std::getenv("APS5_DEPTH_PLANE_COPY_MIB");
return static_cast<VkDeviceSize>(text != nullptr ? std::strtoull(text, nullptr, 10) : 256ull) << 20u;
}();
if (budget == 0) return;
auto& copies = planeCopies();
VkDeviceSize total = 0;
for (const auto& entry : copies) total += entry.second->HeldBytes();
while (total > budget) {
auto oldest = copies.end();
for (auto it = copies.begin(); it != copies.end(); ++it) {
if (it->first == keep) continue;
if (oldest == copies.end() || it->second->lastUse < oldest->second->lastUse) oldest = it;
}
if (oldest == copies.end()) break;
total -= oldest->second->HeldBytes();
copies.erase(oldest);
}
}

struct LayeredSlice {
DepthSurface* surface;
std::uint32_t layer;
Expand Down Expand Up @@ -2311,6 +2344,10 @@ void ClearDepthSurfaces(VkDevice device) {
UpdateResidentImageUnmapObserver_nid_no_patch();
}

std::size_t DepthPlaneCopyCount() {
return planeCopies().size();
}

std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<const std::uint32_t> words, const GuestTextureResource& resource, VkComponentMapping components, VkImageViewType multisampleViewType) {
const auto held = [&](const auto& surface) {
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));
Expand Down Expand Up @@ -2372,11 +2409,14 @@ std::shared_ptr<Texture> DepthSurfaceTexture(const Context& context, std::span<c
else slices.push_back({slice->image, slice == drawnDepth ? 0u : slice->written});
}
const auto imageFormat = integer ? VK_FORMAT_R16_UINT : d16 ? VK_FORMAT_D16_UNORM : VK_FORMAT_D32_SFLOAT;
auto& copy = planeCopies()[{context.device, base.address, base.extent.width, base.extent.height, imageFormat, layers}];
if (copy == nullptr) {
copy = std::make_unique<DepthPlaneCopy>(context, base.extent, imageFormat, layers);
}
return copy->Refresh(slices, resource, components, cube || resource.dimension == TextureDimension::k2DArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, layered && !cube ? resource.baseArray : 0u);
auto& copies = planeCopies();
const std::tuple<VkDevice, std::uint64_t, std::uint32_t, std::uint32_t, VkFormat, std::uint32_t> copyKey{context.device, base.address, base.extent.width, base.extent.height, imageFormat, layers};
auto& copy = copies[copyKey];
if (copy == nullptr) copy = std::make_unique<DepthPlaneCopy>(context, base.extent, imageFormat, layers);
copy->lastUse = ++planeCopyClock();
auto texture = copy->Refresh(slices, resource, components, cube || resource.dimension == TextureDimension::k2DArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D, layered && !cube ? resource.baseArray : 0u);
evictPlaneCopies(copyKey);
return texture;
}

bool DepthSurfaceHolds(const Context& context, const GuestTextureResource& resource, const Texture* texture) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,8 +434,9 @@ void RefusalCase(AgcDriver::VulkanDevice& device, GuestBlock& block) {
}
}

int main() {
int main(int argc, char** argv) {
try {
const bool evicting = argc > 1 && std::string(argv[1]) == "--evicting";
GuestBlock block;
const auto device = OpenVulkanTestDevice();
if (!device) return VulkanTestSkipped;
Expand All @@ -452,6 +453,10 @@ int main() {
PaddedD16CubeCase(*device, block, output);
BaseSliceCase(*device, block, output);
RefusalCase(*device, block);
if (evicting) {
const auto kept = AgcDriver::Graphics::DepthPlaneCopyCount();
Require(kept >= 1 && kept < 8, std::to_string(kept) + " depth plane copies were kept with a 1 MiB budget, expected at least the newest and fewer than the 8 an unbounded cache keeps");
}
std::puts("depth plane sampling tests passed");
return 0;
} catch (const std::exception& error) {
Expand Down
1 change: 1 addition & 0 deletions docs/dev/ENVIRONMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ The code reads environment names through `getenv`, `IsEnvironmentSet`, `kibSetti
| `APS5_CPU_STORES` | presence | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp` | | writes packet stores on the CPU instead of recording them on the GPU |
| `APS5_DCC_KEYS_EACH` | presence | `core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp` | | records every DCC key store at once instead of batching them |
| `APS5_DEPTH_COPY_MIN_KIB` | integer | `core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp` | 1024 | minimum surface size in KiB for a depth target to take the depth-copy path |
| `APS5_DEPTH_PLANE_COPY_MIB` | integer | `core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp` | 256 | budget in MiB of the sampled depth-plane copies kept for reuse (least recently used copies leave first); `0` keeps every copy |
| `APS5_DEPTH_PLANE_WHOLE_STORE` | presence | `core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp` | | stores a stale depth plane whole when memory over it is read, instead of only the 64 KiB units the read overlaps |
| `APS5_DISPATCH_CACHE_BYTES` | integer | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchCache.cpp` | 268435456 | size of the dispatch cache in bytes (0 keeps the default of 256 MiB) |
| `APS5_DISPATCH_CACHE_ENTRIES` | integer | `core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchCache.cpp` | 8192 | number of dispatch cache entries; 0 picks a default from the variant count |
Expand Down
Loading