Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
aa154d5
fix(libSceCdlgG2P): transition to finished on dialog close
ErenYeager1836 Oct 18, 2026
1bb663f
fix(libSceVrSetupDialog): finish dialog on close
Oct 18, 2026
4aa81fb
test(agc): print the staged clear's expected byte count as a size_t
milescoviello Oct 18, 2026
8bcf040
fix(relinker): allow Windows export aliases when probing backup copies
tkcm01 Oct 18, 2026
3f33dcf
fix(libSceNgs2): clear the voice callback on sampler and mixer setup
mrfelek Oct 17, 2026
a45b08a
feat: require matching recorded context in performance comparisons
MrMha Oct 18, 2026
5e0deae
docs(libSceNgs2): note that a setup inside the voice callback clears it
mrfelek Oct 18, 2026
499e2db
fix(shader): link a table call whose descriptor load sits before its …
thuanquang Oct 18, 2026
cc69016
fix(shader): follow long branches in the hoisted descriptor search
thuanquang Oct 18, 2026
b7e0189
feat(recompiler): support waterfall select conditions and key bounds …
pushkarreddyy Oct 18, 2026
bfd5b6e
fix(recompiler): constrain ActiveMaskImplies template and make bounde…
pushkarreddyy Oct 18, 2026
ef897dc
fix(libScePngDec): reject a maximum image width above 1000000
KernelPanicNT Oct 19, 2026
1fbbad7
fix(libSceUserService): check the thread priority on initialization
KernelPanicNT Oct 19, 2026
0a6c388
fix(libScePngDec): enforce decode width limit
MarcZX10 Oct 19, 2026
d0119e5
fix(libScePngDec): validate custom decode pitch
MarcZX10 Oct 19, 2026
8c84dfc
feat(agc): render layered draws into 2D array color views
gjonn Oct 17, 2026
a15694e
feat(agc): render layered draws into a one-slice surface as an array …
gjonn Oct 17, 2026
9457d72
fix(agc): check every slice pitch of a resident color array and keep …
gjonn Oct 17, 2026
deb0ba3
test(agc): render layered draws into 2D array color views
gjonn Oct 17, 2026
1ed8eb6
fix(shader): sample a 3D T# through DIM 2D_ARRAY as a volume
thuanquang Oct 18, 2026
826f1ab
fix(libSceNpAuthAuthorizedAppDialog): transition to finished on dialo…
ErenYeager1836 Oct 18, 2026
84a6f79
docs(libSceNpAuthAuthorizedAppDialog): document unverified close-befo…
ErenYeager1836 Oct 18, 2026
542fcef
docs(libSceNpAuthAuthorizedAppDialog): drop BOM and restore the exist…
adriadam10 Oct 19, 2026
83189d2
fix(libSceLoginDialog): transition to finished on dialog close
ErenYeager1836 Oct 18, 2026
1dbba02
docs(libSceLoginDialog): document unverified close-before-open lifecycle
ErenYeager1836 Oct 18, 2026
91abb61
fix(recompiler): use ActiveMaskImplies in SrtTape and restore debt entry
pushkarreddyy Oct 19, 2026
d2e5f1b
fix(libSceLoginDialog): drop BOM added to the debt file
adriadam10 Oct 19, 2026
28cc5a6
test(libScePngDec): size padded output for both rows
MarcZX10 Oct 19, 2026
bcb65a3
Merge pull request #7399 from MarcZX10/codex/dialog-close-finished
adriadam10 Oct 19, 2026
f39852f
Merge pull request #7397 from ErenYeager1836/fix/npauth-authorized-ap…
adriadam10 Oct 19, 2026
b7fc3d3
Merge pull request #7404 from ErenYeager1836/fix/cdlg-g2p-close-status
adriadam10 Oct 19, 2026
d10ef4d
Merge pull request #7381 from thuanquang/fix/volume-array-sample
adriadam10 Oct 19, 2026
8075b6a
Merge pull request #7398 from ErenYeager1836/fix/login-dialog-close-s…
adriadam10 Oct 19, 2026
f745930
Merge pull request #7413 from thuanquang/fix/table-call-hoisted-descr…
adriadam10 Oct 19, 2026
19f21eb
Merge pull request #7415 from milescoviello/fix/staged-clear-format
adriadam10 Oct 19, 2026
aea539e
Merge pull request #7854 from KernelPanicNT/fix/userservice-initializ…
oneandonlydean Oct 19, 2026
dd4c2a4
Merge pull request #7418 from tkcm01/fix/relinker-backup-copy-export-…
adriadam10 Oct 19, 2026
dfd22c1
Merge pull request #7428 from mrfelek/fix/ngs2-setup-clears-callback
adriadam10 Oct 19, 2026
f1861e4
Merge pull request #7855 from KernelPanicNT/fix/pngdec-create-max-width
oneandonlydean Oct 19, 2026
b372f30
Merge pull request #7857 from MarcZX10/codex/pngdec-decode-width-limit
oneandonlydean Oct 19, 2026
e80325a
Merge pull request #7860 from MarcZX10/codex/pngdec-pitch-validation
oneandonlydean Oct 19, 2026
7fe0790
Merge pull request #7388 from pushkarreddyy/feat/recompiler-waterfall…
adriadam10 Oct 19, 2026
cde1ffd
Merge pull request #7254 from gjonn/feat/agc-layered-2d-array-color-v…
adriadam10 Oct 19, 2026
252cbc2
Merge pull request #7430 from MrMha/feat/performance-context-gate-202…
adriadam10 Oct 19, 2026
ec5c0c3
feat(libc): implement sceLibcBacktraceSelf on Windows
claude Oct 19, 2026
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
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ class StorageTexture : public std::enable_shared_from_this<StorageTexture> {
void WriteBack();
// Deferred write-back (APS5_EAGER_WRITEBACK=1 stores at once instead).
void MarkDirty();
void MarkSliceDirty(std::uint32_t slice);
void MarkSliceDirty(std::uint32_t slice, std::uint32_t count = 1);
void Flush();
bool Dirty() const;
// Stores every pending image overlapping the range, except `except`; returns whether any was.
Expand Down
21 changes: 13 additions & 8 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1648,7 +1648,7 @@ struct Kept {
// The completion side of a recorded draw: the kept objects, the record check, the lease outcome,
// the GPU write notes, the copied-buffer write-back (listed in DrawCopiedWriters or run as a
// completion action) and the targets marked dirty.
void keepRecordedDraw(Recorder& recorder, const std::shared_ptr<ShaderResources>& resources, std::shared_ptr<Pipeline> pipeline, std::shared_ptr<Framebuffer> framebuffer, DrawInputs& inputs, std::vector<std::shared_ptr<StorageTexture>> targets, std::vector<std::uint32_t> slices, std::unique_ptr<DeviceBuffer> scratch, std::function<void()> checkRecords, bool listed, bool completion, const DrawOutcome& outcome) {
void keepRecordedDraw(Recorder& recorder, const std::shared_ptr<ShaderResources>& resources, std::shared_ptr<Pipeline> pipeline, std::shared_ptr<Framebuffer> framebuffer, DrawInputs& inputs, std::vector<std::shared_ptr<StorageTexture>> targets, std::vector<std::pair<std::uint32_t, std::uint32_t>> slices, std::unique_ptr<DeviceBuffer> scratch, std::function<void()> checkRecords, bool listed, bool completion, const DrawOutcome& outcome) {
auto kept = std::make_shared<Kept>();
kept->resources = resources;
kept->pipeline = std::move(pipeline);
Expand Down Expand Up @@ -1689,7 +1689,7 @@ void keepRecordedDraw(Recorder& recorder, const std::shared_ptr<ShaderResources>
}
for (std::size_t index = 0; index < residents.size(); ++index) {
if (residents[index] == nullptr) continue;
if (index < slices.size()) residents[index]->MarkSliceDirty(slices[index]);
if (index < slices.size()) residents[index]->MarkSliceDirty(slices[index].first, slices[index].second);
else residents[index]->MarkDirty();
}
for (const auto& resident : residents) {
Expand All @@ -1709,7 +1709,7 @@ struct RecordedDraw {
std::shared_ptr<Framebuffer> framebuffer;
std::span<const VkImageView> targetViews;
std::vector<std::shared_ptr<StorageTexture>> targets;
std::vector<std::uint32_t> targetSlices;
std::vector<std::pair<std::uint32_t, std::uint32_t>> targetSlices;
std::vector<std::shared_ptr<void>> multisampleTargets;
std::vector<std::shared_ptr<StorageTexture>> proxies;
std::vector<VkImage> multisampleImages;
Expand Down Expand Up @@ -2197,7 +2197,11 @@ void Draw(const Context& context, const State& state, const Pm4::DrawParameters&
if (color.arrayLastSlice != 0) {
Require(color.dccAddress == 0 && color.cmaskAddress == 0 && AttachmentProxyFormat(context, color.format) == VK_FORMAT_UNDEFINED, "a slice of a 2D array color target with DCC, CMASK or an attachment proxy has no resident array image");
const auto array = ArraySurfaceForTarget(color);
Require(color.surfaceAddress == color.arrayAddress + color.arraySlice * DescribeSurface(array).layerBytes, "the array image's layer pitch differs from the color view's slice offset");
// DecodeColorBuffer offsets slice s by s times this size; every slice the image stores must agree.
const auto sliceBytes = ComputeSurfaceSize(ComputeElementMipLayout(ColorTextureTileMode(color.tileMode), color.elementBytes, color.surfaceExtent.width, color.surfaceExtent.height, color.mipCount), 1);
const auto geometry = DescribeSurface(array);
for (std::uint32_t slice = 0; slice <= color.arrayLastSlice; ++slice) Require(geometry.GuestLayerOffset(slice) == slice * sliceBytes, "the array image's layer pitch differs from the color view's slice offset");
Require(color.surfaceAddress == color.arrayAddress + color.arraySlice * sliceBytes, "the array image's layer pitch differs from the color view's slice offset");
auto resident = CachedStorageSurface(context, array);
Require(resident->Attachable(), "storage format cannot be a color attachment");
return resident;
Expand All @@ -2217,6 +2221,7 @@ void Draw(const Context& context, const State& state, const Pm4::DrawParameters&
materializeCmaskClear(context, color, nullptr);
Require(!color.mipTail || binding.gpuTiling, "rendering into a packed mip tail requires the GPU tiled fallback");
Require(color.depth == 1, "rendering into a 3D color target needs the resident image of its surface");
Require(color.layers == 1, "layered rendering into a 2D array color target needs the resident image of its array");
Require(color.arraySlice == 0 || !ColorTileModeIsXor(color.tileMode), "rendering into a slice of a 2D array color target with an XOR tile mode needs the resident image of its array");
if (binding.gpuTiling) {
binding.mip = color.mipTail ? ComputeColorTargetMipLayout(color.tileMode, color.elementBytes, color.surfaceExtent.width, color.surfaceExtent.height, color.mipCount, color.mip) : ColorTargetMip(color, colorLayout);
Expand Down Expand Up @@ -2451,7 +2456,7 @@ void Draw(const Context& context, const State& state, const Pm4::DrawParameters&
record.framebuffer = framebuffer;
record.targetViews = targetViews;
record.targets = owners;
for (const auto& binding : targets) record.targetSlices.push_back(binding.color.arraySlice);
for (const auto& binding : targets) record.targetSlices.emplace_back(binding.color.arraySlice, binding.color.arrayLastSlice != 0 ? binding.color.layers : 1u);
for (const auto& binding : targets) {
if (binding.proxied) record.proxies.push_back(binding.resident);
if (binding.multisampled) {
Expand Down Expand Up @@ -2665,7 +2670,7 @@ void Draw(const Context& context, const State& state, const Pm4::DrawParameters&
APS5_LOG_CHARS_OUT_DEBUG("SubmitAndWait");
timer.phase(PhaseRecord);
if (recorded) {
keepRecordedDraw(*recorder, resources, pipeline, framebuffer, inputs, owners, [&] { std::vector<std::uint32_t> slices; for (const auto& binding : targets) slices.push_back(binding.color.arraySlice); return slices; }(), std::move(scratch), std::move(checkRecords), listed, completion, outcome);
keepRecordedDraw(*recorder, resources, pipeline, framebuffer, inputs, owners, [&] { std::vector<std::pair<std::uint32_t, std::uint32_t>> slices; for (const auto& binding : targets) slices.emplace_back(binding.color.arraySlice, binding.color.arrayLastSlice != 0 ? binding.color.layers : 1u); return slices; }(), std::move(scratch), std::move(checkRecords), listed, completion, outcome);
timer.phase(PhaseKeep);
if (outcome.waited) {
// The wait the dispatch path makes for such work (source 3, "address-based"): the
Expand Down Expand Up @@ -2711,7 +2716,7 @@ void Draw(const Context& context, const State& state, const Pm4::DrawParameters&
if (skipTargetWrite) break;
if (binding.resident != nullptr) {
// The results stay on the GPU until something reads the target's memory.
binding.resident->MarkSliceDirty(binding.color.arraySlice);
binding.resident->MarkSliceDirty(binding.color.arraySlice, binding.color.arrayLastSlice != 0 ? binding.color.layers : 1u);
continue;
}
if (binding.gpuTiling) GuestMemory::WriteChanged(binding.color.address, binding.tiled->Bytes(), binding.original);
Expand Down Expand Up @@ -2854,7 +2859,7 @@ DrawRecipeOutcome DrawWithRecipe(const Context& context, const State& state, con
record.framebuffer = std::move(framebuffer);
record.targetViews = recipe.targetViews;
record.targets = std::move(targets);
for (const auto& color : state.colors) record.targetSlices.push_back(color.arraySlice);
for (const auto& color : state.colors) record.targetSlices.emplace_back(color.arraySlice, color.arrayLastSlice != 0 ? color.layers : 1u);
record.pushBytes = &recipe.pushBytes;
record.pushStages = recipe.pushStages;
recordDraw(context, state, draw, shaders, inputs, record, outcome, timer, ownWaitedMs);
Expand Down
8 changes: 7 additions & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1659,7 +1659,13 @@ ColorTarget DecodeColorBuffer(const Registers& cx, std::uint32_t slot, bool allo
}
if (!volume && lastSlice != slice) {
const auto exports = find(cx, 0x207);
Require(exports == cx.end() || (exports->second & (1u << 18u)) == 0, "layered draws into a color view of several array slices are unsupported");
if (exports != cx.end() && (exports->second & (1u << 18u)) != 0) {
if (color.arrayLastSlice == 0) {
color.arrayLastSlice = lastSlice;
color.arraySlice = slice;
}
color.layers = lastSlice + 1u - slice;
}
}
color.extent = {((attrib2 >> 14u) & 0x3fffu) + 1u, (attrib2 & 0x3fffu) + 1u};
color.elementBytes = decoded.elementBytes;
Expand Down
11 changes: 6 additions & 5 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1822,8 +1822,9 @@ VkImageView StorageTexture::AttachmentView(VkFormat format, std::uint32_t mip, s
Require(attachable, "storage image cannot be a color attachment");
Require(mip < descriptor.mipCount, "attachment mip exceeds the storage image");
const bool volume = descriptor.dimension == TextureDimension::k3D;
Require((depthSlice == 0 && layers == 1) || (volume && mip == 0 && layers != 0 && depthSlice + layers - 1u <= descriptor.depthOrLastArray), "attachment slice is outside the storage image");
Require(layer == 0 || (!volume && descriptor.dimension == TextureDimension::k2DArray && descriptor.baseArray + layer <= descriptor.depthOrLastArray), "attachment layer is outside the storage image");
const bool array = !volume && descriptor.dimension == TextureDimension::k2DArray;
Require((depthSlice == 0 && layers == 1) || (volume && mip == 0 && layers != 0 && depthSlice + layers - 1u <= descriptor.depthOrLastArray) || (array && depthSlice == 0 && layers != 0), "attachment slice is outside the storage image");
Require((layer == 0 && layers == 1) || (volume && layer == 0) || (array && descriptor.baseArray + layer + layers - 1u <= descriptor.depthOrLastArray), "attachment layer is outside the storage image");
const auto found = attachmentViews.find({format, mip, depthSlice, layers, layer});
if (found != attachmentViews.end()) return found->second;
VkImageViewUsageCreateInfo usage{VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO};
Expand Down Expand Up @@ -3515,14 +3516,14 @@ void StorageTexture::MarkDirty() {
markLayersPending(0, trackedLayers);
}

void StorageTexture::MarkSliceDirty(std::uint32_t slice) {
if (geometry.thick || geometry.imageLayers <= 1 || slice >= geometry.imageLayers || geometry.layerBytes == 0 || trackedLayerBytes == 0 || descriptor.dccAddress != 0) {
void StorageTexture::MarkSliceDirty(std::uint32_t slice, std::uint32_t count) {
if (geometry.thick || geometry.imageLayers <= 1 || count == 0 || slice >= geometry.imageLayers || count > geometry.imageLayers - slice || geometry.layerBytes == 0 || trackedLayerBytes == 0 || descriptor.dccAddress != 0) {
MarkDirty();
return;
}
const auto begin = geometry.GuestLayerOffset(slice);
const auto first = static_cast<std::uint32_t>(begin / trackedLayerBytes);
const auto last = static_cast<std::uint32_t>(std::min<std::uint64_t>((begin + geometry.layerBytes + trackedLayerBytes - 1) / trackedLayerBytes, trackedLayers));
const auto last = static_cast<std::uint32_t>(std::min<std::uint64_t>((begin + geometry.layerBytes * count + trackedLayerBytes - 1) / trackedLayerBytes, trackedLayers));
if (first >= last) {
MarkDirty();
return;
Expand Down
6 changes: 4 additions & 2 deletions core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2341,7 +2341,8 @@ void DepthStencilTests() {
const auto firstSlice = AgcDriver::Graphics::DecodeState(queue);
Require(firstSlice.color.address == reinterpret_cast<std::uintptr_t>(colorMemory.data()), "a color view of several slices did not retain its first slice");
queue.context[0x207] = 1u << 18u;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "layered draws into a color view of several array slices");
const auto layeredSingle = AgcDriver::Graphics::DecodeState(queue);
Require(layeredSingle.color.address == firstSlice.color.address && layeredSingle.color.arrayAddress == firstSlice.color.address && layeredSingle.color.arrayLastSlice == 1u && layeredSingle.color.layers == 2u && layeredSingle.renderLayers == 2u, "a layered draw into slices 0 to 1 of a surface of one slice did not render them as a two-slice array");
queue.context[0x207] = 0;
const auto sliced = reinterpret_cast<std::uintptr_t>(sliceMemory.data());
queue.context[0x318] = static_cast<std::uint32_t>(sliced >> 8u);
Expand All @@ -2356,7 +2357,8 @@ void DepthStencilTests() {
const auto range = AgcDriver::Graphics::DecodeState(queue);
Require(range.color.address == sliced && range.color.bytes == 1024u, "a color view of slices 0 to 1 of a 2D array target did not render into its first slice");
queue.context[0x207] = 1u << 18u;
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "layered draws into a color view of several array slices");
const auto layeredArray = AgcDriver::Graphics::DecodeState(queue);
Require(layeredArray.color.address == sliced && layeredArray.color.arraySlice == 0u && layeredArray.color.layers == 2u && layeredArray.renderLayers == 2u && layeredArray.layerExports != 0u, "a layeredArray draw into slices 0 to 1 of a 2D array target did not render two layers");
queue.context[0x207] = 0;
queue.context[0x31b] = 2u | (2u << 13u);
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "beyond the array surface");
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/tests/ShaderDiskCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ CompiledVariant sampleVariant() {
image.cubeFaceCompatible = false;
image.flatVolumeCompatible = false;
image.singleMipPlaneBiasCompatible = true;
image.volumeArraySampleCompatible = true;
image.flatLineCompatible = false;
image.flatVolumeLineCompatible = false;
image.foldTexelOffsetsOnly = true;
Expand Down
Loading