Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
513282c
feat(libc): implement ilogb and ilogbf
BIGFERRY999 Oct 14, 2026
5ecd999
feat(libc): implement clearerr_unlocked, fileno_unlocked and fgetln
T3cm0 Oct 17, 2026
60a3dc2
feat(libc): implement bounded error message APIs
Lorkydey Oct 17, 2026
75fc5a4
fix(libkernel): answer F_GETLK with F_UNLCK on Linux and macOS
AlexOfTheForest Oct 17, 2026
b8f76b9
test(libkernel): cover F_GETLK against another process's record locks
AlexOfTheForest Oct 17, 2026
f69d530
fix(libkernel): measure the host stack reserve from the frame address
milescoviello Oct 17, 2026
15a3896
fix(libkernel): leave a blocked SIGALRM expiry pending
LaunchDoesntCode Oct 17, 2026
96b9d01
fix(libkernel): accept an uninitialized attribute in scePthreadCondInit
Lindamea1 Oct 17, 2026
75fc33c
fix(libkernel): treat a null deadline as an untimed lock in the timed…
milescoviello Oct 17, 2026
2ec7b26
fix(libkernel): return EINVAL/EFAULT from getrusage instead of throwing
milescoviello Oct 17, 2026
93cb3ec
fix(libkernel): return EFAULT from sceKernelRead/sceKernelWrite for a…
milescoviello Oct 17, 2026
86ab5c8
fix(libkernel): return EINVAL from the scePthreadAttr stack and guard…
milescoviello Oct 17, 2026
543ca66
fix(libkernel): return EINVAL from read and write for a byte count ab…
milescoviello Oct 17, 2026
9d90f5c
fix(libkernel): return ENOTSUP from pthread_attr_setschedparam and se…
milescoviello Oct 17, 2026
fab260a
fix(libkernel): return 0 from sceKernelMprotect and sceKernelMtypepro…
milescoviello Oct 17, 2026
5e93a78
fix(libkernel): return EFAULT from sceKernelWriteThrottlingStatus for…
pushkarreddyy Oct 17, 2026
e5541e3
fix(libkernel): return EFAULT from clock_gettime for a null result po…
Bonjourcestmatt Oct 15, 2026
b8f1854
fix(libkernel): take NOTE_LOWAT on socket read and write events
milescoviello Oct 17, 2026
d8e7173
fix(libkernel): reject connects on listening sockets first
Oct 18, 2026
17161cb
fix(libkernel): reject PTHREAD_PROCESS_SHARED in pshared setters as t…
ionut27001 Oct 17, 2026
0c60a31
fix(relinker): decode near branches with an operand-size prefix as AM…
Oct 17, 2026
228c0ad
fix(relinker): keep the Windows TLS rewrite from moving truncated bra…
Oct 17, 2026
9847458
fix(relinker): move a neighbour without an FS or GS prefix with a 256…
morten-holm Oct 17, 2026
6bc4f40
test(relinker): keep an FS or GS access out of the window of a 256-bi…
morten-holm Oct 17, 2026
57f0511
feat(libSceJobManager): implement compute sequences and compute dispa…
fma-rc Oct 11, 2026
a784572
feat(agc): count the render passes recorded draws begin and continue
EagleBearerYS Oct 17, 2026
73a90d9
perf(agc): let a draw that only reads through the BDA table continue …
EagleBearerYS Oct 17, 2026
c271995
test(agc): check that draws reading through the BDA table share a ren…
EagleBearerYS Oct 17, 2026
f573a3a
fix(agc): let the storage image cache budget follow the heap's use li…
SleglJan Oct 17, 2026
53c1aea
fix(agc): decode COLOR_8_8 UINT as R8G8_UINT
mazen320 Oct 14, 2026
4f3a84b
perf(agc): release settle-retired imports after the overlap block of …
oneandonlydean Oct 18, 2026
09965e3
fix(recompiler): drop a sample-adjust S# dword 3 that sets only reser…
gjonn Oct 17, 2026
89e459b
perf(shader): fold a select nested in a select on the same condition
milescoviello Oct 17, 2026
b792e9c
fix(shader): read low-half 16-bit multiply factors as 24-bit fields
thuanquang Oct 17, 2026
2c9e7d4
fix(libkernel): recognize listening sockets on macOS hosts
mugurc Oct 17, 2026
33fd61a
fix(libkernel): set the open file limit at load on macOS
DavidSamir Oct 16, 2026
38c51a6
test(libkernel): check the macOS open file limit against EMFILE
DavidSamir Oct 16, 2026
8e80b6c
fix(libc): keep errno when strtol converts nothing on macOS
DavidSamir Oct 16, 2026
ed1ac09
fix(libc): keep errno in strtoimax, strtoumax and _Stoul on macOS
DavidSamir Oct 16, 2026
2e7b168
docs(debt): record the macOS RLIMIT_NOFILE at load in libkernel.md
DavidSamir Oct 16, 2026
f4e4c4c
fix(agc): drop committed conflict markers in DepthSurface.cpp
RINNECODER Oct 18, 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
15 changes: 15 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,8 @@ target_include_directories(agc_driver_swap_alt_blend_tests PRIVATE $<TARGET_PROP

target_include_directories(agc_driver_packed_float_color_target_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)

target_link_libraries(agc_driver_job_manager_compute_tests PRIVATE libSceJobManager libSceAgc libkernel)

target_include_directories(agc_driver_packed_unorm_color_target_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)

target_include_directories(agc_driver_color1555_target_tests PRIVATE $<TARGET_PROPERTY:shader_recompiler_agc_driver,INTERFACE_INCLUDE_DIRECTORIES>)
Expand Down Expand Up @@ -1937,6 +1939,19 @@ if(BUILD_TESTING)
endif()


add_test_executable(agc_constant_select_tests EXCLUDE_FROM_ALL tests/ConstantSelect.cpp)
target_link_libraries(agc_constant_select_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_constant_select_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_constant_select_tests)
if(BUILD_TESTING)
set_target_properties(agc_constant_select_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
add_test(NAME agc_constant_select COMMAND agc_constant_select_tests)
if(WIN32)
set_tests_properties(agc_constant_select PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()

add_test_executable(agc_constant_select_tests EXCLUDE_FROM_ALL tests/ConstantSelect.cpp)
target_link_libraries(agc_constant_select_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_constant_select_tests PROPERTIES CXX_EXTENSIONS OFF)
Expand Down
9 changes: 9 additions & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ bool DrawRecipes();
enum class IndirectDrawPath : std::uint8_t { Gpu, NotFolded, FetchUnknown, NonVertexPath, IndxOffset, DrawIndex, VertexRange, FeatureGap, PendingImage, PendingLabelOrCopy, NotImported, Disabled, Count };
void CountIndirectDraw(IndirectDrawPath path, double readMs, bool rewritten = false);
std::array<std::uint64_t, static_cast<std::size_t>(IndirectDrawPath::Count)> IndirectDrawCounts();

struct DrawPassCounts {
std::uint64_t draws = 0;
std::uint64_t passesBegun = 0;
std::uint64_t passesContinued = 0;
std::uint64_t keyStoreFlushes = 0;
std::uint64_t storeFlushes = 0;
};
std::array<DrawPassCounts, 2> DrawPassTotals();
const char* IndirectDrawPathName(IndirectDrawPath path);

// Draw packets that drew nothing, for the [draws] line: Nothing (an empty count, or no color writes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ class Recorder;
void FlushCachedTextures(VkDevice device);
void ClearCachedTextures(VkDevice device);
std::uint64_t TextureCacheBudget(const VkPhysicalDeviceMemoryProperties& memory);
std::uint64_t StorageTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported);
std::uint64_t StorageTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported, std::uint64_t sampledBytes, std::uint64_t storageBytes);
std::uint64_t SampledTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported, std::uint64_t textureBytes);
bool SampledBudgetReportDue(std::uint64_t reported, std::uint64_t budget, std::chrono::steady_clock::duration sinceReport);
std::uint64_t StorageTextureCacheBudget(const Context& context);
struct TextureCacheUse {
std::size_t sampledEntries = 0;
std::uint64_t sampledBytes = 0;
Expand Down
3 changes: 0 additions & 3 deletions core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,6 @@ class DepthSurface {
VkImageAspectFlags pendingClear = 0;
float clearDepth = 0.0f;
std::uint8_t clearStencil = 0;
<<<<<<< HEAD
=======

bool StorageViewMatches(std::span<const std::uint32_t> words, const GuestTextureResource& resource) const {
if (resource.width != target.extent.width || resource.height != target.extent.height) return false;
Expand Down Expand Up @@ -447,7 +445,6 @@ class DepthSurface {
else Recorder::CountBarriers(Recorder::CommandClass::Copy, 3);
}

>>>>>>> 92f170c67 (fix(agc): treat a view past a depth surface's first level as memory)
const Context context;
const DepthTarget target;
const VkFormat hostFormat;
Expand Down
34 changes: 31 additions & 3 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ struct DrawOutcome {
// A recorded draw began a render pass of its own, or continued the previous draw's.
bool passBegun = false;
bool passContinued = false;
bool keyStoresFlushed = false;
bool storesFlushed = false;
bool addressDraw = false;
SyncReason reason = SyncNone;
// Shader validation memo (see CachedFragmentOutputs).
bool validateMemoized = false;
Expand Down Expand Up @@ -464,6 +467,7 @@ struct DrawProfile {
// Render passes recorded draws began, and draws that continued the previous draw's pass.
std::uint64_t passesBegun = 0;
std::uint64_t passesContinued = 0;
std::array<DrawPassCounts, 2> passTotals{};
std::array<std::uint64_t, SyncCount> reasons{};
// The CPU inside Graphics::Draw, split by outcome: a synchronous draw costs ten times a recorded
// one, so one average would only show the synchronous population.
Expand Down Expand Up @@ -534,6 +538,14 @@ void reportDraw(const std::array<double, PhaseCount>& us, const ShaderResources:
if (outcome.completion) ++profile.completion;
if (outcome.passBegun) ++profile.passesBegun;
if (outcome.passContinued) ++profile.passesContinued;
if (outcome.recorded) {
auto& totals = profile.passTotals[outcome.addressDraw ? 1 : 0];
++totals.draws;
if (outcome.passBegun) ++totals.passesBegun;
if (outcome.passContinued) ++totals.passesContinued;
if (outcome.keyStoresFlushed) ++totals.keyStoreFlushes;
if (outcome.storesFlushed) ++totals.storeFlushes;
}
++profile.reasons[outcome.reason];
(outcome.recorded ? (outcome.waited ? profile.waitedUs : profile.recordedUs) : profile.synchronousUs) += drawUs;
profile.targetLookups += outcome.targetLookups;
Expand Down Expand Up @@ -871,6 +883,12 @@ std::array<std::uint64_t, IndirectPathCount> IndirectDrawCounts() {
return stats.indirect;
}

std::array<DrawPassCounts, 2> DrawPassTotals() {
auto& stats = Profile();
std::lock_guard lock(stats.mutex);
return stats.passTotals;
}

void CountDrawSkip(DrawSkip kind, double us) {
static const bool profile = std::getenv("APS5_PROFILE_DRAW") != nullptr;
if (!profile) return;
Expand Down Expand Up @@ -1721,13 +1739,20 @@ void recordDraw(const Context& context, const State& state, const Pm4::DrawParam
if (!gpuIndirect) return false;
return (begin < args->arguments + args->RangeBytes() && args->arguments < end) || (args->countIndirect && begin < args->countAddress + 4 && args->countAddress < end);
};
if (recorder->HasQueuedKeyStores() && (resources.HoldsLease() || recorder->AnyQueuedKeyStore(touches))) recorder->FlushKeyStores();
if (recorder->HasQueuedKeyStores() && (resources.HoldsLease() || recorder->AnyQueuedKeyStore(touches))) {
recorder->FlushKeyStores();
outcome.keyStoresFlushed = true;
}
// A queued label store over such memory likewise (Recorder::RecordStore).
if (recorder->HasQueuedStores() && (resources.HoldsLease() || recorder->AnyQueuedStore(touches))) recorder->FlushStores();
if (recorder->HasQueuedStores() && (resources.HoldsLease() || recorder->AnyQueuedStore(touches))) {
recorder->FlushStores();
outcome.storesFlushed = true;
}
const auto drawBindings = resources.PrepareDrawBindings(*recorder, record.moved);
const bool capture = CaptureInputsEnabled();
const bool meshIndirect = state.stages.mesh && args != nullptr;
const bool addressBased = resources.HoldsLease();
outcome.addressDraw = addressBased;
auto passReads = addressBased ? std::vector<std::pair<std::uint64_t, std::uint64_t>>{} : resources.DeviceReads();
if (gpuIndirect) {
passReads.emplace_back(args->arguments, args->arguments + args->RangeBytes());
Expand All @@ -1740,7 +1765,10 @@ void recordDraw(const Context& context, const State& state, const Pm4::DrawParam
if (target != nullptr) passAttachments.emplace_back(target->Image(), true);
}
const bool unknownMemory = addressBased || resources.UsesAddressTable() || resources.HasCopiedWrites();
const PassAccess passAccess{passReads, resources.GpuWrites(), passImages, passAttachments, unknownMemory, unknownMemory};
static const bool addressReadPasses = std::getenv("APS5_NO_ADDRESS_READ_PASSES") == nullptr;
const bool readOnlyBda = addressReadPasses && resources.BdaReadOnly();
const bool unknownWrites = ((addressBased || resources.UsesAddressTable()) && !readOnlyBda) || resources.HasCopiedWrites();
const PassAccess passAccess{passReads, resources.GpuWrites(), passImages, passAttachments, unknownMemory, unknownWrites};
const bool fenced = state.depth.has_value() || !record.proxies.empty();
const auto start = recorder->StartDrawPass(passKey, capture || readsTarget || gpuIndirect || meshIndirect, fenced, passAccess);
const bool continued = start.continued;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,9 @@ bool WaitForLeasesAndImports(std::uintptr_t address, std::size_t bytes) noexcept
} catch (const std::exception& error) {
std::fprintf(stderr, "[gpu] lease wait failed: %s\n", error.what());
}
#ifdef _WIN32
if (releaseSettleRetired(imports, address, end)) retiredImport = true;
#endif
}
auto& state = Leases();
std::lock_guard lock(state.mutex);
Expand Down
27 changes: 21 additions & 6 deletions core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ struct TextureCache {
std::chrono::steady_clock::time_point budgetRead{};
std::uint64_t budget = 0;
std::uint64_t reportedBudget = 0;
std::uint64_t reportedStorage = 0;
std::chrono::steady_clock::time_point reportedAt{};
std::uint64_t erasures = 0;
};
Expand Down Expand Up @@ -499,7 +500,7 @@ std::uint64_t storageBudget(const Context& context) {
context.memoryProperties2(context.physical, &properties);
cached.device = context.physical;
cached.read = now;
cached.budget = StorageTextureBudget(context.memory, &reported);
cached.budget = StorageTextureBudget(context.memory, &reported, SampledTextureMemory(), storageCacheBytes());
return cached.budget;
}

Expand All @@ -516,11 +517,17 @@ std::uint64_t sampledBudget(const Context& context, TextureCache& cache) {
const auto storage = storageCacheBytes();
const auto budget = SampledTextureBudget(context.memory, &reported, sampled + storage);
const bool fresh = cache.budgetDevice != context.physical;
if (const auto heap = largestDeviceLocalHeap(context.memory); heap && (fresh || SampledBudgetReportDue(cache.reportedBudget, budget, now - cache.reportedAt))) {
const auto storageLimit = storageBudget(context);
if (const auto heap = largestDeviceLocalHeap(context.memory); heap && (fresh || SampledBudgetReportDue(cache.reportedBudget, budget, now - cache.reportedAt) || SampledBudgetReportDue(cache.reportedStorage, storageLimit, now - cache.reportedAt))) {
char was[48] = "";
if (!fresh) std::snprintf(was, sizeof(was), " (was %llu MiB)", static_cast<unsigned long long>(cache.reportedBudget >> 20u));
std::fprintf(stderr, "[gpu] sampled texture cache budget %llu MiB%s: device-local heap %u has a VK_EXT_memory_budget budget of %llu MiB and uses %llu MiB, %llu MiB of it sampled textures (%llu MiB in the cache) and %llu MiB cached storage images; storage image cache budget %llu MiB\n", static_cast<unsigned long long>(budget >> 20u), was, *heap, static_cast<unsigned long long>(reported.heapBudget[*heap] >> 20u), static_cast<unsigned long long>(reported.heapUsage[*heap] >> 20u), static_cast<unsigned long long>(sampled >> 20u), static_cast<unsigned long long>(cache.bytes >> 20u), static_cast<unsigned long long>(storage >> 20u), static_cast<unsigned long long>(storageBudget(context) >> 20u));
char wasStorage[48] = "";
if (!fresh) {
std::snprintf(was, sizeof(was), " (was %llu MiB)", static_cast<unsigned long long>(cache.reportedBudget >> 20u));
std::snprintf(wasStorage, sizeof(wasStorage), " (was %llu MiB)", static_cast<unsigned long long>(cache.reportedStorage >> 20u));
}
std::fprintf(stderr, "[gpu] sampled texture cache budget %llu MiB%s: device-local heap %u has a VK_EXT_memory_budget budget of %llu MiB and uses %llu MiB, %llu MiB of it sampled textures (%llu MiB in the cache) and %llu MiB cached storage images; storage image cache budget %llu MiB%s\n", static_cast<unsigned long long>(budget >> 20u), was, *heap, static_cast<unsigned long long>(reported.heapBudget[*heap] >> 20u), static_cast<unsigned long long>(reported.heapUsage[*heap] >> 20u), static_cast<unsigned long long>(sampled >> 20u), static_cast<unsigned long long>(cache.bytes >> 20u), static_cast<unsigned long long>(storage >> 20u), static_cast<unsigned long long>(storageLimit >> 20u), wasStorage);
cache.reportedBudget = budget;
cache.reportedStorage = storageLimit;
cache.reportedAt = now;
}
cache.budgetDevice = context.physical;
Expand Down Expand Up @@ -943,10 +950,14 @@ std::uint64_t TextureCacheBudget(const VkPhysicalDeviceMemoryProperties& memory)
return std::max<std::uint64_t>(2048ull << 20u, heap ? memory.memoryHeaps[*heap].size / 4u : 0u);
}

std::uint64_t StorageTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported) {
std::uint64_t StorageTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported, std::uint64_t sampledBytes, std::uint64_t storageBytes) {
const auto heap = largestDeviceLocalHeap(memory);
if (reported == nullptr || !heap || reported->heapBudget[*heap] == 0) return TextureCacheBudget(memory);
return std::max<std::uint64_t>(512ull << 20u, std::min<std::uint64_t>(TextureCacheBudget(memory), reported->heapBudget[*heap] / 4u));
const auto budget = reported->heapBudget[*heap];
const auto usage = reported->heapUsage[*heap];
const auto reserved = usage - std::min<std::uint64_t>(usage, sampledBytes + storageBytes) + std::max<std::uint64_t>(2048ull << 20u, sampledBytes) + budget / 8u;
const auto cap = std::min<std::uint64_t>(TextureCacheBudget(memory), budget / 4u);
return std::max<std::uint64_t>(512ull << 20u, std::min<std::uint64_t>(cap, budget > reserved ? budget - reserved : 0u));
}

std::uint64_t SampledTextureBudget(const VkPhysicalDeviceMemoryProperties& memory, const VkPhysicalDeviceMemoryBudgetPropertiesEXT* reported, std::uint64_t textureBytes) {
Expand All @@ -963,6 +974,10 @@ bool SampledBudgetReportDue(std::uint64_t reported, std::uint64_t budget, std::c
return change > reported / 10u && sinceReport >= std::chrono::seconds(10);
}

std::uint64_t StorageTextureCacheBudget(const Context& context) {
return storageBudget(context);
}

TextureCacheUse TextureCacheUsage() {
TextureCacheUse use;
{
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ DecodedColorFormat DecodeColorFormat(std::uint32_t format, std::uint32_t number,
const auto mapping = static_cast<std::uint8_t>(alternate ? 0xecu : 0xe4u);
if (number == unorm) return {VK_FORMAT_R8G8_UNORM, 2, mapping};
if (number == snorm) return {VK_FORMAT_R8G8_SNORM, 2, mapping};
if (number == uint) return {VK_FORMAT_R8G8_UINT, 2, mapping};
return fail();
}
case 4:
Expand Down
Loading