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
7 changes: 7 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,13 @@ if(BUILD_TESTING)
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()

add_test(NAME agc_driver_stencil_replay_no_gpl COMMAND agc_driver_stencil_replay_tests)
set_tests_properties(agc_driver_stencil_replay_no_gpl PROPERTIES ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1;APS5_NO_GPL=1" TIMEOUT 30 SKIP_RETURN_CODE 77)
if(WIN32)
set_tests_properties(agc_driver_stencil_replay_no_gpl PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()

foreach(agcTest IN ITEMS agc_spirv_narrow_constant_store_tests agc_spirv13_image_tests agc_spirv_optimizer_tests agc_driver_constant_store_tests)
if(NOT TARGET ${agcTest})
continue()
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ struct State {
bool stencilTest = false;
VkStencilOpState stencilFront{};
VkStencilOpState stencilBack{};
std::optional<std::uint32_t> stencilReplayReference;
ColorTarget color;
std::vector<ColorTarget> colors;
std::vector<VkPipelineColorBlendAttachmentState> blends;
Expand Down
115 changes: 109 additions & 6 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,12 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
specializations.emplace_back(shader);
stages[i].pSpecializationInfo = specializations.back().Info();
}
if (std::ranges::any_of(shaders, [](const CompiledShader& shader) { return shader.program != nullptr && !shader.program->stencilReferences.empty(); })) {
for (std::size_t i = 0; i < shaders.size(); ++i) {
if (shaders[i].stage != ShaderRecompiler::ShaderStage::Vertex) continue;
Require(stages[i].flags == 0u && stages[i].pNext == nullptr, "stencil replay vertex stage allows varying subgroup size");
}
}
// A descriptor set layout with the same bindings as this one is compatible with the pipeline
// layout, so later draws bind their own ShaderResources' set under it.
const std::array<VkDescriptorSetLayout, 2> setLayouts{resources.main, resources.fragment};
Expand Down Expand Up @@ -412,6 +418,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
PipelineLibraryKeys keys;
libraries = libraryKeys(keys, context, state, vertexInput, resources, shaders);
std::vector<VkDynamicState> dynamicStates{VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
if (state.stencilReplayReference) dynamicStates.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
if (depthBounds) dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
if (depthBias) dynamicStates.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
if (libraries) dynamicStates.assign(PipelineLibraryDynamicStates().begin(), PipelineLibraryDynamicStates().end());
Expand Down Expand Up @@ -536,6 +543,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
}

bool Pipeline::Prebuild(const Context& context, const State& state, const VertexInputLayout& vertexInput, const PipelineSetLayouts& resources, std::span<const CompiledShader> shaders) {
if (std::ranges::any_of(shaders, [](const CompiledShader& shader) { return !shader.program->stencilReferences.empty(); })) return false;
struct Scope {
Scope() { prebuilding = true; prebuilt = false; }
~Scope() { prebuilding = false; }
Expand Down Expand Up @@ -688,6 +696,7 @@ void Pipeline::Continue(VkCommandBuffer commands, const State& state) const {
context.Resolved(&DeviceFunctions::cmdBindPipeline, "vkCmdBindPipeline")(commands, VK_PIPELINE_BIND_POINT_GRAPHICS, best != VK_NULL_HANDLE ? best : pipeline);
context.Resolved(&DeviceFunctions::cmdSetViewport, "vkCmdSetViewport")(commands, 0, 1, &state.viewport);
context.Resolved(&DeviceFunctions::cmdSetScissor, "vkCmdSetScissor")(commands, 0, 1, &state.scissor);
if (state.stencilReplayReference) context.Resolved(&DeviceFunctions::cmdSetStencilReference, "vkCmdSetStencilReference")(commands, VK_STENCIL_FACE_FRONT_AND_BACK, *state.stencilReplayReference);
if (libraries) {
setLibraryState(commands, state);
return;
Expand Down Expand Up @@ -826,8 +835,12 @@ void pipelineKey(std::vector<std::byte>& key, const Context& context, const Stat
append(key, state.depthBias);
append(key, state.depthBiasPerFace);
append(key, state.stencilTest);
append(key, state.stencilFront);
append(key, state.stencilBack);
auto front = state.stencilFront;
auto back = state.stencilBack;
if (state.stencilReplayReference) front.reference = back.reference = 0u;
append(key, state.stencilReplayReference.has_value());
append(key, front);
append(key, back);
}
append(key, state.stages.mesh.has_value());
if (state.stages.mesh) {
Expand Down
43 changes: 42 additions & 1 deletion core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5216,7 +5216,48 @@ void stencilRefExportTests() {
Require(both == "capability extension depth replacing builtin store ", "a depth and stencil reference export declared the wrong outputs: " + both);
const auto depthOnly = stencilRefShape(ShaderRecompiler::Recompile(stencilRefExportRequest(0x51u, stencilExport, DepthStencilRefExportCode)).spirv.Words());
Require(depthOnly == "depth ", "an MRTZ stencil channel without STENCIL_TEST_VAL_EXPORT_ENABLE declared the wrong outputs: " + depthOnly);
expectFailure([&] { static_cast<void>(ShaderRecompiler::Recompile(stencilRefExportRequest(0x52u, plain))); }, "VK_EXT_shader_stencil_export");
const auto emulated = ShaderRecompiler::Recompile(stencilRefExportRequest(0x52u, plain));
Require(emulated.stencilReferences == std::vector<std::uint32_t>{0u} && emulated.stencilReplaySafe && stencilRefShape(emulated.spirv.Words()).empty(), "a constant stencil reference was not lowered to replay");
Require(emulated.stencilReferenceDword == 0u && emulated.pushConstants.size() == sizeof(std::uint32_t), "a stencil-only shader did not reserve dynamic reference data");
auto replayRequest = stencilRefExportRequest(0x52u, plain);
const auto replayHandle = ShaderRecompiler::PrepareShader(replayRequest);
const auto replayCapture = ShaderRecompiler::CaptureResources(replayRequest, ShaderRecompiler::SrtRuntime{}, *replayHandle);
const auto firstReplay = ShaderRecompiler::MaterializeShader(replayRequest, *replayCapture, *replayHandle);
replayRequest.layout.pushConstantOffsetBytes = 128u;
Require(ShaderRecompiler::MatchesPreparedShader(replayRequest, *replayHandle), "moving the stencil replay stage slot invalidated the prepared artifact");
const auto movedReplay = ShaderRecompiler::MaterializeShader(replayRequest, *replayCapture, *replayHandle);
Require(firstReplay->spirv != movedReplay->spirv && firstReplay->variantId == movedReplay->variantId && firstReplay->pushConstants == movedReplay->pushConstants, "prepared stencil replay did not move only the dynamic reference offset");
replayRequest.layout.pushConstantSizeBytes = 0u;
Require(!ShaderRecompiler::MatchesPreparedShader(replayRequest, *replayHandle), "prepared stencil replay accepted an exhausted push range");
expectFailure([&] { static_cast<void>(ShaderRecompiler::Recompile(replayRequest)); }, "unused push constant dword");
const std::array<std::uint32_t, 5> pushedDepthStencil{0x7e000200u, 0x7e0e02f2u, 0xf8001883u, 0x700u, 0xbf810000u};
const std::array<std::uint32_t, 1> pushedDepth{0x3f000000u};
auto pushedRequest = stencilRefExportRequest(0x53u, plain, pushedDepthStencil);
pushedRequest.context.userData = pushedDepth;
pushedRequest.layout = {0u, 0u, 96u, 32u};
const auto pushedHandle = ShaderRecompiler::PrepareShader(pushedRequest);
ShaderRecompiler::SrtRuntime pushedRuntime{};
pushedRuntime.userData = pushedDepth;
const auto pushedCapture = ShaderRecompiler::CaptureResources(pushedRequest, pushedRuntime, *pushedHandle);
const auto pushedResult = ShaderRecompiler::MaterializeShader(pushedRequest, *pushedCapture, *pushedHandle);
Require(pushedResult->stencilReferenceDword == 1u && pushedResult->pushConstants.size() == 8u, "a nonaligned replay stage did not reserve its reference after existing push data");
for (const auto [offset, bytes] : {std::pair{128u, 128u}, std::pair{120u, 8u}}) {
pushedRequest.layout.pushConstantOffsetBytes = offset;
pushedRequest.layout.pushConstantSizeBytes = bytes;
Require(ShaderRecompiler::MatchesPreparedShader(pushedRequest, *pushedHandle), "a replay payload could not move within a valid stage range");
const auto moved = ShaderRecompiler::MaterializeShader(pushedRequest, *pushedCapture, *pushedHandle);
Require(moved->pushConstants == pushedResult->pushConstants && moved->spirv != pushedResult->spirv, "moving replay push data changed its payload or retained its old offset");
}
pushedRequest.layout = {0u, 0u, 124u, 4u};
Require(!ShaderRecompiler::MatchesPreparedShader(pushedRequest, *pushedHandle), "a full push budget reused a replay artifact");
expectFailure([&] { static_cast<void>(ShaderRecompiler::Recompile(pushedRequest)); }, "unused push constant dword");
pushedRequest.layout.pushConstantSizeBytes = 8u;
expectFailure([&] { static_cast<void>(ShaderRecompiler::Recompile(pushedRequest)); }, "crosses a stage slot");
const std::array<std::uint32_t, 4> noStencilExport{0x7e0e02f2u, 0xf800180fu, 0x07070707u, 0xbf810000u};
auto noStencilRequest = stencilRefExportRequest(0x52u, plain, noStencilExport);
noStencilRequest.layout.pushConstantSizeBytes = 0u;
const auto noStencil = ShaderRecompiler::Recompile(noStencilRequest);
Require(noStencil.stencilReferences.empty() && noStencil.stencilReferenceDword == 0xffffffffu && noStencil.pushConstants.empty(), "a stencil export flag without a remaining stencil output reserved replay state");
auto queue = stencilRefExportQueue(0x52u, 2u);
queue.context[0x000] = 0;
queue.context[0x002] = 0;
Expand Down
Loading
Loading