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
11 changes: 9 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4839,7 +4839,8 @@ void StorageTexture::writeBackLayers(const std::vector<bool>& layers) {
overhang = covered >= end;
}
}
if (unregisteredDrop && !overhang && !RegisteredReadableCovers(descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) {
const bool registered = std::all_of(keep.begin(), keep.end(), [](const auto& range) { return RegisteredReadableCovers(range.first, static_cast<std::size_t>(range.second - range.first)); });
if (unregisteredDrop && !overhang && !registered) {
static std::atomic<int> reports{0};
if (reports.fetch_add(1) < 4) std::fprintf(stderr, "[gpu] storage image 0x%llx+0x%llx: memory no longer registered; %zu pending ranges dropped\n", static_cast<unsigned long long>(descriptor.baseAddress), static_cast<unsigned long long>(guestBytes), keep.size());
unregisteredDropped.fetch_add(1, std::memory_order_relaxed);
Expand All @@ -4857,7 +4858,13 @@ void StorageTexture::writeBackLayers(const std::vector<bool>& layers) {
Require(!unsavedOutsideWatch, "storing storage image results pending over memory outside the write watch without the guest bytes saved before them is not implemented");
std::vector<bool> unsaved = layerOriginal;
unsaved.flip();
for (const auto& [begin, end] : unitRuns(unsaved)) GuestMemory::ReadCommitted(descriptor.baseAddress + begin, std::span(original).subspan(static_cast<std::size_t>(begin), static_cast<std::size_t>(end - begin)));
for (const auto& [begin, end] : unitRuns(unsaved)) {
for (const auto& [from, to] : keep) {
const auto first = std::max(descriptor.baseAddress + begin, from);
const auto last = std::min(descriptor.baseAddress + end, to);
if (first < last) GuestMemory::ReadCommitted(first, std::span(original).subspan(static_cast<std::size_t>(first - descriptor.baseAddress), static_cast<std::size_t>(last - first)));
}
}
DeviceBuffer linear(context, static_cast<std::size_t>(sliceLinearBytes * arrayLayers), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
DeviceBuffer tiled(context, original.size(), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
Buffer host(context, original.size(), VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
Expand Down
54 changes: 51 additions & 3 deletions core/libs/prx/libSceAgcDriver/tests/execution/ArrayLayerTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ std::string Hex(std::uint32_t value) {

class GuestBlock {
public:
GuestBlock() {
explicit GuestBlock(std::size_t registeredBytes = SurfaceBytes, std::size_t registeredOffset = 0) : registeredOffset(registeredOffset) {
#ifdef _WIN32
block = static_cast<std::uint8_t*>(GuestArena::GuestArenaAllocate_nid_postfix(SurfaceBytes, LayerBytes));
if (block != nullptr) GuestArena::GuestArenaCommit_nid_postfix(block, SurfaceBytes, PAGE_READWRITE, SurfaceBytes);
Expand All @@ -97,11 +97,11 @@ class GuestBlock {
}
#endif
Require(block != nullptr, "array layer target: cannot allocate the guest block");
GuestAllocations::Mutation().Add(block, SurfaceBytes, true, true, true);
GuestAllocations::Mutation().Add(block + registeredOffset, registeredBytes, true, true, true);
}

~GuestBlock() {
GuestAllocations::Mutation().Remove(block);
if (registered) GuestAllocations::Mutation().Remove(block + registeredOffset);
#ifdef _WIN32
GuestArena::GuestArenaReset_nid_postfix(block, SurfaceBytes);
GuestArena::GuestArenaRelease_nid_postfix(block, SurfaceBytes);
Expand All @@ -115,9 +115,15 @@ class GuestBlock {
GuestBlock& operator=(const GuestBlock&) = delete;

std::uint8_t* Data() { return block; }
void Unregister() {
GuestAllocations::Mutation().Remove(block + registeredOffset);
registered = false;
}

private:
std::uint8_t* block = nullptr;
std::size_t registeredOffset = 0;
bool registered = true;
};

std::array<std::uint32_t, 8> SurfaceDescriptor(std::uint64_t address, std::uint32_t swizzleMode, std::uint32_t type, std::uint32_t lastLayer) {
Expand Down Expand Up @@ -309,6 +315,45 @@ void SampleSliceZero(AgcDriver::VulkanDevice& device, std::uint8_t* texels, std:
AgcDriver::Graphics::ClearCachedTextures(device.Device());
}

void UnregisteredUnusedLayer(AgcDriver::VulkanDevice& device, std::uint32_t slice) {
GuestBlock block(LayerBytes, slice * LayerBytes);
auto* texels = block.Data();
const auto surface = AddressOf(texels);
const auto active = surface + slice * LayerBytes;
std::fill_n(reinterpret_cast<std::uint32_t*>(texels), SurfaceBytes / 4u, Initial);
AgcDriver::GuestMemory::CollectWrites(surface, SurfaceBytes);
AgcDriver::GuestMemory::BumpCollectEpoch();
DrawSlice(device, surface, slice, TileR64KBX, false);
Require(StorageTexture::FindPending(surface, SurfaceBytes) != nullptr, "the registered slice was not pending before its CPU write-back");
StorageTexture::FlushPending(active, LayerBytes, nullptr, "test");
device.WaitIdle();
const auto* first = reinterpret_cast<std::uint32_t*>(active);
const auto* last = reinterpret_cast<std::uint32_t*>(active + LayerBytes);
const auto unchanged = [](std::uint32_t value) { return value == Initial; };
const auto drawn = std::count(first, last, std::bit_cast<std::uint32_t>(Drawn));
const bool untouched = std::all_of(reinterpret_cast<const std::uint32_t*>(texels), first, unchanged) && std::all_of(last, reinterpret_cast<const std::uint32_t*>(texels + SurfaceBytes), unchanged);
AgcDriver::Graphics::ClearCachedTextures(device.Device());
Require(drawn == ScissorWidth * Side, "CPU write-back discarded the registered slice because an unused array slice was unregistered");
Require(untouched, "CPU write-back modified an unregistered unused slice");
}

void RetiredArrayLayer(AgcDriver::VulkanDevice& device) {
GuestBlock block(LayerBytes);
auto* texels = block.Data();
const auto surface = AddressOf(texels);
std::fill_n(reinterpret_cast<std::uint32_t*>(texels), SurfaceBytes / 4u, Initial);
AgcDriver::GuestMemory::CollectWrites(surface, SurfaceBytes);
AgcDriver::GuestMemory::BumpCollectEpoch();
DrawSlice(device, surface, 0u, TileR64KBX, false);
Require(StorageTexture::FindPending(surface, SurfaceBytes) != nullptr, "the retired slice was not pending before it was unregistered");
block.Unregister();
StorageTexture::FlushPending(surface, LayerBytes, nullptr, "test");
device.WaitIdle();
const bool untouched = std::all_of(reinterpret_cast<const std::uint32_t*>(texels), reinterpret_cast<const std::uint32_t*>(texels + SurfaceBytes), [](std::uint32_t value) { return value == Initial; });
AgcDriver::Graphics::ClearCachedTextures(device.Device());
Require(untouched, "CPU write-back stored results over a retired allocation");
}

}

int main() {
Expand All @@ -319,6 +364,9 @@ int main() {
Run(*device, block.Data(), TileR64KBX);
Run(*device, block.Data(), static_cast<std::uint32_t>(AgcDriver::Graphics::ColorTileMode::D64KBX));
for (std::uint32_t slice = 1; slice < Layers; ++slice) Run(*device, block.Data(), TileR64KBX, true, slice);
UnregisteredUnusedLayer(*device, 0u);
UnregisteredUnusedLayer(*device, Layers - 1u);
RetiredArrayLayer(*device);
std::puts("array layer target tests passed");
return 0;
} catch (const std::exception& error) {
Expand Down
Loading