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 @@ -121,6 +121,7 @@ void GuardOneFragmentFmask(const Context& context, const ColorTarget& target);
bool HoldsMultisampleTargetsLock();
void RequireNoMultisampleTarget(std::uint64_t address, std::size_t bytes, const char* access);
void RequireNoMultisampleColorTarget(std::uint64_t address, std::size_t bytes, const char* access);
void RetireMultisampleColorTarget(const std::shared_ptr<std::atomic<bool>>& active);
std::vector<std::pair<std::uint64_t, std::uint64_t>> HostOnlySampleRanges(std::uint64_t address, std::size_t bytes);

}
Expand Down
29 changes: 25 additions & 4 deletions core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ struct DepthSamplingState {
std::optional<std::uint8_t> aliasStencil;
std::optional<MultisampleColorAlias> unprovenStencil;
std::optional<MultisampleColorAlias> depthAlias;
std::optional<MultisampleColorAlias> stencilAlias;

void Refuse(const char* reason) {
if (refusal.empty()) refusal = reason;
Expand All @@ -243,11 +244,22 @@ std::optional<MultisampleColorAlias> soleDepthAlias(const GuestMemory::Unchanged
return aliases.front();
}

bool sameAliasValue(const MultisampleColorAlias& recorded, const MultisampleColorAlias& current) {
return recorded.value.has_value() == current.value.has_value() && (!recorded.value || std::memcmp(&*recorded.value, &*current.value, sizeof(VkClearColorValue)) == 0);
}

bool unchangedAlias(const MultisampleColorAlias& recorded, const GuestMemory::UnchangedQuery& plane) {
const auto aliases = MultisampleColorTargetsOver(plane.address, plane.bytes);
if (aliases.size() != 1u) return false;
const auto& current = aliases.front();
return current.active == recorded.active && current.contents == recorded.contents && current.newest == recorded.newest && current.fills == recorded.fills && sameAliasValue(recorded, current);
}

bool sameDepthAlias(const MultisampleColorAlias& recorded, const GuestMemory::UnchangedQuery& plane) {
const auto aliases = MultisampleColorTargetsOver(plane.address, plane.bytes);
if (aliases.size() != 1u) return false;
const auto& current = aliases.front();
const auto sameValue = recorded.value.has_value() == current.value.has_value() && (!recorded.value || std::memcmp(&*recorded.value, &*current.value, sizeof(VkClearColorValue)) == 0);
const auto sameValue = sameAliasValue(recorded, current);
const bool refilled = recorded.newest == MultisampleColorContent::Clear && current.newest == MultisampleColorContent::Fill && current.fills > recorded.fills && current.fills - recorded.fills == current.sameRun && current.filledBytes >= current.bytes;
return current.active == recorded.active && current.contents == recorded.contents && (current.newest == recorded.newest || refilled) && (current.fills == recorded.fills || refilled) && sameValue;
}
Expand Down Expand Up @@ -407,6 +419,7 @@ DepthSamplingState prepareDepthSampling(const Context& context, const DepthTarge
return refuse(index == 2u ? stencilAliasRefusal : depthAliasRefusal);
}
state.aliasStencil = value;
state.stencilAlias = *alias;
}
const auto& htile = state.initial[1];
for (auto& range : state.initial) {
Expand Down Expand Up @@ -674,6 +687,7 @@ class DepthSurface {
const bool stencilRange = index == 2u || (index == 1u && uniformPlaneTarget(target));
if (!kept) reportAlias(*alias, range, stencilRange ? "stencil plane" : index == 1u ? "HTILE" : "depth");
Require(kept, stencilRange ? stencilAliasRefusal : depthAliasRefusal);
if (index == 2u && stencilClearGeneration != 0u) sampling.stencilAlias = *alias;
planeAliased = true;
}
if (stencilClearGeneration != 0u) {
Expand Down Expand Up @@ -2388,10 +2402,14 @@ void DepthSurface::PublishToGuest() {
live[index] = found->live;
}
}
for (const auto& parts : live) {
for (const auto& part : parts) {
const auto supersedes = [&] {
return std::array{sampling.depthAlias && unchangedAlias(*sampling.depthAlias, sampling.initial[0]), false, sampling.stencilAlias && unchangedAlias(*sampling.stencilAlias, sampling.initial[2])};
};
const auto superseded = supersedes();
for (std::size_t index = 0u; index < live.size(); ++index) {
for (const auto& part : live[index]) {
Require(GuestMemory::Accessible(reinterpret_cast<const void*>(part.address), part.bytes, true) && GuestMemory::Watched(part.address, part.bytes), "native multisample depth publication requires watched accessible guest memory");
Require(!MultisampleColorTargetOver(part.address, part.bytes), "native multisample depth publication over a resident colour target is not implemented");
Require(superseded[index] || !MultisampleColorTargetOver(part.address, part.bytes), "native multisample depth publication over a resident colour target is not implemented");
const std::pair<std::uint64_t, std::uint64_t> range{part.address, part.address + part.bytes};
Require(!StorageTexture::AnyPendingOverlaps(std::span(&range, 1u)), "native multisample depth publication over pending storage image writes is not implemented");
}
Expand Down Expand Up @@ -2480,6 +2498,7 @@ void DepthSurface::PublishToGuest() {
for (const auto& range : observed) Require(GuestMemory::UnchangedSinceCollected(range.address, range.bytes, range.generation), "guest writes raced native multisample depth publication");
Require(GuestMemory::UnchangedSinceAll(observed), "guest writes raced native multisample depth publication");
Require(active->load(std::memory_order_acquire) && !clearPending && clearGeneration == 0u && stencilClearGeneration == 0u && pendingClear == 0u, "native multisample depth ownership changed during publication");
Require(supersedes() == superseded, "native multisample depth publication over a resident colour target is not implemented");
publicationFailed = true;
if (const auto hook = depthPublicationHook.load(std::memory_order_acquire)) hook(DepthPublicationStage::BeforeCommit);
auto seen = observed.begin();
Expand All @@ -2503,6 +2522,8 @@ void DepthSurface::PublishToGuest() {
}
hostWritten->store(false, std::memory_order_release);
publication.clear();
if (superseded[0]) RetireMultisampleColorTarget(sampling.depthAlias->active);
if (superseded[2]) RetireMultisampleColorTarget(sampling.stencilAlias->active);
}

void publishWrittenDepth(std::span<const std::shared_ptr<std::atomic<bool>>> written) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1785,6 +1785,13 @@ void RequireNoMultisampleColorTarget(std::uint64_t address, std::size_t bytes, c
anyGuarded().store(!guarded().empty(), std::memory_order_release);
}

void RetireMultisampleColorTarget(const std::shared_ptr<std::atomic<bool>>& active) {
std::unique_lock lock(guardedMutex());
active->store(false, std::memory_order_release);
if (std::erase_if(guarded(), [&](const auto& range) { return range.active == active; }) != 0u) guardedGeneration().fetch_add(1, std::memory_order_release);
anyGuarded().store(!guarded().empty(), std::memory_order_release);
}

std::vector<std::pair<std::uint64_t, std::uint64_t>> HostOnlySampleRanges(std::uint64_t address, std::size_t bytes) {
std::vector<std::pair<std::uint64_t, std::uint64_t>> ranges;
AppendHostWrittenDepthRanges(address, bytes, ranges);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,7 @@ std::array<std::uint32_t, 8> DepthSampleWords(const DepthTarget& target) {
return {static_cast<std::uint32_t>(base), static_cast<std::uint32_t>((base >> 32u) & 255u) | (format << 20u) | ((width & 3u) << 30u), (width >> 2u) | (height << 14u), (14u << 28u) | (24u << 20u) | (count << 16u) | 0x204u, 0u, count << 4u, (target.iterate256 ? 1u << 10u : 0u) | (target.htilePipeAligned ? 1u << 19u : 0u) | (1u << 21u) | (static_cast<std::uint32_t>(metadata & 255u) << 24u), static_cast<std::uint32_t>(metadata >> 8u)};
}

enum class PublicationWrite { None, Pages, Queued, PaddingSameValue, Completion, Concurrent, CopyRace, LateStore, PlaneStore, TargetsHeld, Retired, ColorAcquisition, DrawAlias, DrawPending, Reuse, DccAcquisition, DriverSameDepth, DriverSameStencil, DriverSameHtile, SameDepth, SameStencil, SameHtile, ChangedHull, Possible, ImportSameValue };
enum class PublicationWrite { None, Pages, Queued, PaddingSameValue, Completion, Concurrent, CopyRace, LateStore, PlaneStore, TargetsHeld, Retired, ColorAcquisition, DrawAlias, DrawPending, AliasImported, AliasDrawnAfterImport, StencilAliasImported, StencilAliasRefilled, StencilAliasDrawnAfterImport, Reuse, DccAcquisition, DriverSameDepth, DriverSameStencil, DriverSameHtile, SameDepth, SameStencil, SameHtile, ChangedHull, Possible, ImportSameValue };
void CheckGuardedWrite() {
TargetMemory memory(65536u, true);
for (const std::size_t head : {0u, 1u, 3u, 8u}) {
Expand Down Expand Up @@ -963,7 +963,32 @@ void CheckDepthPublication(Context context, std::uint32_t samples, PublicationWr
Context context;
~Cleanup() { recorder.Sync(); ClearCachedTextures(context.device); ClearDepthSurfaces(context.device); ClearMultisampleTargets(context.device); }
} cleanup{recorder, context};
const bool stencilAlias = write == PublicationWrite::StencilAliasImported || write == PublicationWrite::StencilAliasRefilled || write == PublicationWrite::StencilAliasDrawnAfterImport;
const bool importedAlias = stencilAlias || write == PublicationWrite::AliasImported || write == PublicationWrite::AliasDrawnAfterImport;
const bool aliasDrawn = write == PublicationWrite::AliasDrawnAfterImport || write == PublicationWrite::StencilAliasDrawnAfterImport;
ColorTarget alias{};
alias.address = alias.surfaceAddress = stencilAlias ? target.stencilAddress : target.address;
alias.extent = alias.surfaceExtent = extent;
alias.format = stencilAlias ? VK_FORMAT_R8_UNORM : VK_FORMAT_R32_SFLOAT;
alias.elementBytes = stencilAlias ? 1u : 4u;
alias.tileMode = ColorTileMode::RenderTarget;
alias.samples = samples;
alias.bytes = extent.width * extent.height * alias.elementBytes;
const auto aliasBytes = stencilAlias ? stencilBytes : depthBytes;
const auto fillStencilAlias = [&] {
Require(MultisampledColorFillAbsorbs(alias.address, stencilBytes, 0x5a5a5a5au), "the R8 colour target over the stencil plane did not absorb its fill");
NoteDepthMetadataFill(alias.address, stencilBytes, 0x5a5a5a5au);
NoteColorMetadataFill(alias.address, stencilBytes, 0x5a5a5a5au);
};
if (importedAlias) MultisampleTargetView(context, alias);
if (stencilAlias) fillStencilAlias();
const auto view = DepthSurfaceView(context, target);
if (importedAlias) Require(MultisampleColorTargetOver(alias.address, aliasBytes).has_value(), "the colour target over the depth or stencil plane was retired by the depth import");
if (write == PublicationWrite::StencilAliasRefilled) {
fillStencilAlias();
Require(DepthSurfaceView(context, target) == view, "a stencil plane fill through its colour alias replaced the native attachment");
}
if (aliasDrawn) MultisampleTargetView(context, alias);
if (write == PublicationWrite::DrawAlias) {
ColorTarget color{};
color.address = color.surfaceAddress = target.address;
Expand Down Expand Up @@ -1336,6 +1361,12 @@ void CheckDepthPublication(Context context, std::uint32_t samples, PublicationWr
Require(value == 0.25f + static_cast<float>(index % samples + 1u) / 16.0f, "an unavailable publication capture prevented a depth sample from rendering");
}
}
} else if (aliasDrawn) {
recorder.Sync();
const auto held = guestBytes();
std::array<std::byte, 1> probe;
TargetRefuses([&] { AgcDriver::GuestMemory::Read(target.address, probe); }, "aliases a multisampled colour target whose samples are only on the host");
Require(held == guestBytes() && MultisampleColorTargetOver(alias.address, aliasBytes).has_value() && DepthSurfaceAt(target.address), "a refused publication over a colour target drawn after the depth import changed guest bytes or retired a target");
} else if (write >= PublicationWrite::SameDepth) {
std::vector<std::pair<std::size_t, std::size_t>> stored;
if (write == PublicationWrite::SameDepth || write == PublicationWrite::ImportSameValue) stored.emplace_back(0u, sampleOffset);
Expand Down Expand Up @@ -1374,6 +1405,7 @@ void CheckDepthPublication(Context context, std::uint32_t samples, PublicationWr
for (const auto& failure : failures) if (failure) std::rethrow_exception(failure);
} else AgcDriver::GuestMemory::Read(addresses[trigger] + (first == 0u ? last : 0u), probe);
Require(DepthSurfaceAt(target.address), "a published native D32S8 owner was retired");
if (importedAlias) Require(!MultisampleColorTargetOver(alias.address, aliasBytes).has_value(), "a publication over a colour target the depth surface had taken in kept that colour target resident");
if (write == PublicationWrite::Pages || write == PublicationWrite::Queued || (write >= PublicationWrite::DriverSameDepth && write <= PublicationWrite::DriverSameHtile)) TargetRefuses([&] { DepthSurfaceView(context, target); }, "guest writes over native multisample depth are not implemented");
else if (unmap == PublicationUnmap::None) Require(DepthSurfaceView(context, target) == view, "a published native D32S8 owner was not reused");
protectedHoles.Restore();
Expand Down Expand Up @@ -3395,6 +3427,10 @@ int main(int argc, char** argv) {
CheckDepthPublication(publishing, 4u, PublicationWrite::Completion, true);
for (const auto write : {PublicationWrite::SameDepth, PublicationWrite::SameStencil, PublicationWrite::SameHtile, PublicationWrite::ChangedHull, PublicationWrite::Possible, PublicationWrite::ImportSameValue}) CheckDepthPublication(publishing, 4u, write, true);
CheckDepthPublication(publishing, 4u, PublicationWrite::DccAcquisition, true);
for (const auto samples : {2u, 4u, 8u}) {
if (!supported(samples) || (context.limits.framebufferColorSampleCounts & samples) == 0u) continue;
for (const auto write : {PublicationWrite::AliasImported, PublicationWrite::AliasDrawnAfterImport, PublicationWrite::StencilAliasImported, PublicationWrite::StencilAliasRefilled, PublicationWrite::StencilAliasDrawnAfterImport}) CheckDepthPublication(publishing, samples, write, true);
}
return 0;
}
CheckDrawFeedback();
Expand Down
Loading
Loading