Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ void SetImportWatch(const Context& context, ImportWatch watch);
// (alignment and budget permitting), or null. Bytes at `address` are at `address - import->base` in
// the import's buffer.
const HostImport* HostImportFor(const Context& context, std::uint64_t address, std::size_t bytes);
const HostImport* HostImportSpanning(const Context& context, std::uint64_t address, std::size_t bytes);
void SetHostImportWindow(std::uint64_t bytes);
// Tests: the window of one large registered range (64 MiB) and the import budget (0: the configured one).
void SetHostImportRangeWindow(std::uint64_t bytes);
Expand Down
14 changes: 14 additions & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2407,6 +2407,20 @@ const HostImport* HostImportFor(const Context& context, std::uint64_t address, s
return importAccess(context, state, address, address + bytes, lease);
}

const HostImport* HostImportSpanning(const Context& context, std::uint64_t address, std::size_t bytes) {
if (const auto* import = HostImportFor(context, address, bytes)) return import;
if (context.hostImportAlignment == 0 || bytes == 0 || bytes > std::numeric_limits<std::uint64_t>::max() - address) return nullptr;
auto& state = Imports();
std::lock_guard lock(state.mutex);
if (const auto* found = findImport(state, address, address + bytes)) return found;
const auto lease = GuestAllocations::GuestAllocationsAcquire_nid_postfix();
refreshImports(context, state, lease);
const auto run = crossedRun(lease, address, address + bytes);
if (run.ranges.empty()) return nullptr;
const auto* joined = importJoined(context, state, run.base, run.base + run.bytes, lease);
return joined != nullptr && findImport(state, address, address + bytes) == joined ? joined : nullptr;
}

bool ImportMappedRanges(const Context& context, const GuestAllocations::Mapped& ranges, std::uint64_t generation, bool adoptDevice) {
if (context.hostImportAlignment == 0) return true;
ensurePinWaiter();
Expand Down
12 changes: 6 additions & 6 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1741,7 +1741,7 @@ bool StorageTexture::Refresh() {
// stamped); an untracked unit is stored whole by that write-back, and a unit pending in both
// images takes the old order (store, then this image re-uploads it).
auto alias = pendingAlias();
if (alias != nullptr && !(ProvedClearKeys(descriptor, guestBytes, keyProof) == DccKeys::Uncompressed && HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) != nullptr)) alias = nullptr;
if (alias != nullptr && !(ProvedClearKeys(descriptor, guestBytes, keyProof) == DccKeys::Uncompressed && HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) != nullptr)) alias = nullptr;
if (alias != nullptr) {
std::vector<std::uint8_t> aliasStamped(trackedLayers);
if (!GuestMemory::ChangedBlocks(descriptor.baseAddress, static_cast<std::size_t>(guestBytes), alias->layerGeneration, aliasStamped)) alias = nullptr;
Expand Down Expand Up @@ -1856,7 +1856,7 @@ bool StorageTexture::Refresh() {
}
// Only the direct path uploads the selected layers alone (see upload); the others replace
// the whole image, so every pending layer's results are stored first.
direct = keys == DccKeys::Uncompressed && HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) != nullptr;
direct = keys == DccKeys::Uncompressed && HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) != nullptr;
if (alias != nullptr && direct) {
// The alias's pending units that nothing stamped since its generation (a CPU store or a
// driver store there wins over its results, as at its own write-back) are taken from
Expand Down Expand Up @@ -2183,7 +2183,7 @@ void StorageTexture::upload(const std::vector<bool>* layers) {
// The clear is recorded into the open batch like a direct upload (the image kept by it): a
// batch of its own submitted the recorder's work first and waited for all of it, 25-40 ms
// under the GPU mutex at the movie stage. APS5_NO_RECORDED_CLEAR=1 waits as before.
static_cast<void>(HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)));
static_cast<void>(HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)));
if (GuestMemory::Watched(descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) {
layerOriginal.assign(trackedLayers, false);
cancelStoredSaves();
Expand Down Expand Up @@ -2236,7 +2236,7 @@ void StorageTexture::upload(const std::vector<bool>* layers) {
if (profile) LookupOutcomes::Add(LookupOutcomes::UploadClear, start);
return;
}
if (const auto* import = uploadedKeys == DccKeys::Uncompressed ? HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) : nullptr) {
if (const auto* import = uploadedKeys == DccKeys::Uncompressed ? HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) : nullptr) {
if (GuestMemory::Watched(descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) {
layerOriginal.assign(trackedLayers, false);
cancelStoredSaves();
Expand Down Expand Up @@ -4211,7 +4211,7 @@ bool StorageTexture::CopyFrom(StorageTexture& source, const char*& refusal) {
refusal = "released";
return false;
}
if (HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) == nullptr) {
if (HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes)) == nullptr) {
refusal = "not imported";
return false;
}
Expand Down Expand Up @@ -4670,7 +4670,7 @@ void StorageTexture::writeBackLayers(const std::vector<bool>& layers) {
settle(true);
return;
}
if (const auto* import = HostImportFor(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) segments.push_back({import, descriptor.baseAddress, descriptor.baseAddress + guestBytes});
if (const auto* import = HostImportSpanning(context, descriptor.baseAddress, static_cast<std::size_t>(guestBytes))) segments.push_back({import, descriptor.baseAddress, descriptor.baseAddress + guestBytes});
else segments = importSegments();
if (!segments.empty()) {
Require(!unsavedOutsideWatch, "storing storage image results pending over memory outside the write watch without the guest bytes saved before them is not implemented");
Expand Down
27 changes: 27 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/BdaResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,32 @@ void importWindowTests(const Context& context) {
::operator delete(block, std::align_val_t{window});
}

void importSpanningTests(const Context& context) {
constexpr std::size_t piece = 65536;
constexpr std::size_t window = 2 * piece;
void* block = ::operator new(4 * piece, std::align_val_t{window});
auto* guest = static_cast<std::uint8_t*>(block);
const auto first = reinterpret_cast<std::uintptr_t>(block);
auto importing = context;
importing.hostImportAlignment = piece;
SetHostImportWindow(window);
const auto change = [&](std::uint8_t* range, bool add) {
auto* mutation = GuestAllocations::GuestAllocationsBegin_nid_postfix();
if (add) GuestAllocations::GuestAllocationsAdd_nid_postfix(mutation, range, piece, true, false, true);
else GuestAllocations::GuestAllocationsRemove_nid_postfix(mutation, range);
GuestAllocations::GuestAllocationsEnd_nid_postfix(mutation);
};
for (std::size_t index = 0; index < 4; ++index) change(guest + index * piece, true);
Require(HostImportFor(importing, first + window - 16, 32) == nullptr, "a view crossing the import window was imported");
const auto* spanning = HostImportSpanning(importing, first + window - 16, 32);
Require(spanning != nullptr && spanning->base <= first + window - 16 && spanning->base + spanning->bytes >= first + window + 16, "a surface crossing the import window was not imported through a joined import");
const auto* inside = HostImportSpanning(importing, first + window, piece);
Require(inside != nullptr && inside->base <= first + window && inside->base + inside->bytes >= first + window + piece, "a surface inside one window was not imported");
for (std::size_t index = 0; index < 4; ++index) change(guest + index * piece, false);
SetHostImportWindow(0);
::operator delete(block, std::align_val_t{window});
}

void importJoinTests(const Context& context) {
constexpr std::size_t piece = 65536;
constexpr std::size_t window = 2 * piece;
Expand Down Expand Up @@ -1783,6 +1809,7 @@ void RunBdaResourceTests(const Context& context, const BdaTestAccess& access) {
spaceWritableWritesTests(context);
spaceReadListTests(context);
importWindowTests(context);
importSpanningTests(context);
spaceReadAcrossImportsTests(context, access);
spaceReadAcrossImportsWrittenTests(context);
importJoinTests(context);
Expand Down
Loading