Skip to content
Closed
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 @@ -250,9 +250,10 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
if (program.binary.stage == Stage::Fragment || roles[i] == Role::GeometryBack) return;
decodeReads[i].clear();
vertexInfos[i] = Graphics::DecodeVertexStageInfo(program.binary.header, program.binary.headerAddress, program.userData, &decodeReads[i], false, 8u - program.firstUserSgpr);
if (vertexInfos[i]) vertexInfos[i]->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, readRegister(queue.context, 0x207), program.tailContinuation.get()) | graphics.layerExports;
if (vertexInfos[i]) {
vertexInfos[i]->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, readRegister(queue.context, 0x207), program.tailContinuation.get()) | graphics.layerExports;
vertexInfos[i]->depthRemapMode = graphics.depthRemap.mode;
Graphics::ApplyPointSize(graphics, *vertexInfos[i]);
}
};
if (!registerKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
#include <algorithm>
#include <bit>

namespace AgcDriver::DriverDetail {

Expand Down Expand Up @@ -51,6 +52,10 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
mix(vertex.fetchBufferReg);
mix(vertex.fetchEmbedded);
mix(vertex.paClVsOutCntl);
mix(vertex.pointList);
mix(std::bit_cast<std::uint32_t>(vertex.pointSize));
mix(std::bit_cast<std::uint32_t>(vertex.pointSizeMin));
mix(std::bit_cast<std::uint32_t>(vertex.pointSizeMax));
for (std::uint32_t r = 0; r < vertex.resourcesNum; ++r) {
for (const auto field : vertex.resources[r].fields) mix(field);
const auto& destination = vertex.resourcesDst[r];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ void Driver::traceDrawKeyLookup(const std::array<std::uint64_t, 5>& components,
}

bool Driver::sameVertexInfo(const ShaderRecompiler::ShaderVertexStageInfo& a, const ShaderRecompiler::ShaderVertexStageInfo& b) {
if (a.resourcesNum != b.resourcesNum || a.fetchAttribReg != b.fetchAttribReg || a.fetchBufferReg != b.fetchBufferReg || a.fetchEmbedded != b.fetchEmbedded || a.paClVsOutCntl != b.paClVsOutCntl) return false;
if (a.resourcesNum != b.resourcesNum || a.fetchAttribReg != b.fetchAttribReg || a.fetchBufferReg != b.fetchBufferReg || a.fetchEmbedded != b.fetchEmbedded || a.paClVsOutCntl != b.paClVsOutCntl || a.pointList != b.pointList || a.pointSize != b.pointSize || a.pointSizeMin != b.pointSizeMin || a.pointSizeMax != b.pointSizeMax) return false;
if (a.depthRemapMode != b.depthRemapMode) return false;
for (std::uint32_t i = 0; i < a.resourcesNum && i < a.resources.size(); ++i) {
if (a.resources[i].fields != b.resources[i].fields) return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,10 @@ std::vector<PreparedGraphicsStage> PrepareGraphicsStages(const DrawDecode& decod
prepared.push_back({program.snapshot, {program.codeOffset, nullptr}, program.binary.stage, offset, nullptr});
continue;
}
if (vertex) vertex->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, decoded.state.paClVsOutCntl, program.tailContinuation.get()) | decoded.state.layerExports;
if (vertex) {
vertex->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, decoded.state.paClVsOutCntl, program.tailContinuation.get()) | decoded.state.layerExports;
Graphics::ApplyPointSize(decoded.state, *vertex);
}
ShaderRecompiler::RecompileRequest request{program.binary, {wave, program.firstUserSgpr, program.userData, {}, fragment ? std::optional(decoded.pixel) : std::nullopt, vertex, memory, RegisteredFloatMode(*program.snapshot)}, target, {0, 0, offset, room}, ShaderRecompiler::GraphicsCompileContext{program.firstUserSgpr, linked, decoded.state.stages.mesh, decoded.state.stages.tessellation, {}}};
std::vector<std::uint64_t> key;
ShaderRecompiler::BuildPreparedShaderKey(request, key);
Expand Down
4 changes: 4 additions & 0 deletions core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ struct VulkanDevice::State {
bool fragmentShaderBarycentric = false;
bool shaderTerminateInvocation = false;
bool geometryShader = false;
bool largePoints = false;
bool sampleRateShading = false;
bool storageImageMultisample = false;
bool storageImageWriteWithoutFormat = false;
Expand Down Expand Up @@ -1718,6 +1719,8 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
enabled.sampleRateShading = available.sampleRateShading;
enabled.geometryShader = available.geometryShader;
state->geometryShader = enabled.geometryShader == VK_TRUE;
enabled.largePoints = available.largePoints;
state->largePoints = enabled.largePoints == VK_TRUE;
state->sampleRateShading = enabled.sampleRateShading == VK_TRUE;
if (enabled.sampleRateShading) state->capabilities.push_back(spv::CapabilityInterpolationFunction);
if (enabled.geometryShader) state->capabilities.push_back(spv::CapabilityGeometry);
Expand Down Expand Up @@ -3847,6 +3850,7 @@ Graphics::Context VulkanDevice::buildContext() const {
context.imageTableUpdateAfterBind = ImageTableUpdateAfterBind(context);
context.samplerTableUpdateAfterBind = SamplerTableUpdateAfterBind(context);
context.geometryShader = state->geometryShader;
context.largePoints = state->largePoints;
context.sampleRateShading = state->sampleRateShading;
context.fillModeNonSolid = state->fillModeNonSolid;
context.maintenance5 = state->maintenance5;
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/Context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ struct Context {
bool imageTableUpdateAfterBind = false;
bool samplerTableUpdateAfterBind = false;
bool geometryShader = false;
bool largePoints = false;
bool sampleRateShading = false;
bool fillModeNonSolid = false;
bool maintenance5 = false;
Expand Down
5 changes: 5 additions & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ struct State {
bool customSampleLocations = false;
bool sampleLocationGrid = false;
std::uint32_t paClVsOutCntl = 0;
bool vertexPoints = false;
float pointSize = 1.0f;
float pointSizeMin = 0.0f;
float pointSizeMax = 0.0f;
std::array<std::uint16_t, 4> quadSampleMask{0xffffu, 0xffffu, 0xffffu, 0xffffu};
bool pixelEarlyZ = false;
};
Expand All @@ -165,6 +169,7 @@ struct State {
inline constexpr std::uint32_t PositionExportLayoutBits = 0xffffu | (1u << 21u) | (1u << 22u) | (1u << 23u);

ShaderStages DecodeShaderStages(const QueueState& queue, bool vertexWorkgroup = false);
void ApplyPointSize(const State& state, ShaderRecompiler::ShaderVertexStageInfo& vertex);
State DecodeState(const QueueState& queue, bool vertexWorkgroup = false);
void ApplyDepthRemap(const Context& context, State& state);
void NormalizeUnusedViewportDepth(State& state, const ShaderRecompiler::ShaderPixelStageInfo& pixel);
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ bool ValidationKey(const Context& context, std::span<const CompiledShader> shade
add(context.viewportIndexLayer);
add(context.shaderTerminateInvocation);
add(state.paClVsOutCntl);
add(state.vertexPoints);
add(state.stages.mesh.has_value());
if (state.stages.mesh) {
const auto& mesh = *state.stages.mesh;
Expand Down
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
Require(!state.perSampleShading || context.sampleRateShading, "per-sample pixel shading requires the sampleRateShading device feature");
Require(!state.mergedCoverage || (context.mergedCoverageSampleCounts & state.samples) != 0, "an overrasterized draw (a multisampled rasterizer into one-sample color targets) requires VK_NV_framebuffer_mixed_samples with merged coverage reduction");
Require(!state.truncatedCoverage || (context.truncatedCoverageSampleCounts & state.samples) != 0, "one-sample color targets beside a multisampled depth target require VK_AMD_mixed_attachment_samples or VK_NV_framebuffer_mixed_samples with truncated coverage reduction");
Require(!state.vertexPoints || context.largePoints || (state.pointSize == 1.0f && ((state.paClVsOutCntl & (1u << 16u)) == 0 || (state.pointSizeMin == 1.0f && state.pointSizeMax == 1.0f))), "points of a size other than one pixel require the largePoints device feature");
Require(state.conservativeRasterization == VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT || context.conservativeRasterization, "conservative rasterization requires VK_EXT_conservative_rasterization with at most 1/256 pixel of overestimation and degenerate triangles rasterized");
ValidateProvokingVertex(context, state, shaders);
if (state.rectList) Require(context.tessellationShader && context.limits.maxTessellationPatchSize >= 4, "rect-list requires tessellation with four output control points");
Expand Down
16 changes: 14 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/PipelineJournal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static_assert(sizeof(VkStencilOpState) == 28, "VkStencilOpState changed: update
static_assert(sizeof(VkVertexInputBindingDescription) == 12, "VkVertexInputBindingDescription changed: update the recipe codec");
static_assert(sizeof(VkVertexInputAttributeDescription) == 16, "VkVertexInputAttributeDescription changed: update the recipe codec");
#if defined(__linux__) && defined(__x86_64__) && defined(__GLIBCXX__)
static_assert(sizeof(State) == 808, "State changed: update CanonicalPipelineState and the recipe codec");
static_assert(sizeof(State) == 824, "State changed: update CanonicalPipelineState and the recipe codec");
static_assert(sizeof(ShaderStages) == 112, "ShaderStages changed: update the recipe codec");
static_assert(sizeof(ShaderRecompiler::MeshConfiguration) == 40, "MeshConfiguration changed: update the recipe codec");
static_assert(sizeof(ShaderRecompiler::TessellationConfiguration) == 40, "TessellationConfiguration changed: update the recipe codec");
Expand All @@ -44,7 +44,7 @@ static_assert(sizeof(ShaderRecompiler::TessellationConfiguration) == 40, "Tessel
constexpr std::uint32_t FileMagic = 0x4c4a5041u;
// Bumped when the recipe codec, CanonicalPipelineState or the store key change in a way the
// layout guards above do not catch (a field renumbered or reinterpreted at the same size).
constexpr std::uint32_t FileFormat = 7u;
constexpr std::uint32_t FileFormat = 8u;
constexpr std::uint32_t ModuleRecord = 1u;
constexpr std::uint32_t GraphicsRecord = 2u;
constexpr std::uint32_t ComputeRecord = 3u;
Expand Down Expand Up @@ -220,6 +220,10 @@ void encodeState(Writer& writer, const State& state) {
writer.Bool(state.truncatedCoverage);
for (const auto mask : state.quadSampleMask) writer.Raw(mask);
writer.U32(state.depthRemap.mode);
writer.Bool(state.vertexPoints);
writer.Raw(state.pointSize);
writer.Raw(state.pointSizeMin);
writer.Raw(state.pointSizeMax);
}

void decodeState(Reader& reader, State& state) {
Expand Down Expand Up @@ -282,6 +286,10 @@ void decodeState(Reader& reader, State& state) {
state.truncatedCoverage = reader.Bool();
for (auto& mask : state.quadSampleMask) mask = reader.Raw<std::uint16_t>();
state.depthRemap.mode = reader.U32();
state.vertexPoints = reader.Bool();
state.pointSize = reader.Raw<float>();
state.pointSizeMin = reader.Raw<float>();
state.pointSizeMax = reader.Raw<float>();
}

void encodeRecipe(Writer& writer, const GraphicsPipelineRecipe& recipe) {
Expand Down Expand Up @@ -1056,6 +1064,10 @@ State CanonicalPipelineState(const State& state) {
canonical.truncatedCoverage = state.truncatedCoverage;
canonical.quadSampleMask = state.quadSampleMask;
canonical.depthRemap.mode = state.depthRemap.mode;
canonical.vertexPoints = state.vertexPoints;
canonical.pointSize = state.pointSize;
canonical.pointSizeMin = state.pointSizeMin;
canonical.pointSizeMax = state.pointSizeMax;
return canonical;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ struct Module {
bool layerOutput = false;
bool meshCapability = false;
std::uint32_t primitiveInputs = 0;
bool pointSizeOutput = false;
bool pointSize = false;
std::map<std::uint32_t, std::vector<std::uint32_t>> modes;

const std::vector<std::uint32_t>& Type(std::uint32_t id) const {
Expand Down Expand Up @@ -149,6 +151,10 @@ struct Module {
Require((value == spv::BuiltInVertexIndex || value == spv::BuiltInInstanceIndex || value == spv::BuiltInBaseInstance) && signature == "i32", "unsupported vertex built-in input");
} else if (vertex && storage == spv::StorageClassOutput) {
if (value == spv::BuiltInLayer && layerOutput && (signature == "u32" || signature == "i32")) return;
if (value == spv::BuiltInPointSize && pointSizeOutput && signature == "f32" && !pointSize) {
pointSize = true;
return;
}
Require(value == spv::BuiltInPosition && signature == "f32x4" && !position, "unsupported or duplicate vertex built-in output");
position = true;
} else {
Expand Down Expand Up @@ -186,6 +192,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi
Require(words[4] == 0, "unsupported SPIR-V schema: " + std::to_string(words[4]));

Module module;
module.pointSizeOutput = state.vertexPoints && stage == Stage::Vertex;
std::uint32_t entries = 0;
std::uint32_t memoryModels = 0;
std::uint32_t entryPoint = 0;
Expand Down
48 changes: 45 additions & 3 deletions core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,34 @@ std::uint32_t inactiveVertexPointSize(const QueueState& queue) {
}
}

bool vertexPointList(const QueueState& queue) {
const auto stages = find(queue.context, 0x2d5);
const auto primitive = find(queue.userConfig, 0x242, RegisterBank::UserConfig);
return stages != queue.context.end() && primitive != queue.userConfig.end() && (stages->second & 0x24u) == 0 && primitive->second == 1u;
}

void decodePointSize(const QueueState& queue, State& result) {
const auto& cx = queue.context;
const auto size = read(cx, 0x280);
const auto limits = read(cx, 0x281);
const bool fromVertex = (result.paClVsOutCntl & (1u << 16u)) != 0;
Require(!fromVertex || (result.paClVsOutCntl & (1u << 21u)) != 0, "USE_VTX_POINT_SIZE without VS_OUT_MISC_VEC_ENA is unsupported");
Require(fromVertex || (size & 0xffffu) == size >> 16u, "points whose PA_SU_POINT_SIZE width and height differ are unsupported");
Require(fromVertex || (size & 0xffffu) != 0, "points of size 0 (PA_SU_POINT_SIZE 0) are unsupported");
Require((limits & 0xffffu) <= limits >> 16u, "PA_SU_POINT_MINMAX with a minimum above its maximum is unsupported");
Require(!fromVertex || (limits >> 16u) != 0, "a vertex point size clamped to 0 (PA_SU_POINT_MINMAX maximum 0) is unsupported");
result.pointSize = static_cast<float>(size & 0xffffu) / 8.0f;
result.pointSizeMin = static_cast<float>(limits & 0xffffu) / 8.0f;
result.pointSizeMax = static_cast<float>(limits >> 16u) / 8.0f;
const auto interpolation = find(cx, 0x1b5);
const auto inputs = find(cx, 0x1b6);
if (interpolation == cx.end() || (interpolation->second & 2u) == 0 || inputs == cx.end()) return;
for (std::uint32_t input = 0; input < (inputs->second & 0x3fu); ++input) {
const auto control = find(cx, 0x191 + input);
Require(control == cx.end() || (control->second & 0x820000u) == 0, "point sprite texture coordinates (SPI_PS_INPUT_CNTL PT_SPRITE_TEX) are not implemented");
}
}

constexpr std::uint32_t DepthControlMask = ~0x007007f0u;
// EXEC_ON_HIER_FAIL / EXEC_ON_NOOP / EXEC_IF_OVERLAPPED (bits 9, 10, 17) only force the pixel shader
// to run, which it always does here.
Expand Down Expand Up @@ -1082,6 +1110,15 @@ std::array<std::uint8_t, 32> PixelSampleLocations(const State& state, const Shad
return locations;
}

void ApplyPointSize(const State& state, ShaderRecompiler::ShaderVertexStageInfo& vertex) {
if (!state.vertexPoints) return;
vertex.paClVsOutCntl |= state.paClVsOutCntl & (1u << 16u);
vertex.pointList = true;
vertex.pointSize = state.pointSize;
vertex.pointSizeMin = state.pointSizeMin;
vertex.pointSizeMax = state.pointSizeMax;
}

ShaderStages DecodeShaderStages(const QueueState& queue, bool vertexWorkgroup) {
const auto value = read(queue.context, 0x2d5);
const auto validate = [&](bool condition, const char* reason) {
Expand Down Expand Up @@ -1256,7 +1293,11 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
const auto primitive = read(queue.userConfig, 0x242, RegisterBank::UserConfig);
APS5_LOG_OUT_DEBUG("DecodeState primitive=%u path=%u vertexWave=%u", primitive, static_cast<unsigned>(result.stages.path), result.stages.vertexWaveSize);
switch (primitive) {
case 1: Require(result.stages.mesh.has_value(), "point-list vertex rendering requires point-size output support"); result.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; break;
case 1:
Require(result.stages.mesh.has_value() || result.stages.path == ShaderPath::Vertex, "point lists are only drawn through the vertex and geometry paths");
result.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
result.vertexPoints = result.stages.path == ShaderPath::Vertex;
break;
case 2: result.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; break;
case 3: result.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; break;
case 7:
Expand All @@ -1281,9 +1322,10 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
}
APS5_LOG_OUT_DEBUG("Topology=%u", static_cast<unsigned>(result.topology));
result.primitiveRestart = read(queue.userConfig, 0x24b, RegisterBank::UserConfig) != 0 && !result.rectList && !result.quadList && result.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
zero(cx, 0x207, ~(LayerExports | ClipCullExports | inactiveVertexPointSize(queue)), "layer, viewport or auxiliary vertex exports");
zero(cx, 0x207, ~(LayerExports | ClipCullExports | (result.vertexPoints ? 1u << 16u : inactiveVertexPointSize(queue))), "layer, viewport or auxiliary vertex exports");
Require(std::popcount(read(cx, 0x207) & 0xffffu) <= 8, "more than eight clip and cull distances are unsupported");
result.paClVsOutCntl = read(cx, 0x207);
if (result.vertexPoints) decodePointSize(queue, result);
result.samples = decodeSamples(cx);
Require(coveredCentroidSupported(queue), "COVERED_CENTROID_IS_CENTER with active or unspecified centroid inputs is not implemented");
decodeSampleLocations(cx, result);
Expand Down Expand Up @@ -2053,7 +2095,7 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
if (value(queue.userConfig, 0x242, primitive) && (primitive & 0x3fu) != 1 && (primitive & 0x3fu) != 2 && (primitive & 0x3fu) != 3 && (primitive & 0x3fu) != 4 && (primitive & 0x3fu) != 5 && (primitive & 0x3fu) != 6 && (primitive & 0x3fu) != 21) return "AGC graphics: primitive restart is only supported for point, line and triangle topologies";
if (value(cx, 0x103, resetIndex) && (resetIndex & 0xffffu) != 0xffffu) return "AGC graphics: primitive restart index other than all ones is unsupported";
}
if (auto reason = nonzero(cx, 0x207, ~(LayerExports | ClipCullExports | inactiveVertexPointSize(queue)), "layer, viewport or auxiliary vertex exports"); !reason.empty()) return reason;
if (auto reason = nonzero(cx, 0x207, ~(LayerExports | ClipCullExports | (vertexPointList(queue) ? 1u << 16u : inactiveVertexPointSize(queue))), "layer, viewport or auxiliary vertex exports"); !reason.empty()) return reason;
if (value(cx, 0x207, word) && std::popcount(word & 0xffffu) > 8) return require(false, "more than eight clip and cull distances are unsupported");
if (value(cx, 0x200, word)) {
const auto renderControl = find(cx, 0x000);
Expand Down
Loading
Loading