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
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ bool Driver::sameDecode(const DrawDecode& a, const DrawDecode& b) {
if (x.binary.stage != y.binary.stage || x.binary.codeAddress != y.binary.codeAddress || x.userDataBase != y.userDataBase || x.firstUserSgpr != y.firstUserSgpr || x.userData != y.userData || x.snapshot != y.snapshot || x.codeOffset != y.codeOffset || x.tailContinuation != y.tailContinuation) return false;
}
if (p.targetExportPacking != q.targetExportPacking || p.dualSourceBlend != q.dualSourceBlend || p.reversedBlend != q.reversedBlend || p.alphaToCoverage != q.alphaToCoverage || p.rasterPrimitive != q.rasterPrimitive || p.ditheredAlphaToCoverage != q.ditheredAlphaToCoverage || p.quadPixelMask != q.quadPixelMask || p.quadSampleMask != q.quadSampleMask || p.iteratesSamples != q.iteratesSamples || p.positionLocation != q.positionLocation || p.sampleLocations != q.sampleLocations) return false;
if (s.samples != t.samples || s.quadSampleMask != t.quadSampleMask || s.pixelEarlyZ != t.pixelEarlyZ) return false;
if (s.samples != t.samples || s.mergedCoverage != t.mergedCoverage || s.quadSampleMask != t.quadSampleMask || s.pixelEarlyZ != t.pixelEarlyZ) return false;
return true;
}

Expand Down
27 changes: 27 additions & 0 deletions core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ struct VulkanDevice::State {
bool textureCompressionBC = false;
bool samplerFilterMinmax = false;
bool nonSeamlessCubeMap = false;
VkSampleCountFlags mergedCoverageSampleCounts = 0;
bool fragmentShaderPixelInterlock = false;
bool conservativeRasterization = false;
bool provokingVertexLast = false;
Expand Down Expand Up @@ -1440,6 +1441,27 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
}
nonSeamlessCubeFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT};
nonSeamlessCubeFeatures.nonSeamlessCubeMap = VK_TRUE;
VkPhysicalDeviceCoverageReductionModeFeaturesNV coverageReductionFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV};
if (hasExtension(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME) && hasExtension(VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME)) {
VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &coverageReductionFeatures};
state->InstanceFunction<PFN_vkGetPhysicalDeviceFeatures2>("vkGetPhysicalDeviceFeatures2")(selected, &features);
if (coverageReductionFeatures.coverageReductionMode == VK_TRUE) {
const auto combinations = state->InstanceFunction<PFN_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV>("vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV");
std::uint32_t count = 0;
check(combinations(selected, &count, nullptr), "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV");
std::vector<VkFramebufferMixedSamplesCombinationNV> supported(count, {VK_STRUCTURE_TYPE_FRAMEBUFFER_MIXED_SAMPLES_COMBINATION_NV});
check(combinations(selected, &count, supported.data()), "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV");
for (const auto& combination : supported) {
if (combination.coverageReductionMode == VK_COVERAGE_REDUCTION_MODE_MERGE_NV && combination.colorSamples == VK_SAMPLE_COUNT_1_BIT && combination.depthStencilSamples == 0) state->mergedCoverageSampleCounts |= combination.rasterizationSamples;
}
}
if (state->mergedCoverageSampleCounts != 0) {
deviceExtensions.push_back(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME);
deviceExtensions.push_back(VK_NV_COVERAGE_REDUCTION_MODE_EXTENSION_NAME);
}
}
coverageReductionFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV};
coverageReductionFeatures.coverageReductionMode = VK_TRUE;
VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT libraryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT};
VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamicStateFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT};
VkPhysicalDeviceDynamicRenderingFeaturesKHR renderingFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR};
Expand Down Expand Up @@ -1707,6 +1729,10 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
nonSeamlessCubeFeatures.pNext = const_cast<void*>(deviceInfo.pNext);
deviceInfo.pNext = &nonSeamlessCubeFeatures;
}
if (state->mergedCoverageSampleCounts != 0) {
coverageReductionFeatures.pNext = const_cast<void*>(deviceInfo.pNext);
deviceInfo.pNext = &coverageReductionFeatures;
}
byteFeatures.pNext = const_cast<void*>(deviceInfo.pNext);
if (state->fragmentShaderBarycentric) {
barycentricFeatures.pNext = byteFeatures.pNext;
Expand Down Expand Up @@ -3625,6 +3651,7 @@ Graphics::Context VulkanDevice::buildContext() const {
context.depthBiasClamp = state->depthBiasClamp;
context.samplerFilterMinmax = state->samplerFilterMinmax;
context.nonSeamlessCubeMap = state->nonSeamlessCubeMap;
context.mergedCoverageSampleCounts = state->mergedCoverageSampleCounts;
context.conservativeRasterization = state->conservativeRasterization;
context.meshWave32 = state->meshWave32;
context.provokingVertexLast = state->provokingVertexLast;
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 @@ -193,6 +193,7 @@ struct Context {
bool dualSrcBlend = false;
bool samplerFilterMinmax = false;
bool nonSeamlessCubeMap = false;
VkSampleCountFlags mergedCoverageSampleCounts = 0;
bool conservativeRasterization = false;
bool meshWave32 = false;
VkBuffer emptyBuffer = VK_NULL_HANDLE;
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 @@ -128,6 +128,7 @@ struct State {
bool alphaToCoverage = false;
bool ditheredAlphaToCoverage = false;
bool perSampleShading = false;
bool mergedCoverage = false;
VkConservativeRasterizationModeEXT conservativeRasterization = VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
VkRect2D scissor;
VkCullModeFlags cullMode;
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 @@ -51,6 +51,7 @@ std::uint64_t DrawRenderPassKey(const Context& context, const State& state, std:
mix(state.renderExtent.width);
mix(state.renderExtent.height);
mix(state.samples);
mix(state.mergedCoverage);
mix(state.customSampleLocations);
if (state.customSampleLocations) {
mix(state.sampleLocationGrid);
Expand Down
17 changes: 16 additions & 1 deletion core/libs/prx/libSceAgcDriver/Graphics/src/Pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ bool libraryKeys(PipelineLibraryKeys& keys, const Context& context, const State&
appendKey(keys.fragmentOutput, state.samples);
appendKey(keys.fragmentShader, state.perSampleShading);
appendKey(keys.fragmentOutput, state.perSampleShading);
appendKey(keys.fragmentShader, state.mergedCoverage);
appendKey(keys.fragmentOutput, state.mergedCoverage);
const auto sampleLocationsEnabled = ValidateSampleLocations(context, state);
appendKey(keys.fragmentShader, sampleLocationsEnabled);
appendKey(keys.fragmentOutput, sampleLocationsEnabled);
Expand Down Expand Up @@ -314,6 +316,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
Require(state.reversedBlend == 0 || (context.dualSrcBlend && state.blends.size() <= context.limits.maxFragmentDualSrcAttachments), "blending into a color target with a reversed component order through a second source color needs dual-source blending, which the device does not support");
Require(!state.negativeOneToOne || context.depthClipControl, "negative-one-to-one depth clipping requires VK_EXT_depth_clip_control with depthClipControl enabled");
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.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 Expand Up @@ -379,7 +382,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
for (std::uint32_t index = 0; index < state.colors.size(); ++index) {
VkAttachmentDescription color{};
color.format = state.colors[index].format;
color.samples = static_cast<VkSampleCountFlagBits>(state.samples);
color.samples = state.mergedCoverage ? VK_SAMPLE_COUNT_1_BIT : static_cast<VkSampleCountFlagBits>(state.samples);
color.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
color.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
color.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
Expand Down Expand Up @@ -412,6 +415,11 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
VkPipelineRenderingCreateInfoKHR rendering{VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR};
rendering.colorAttachmentCount = static_cast<std::uint32_t>(renderingColors.size());
rendering.pColorAttachmentFormats = renderingColors.empty() ? nullptr : renderingColors.data();
const std::vector<VkSampleCountFlagBits> mergedColorSamples(renderingColors.size(), VK_SAMPLE_COUNT_1_BIT);
VkAttachmentSampleCountInfoNV attachmentSamples{VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV};
attachmentSamples.colorAttachmentCount = static_cast<std::uint32_t>(mergedColorSamples.size());
attachmentSamples.pColorAttachmentSamples = mergedColorSamples.empty() ? nullptr : mergedColorSamples.data();
if (state.mergedCoverage) rendering.pNext = &attachmentSamples;
if (state.depth) {
rendering.depthAttachmentFormat = HostDepthFormat(context, state.depth->format);
if (HasStencil(state.depth->format)) rendering.stencilAttachmentFormat = rendering.depthAttachmentFormat;
Expand Down Expand Up @@ -482,6 +490,12 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
const auto grid = SampleLocationGrid(state);
sampleLocations.sampleLocationsInfo = {VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT, nullptr, samples.rasterizationSamples, grid, state.samples * grid.width * grid.height, locations.data()};
if (sampleLocationsEnabled) samples.pNext = &sampleLocations;
VkPipelineCoverageReductionStateCreateInfoNV coverageReduction{VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_REDUCTION_STATE_CREATE_INFO_NV};
coverageReduction.coverageReductionMode = VK_COVERAGE_REDUCTION_MODE_MERGE_NV;
if (state.mergedCoverage) {
coverageReduction.pNext = samples.pNext;
samples.pNext = &coverageReduction;
}
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
depthStencil.depthTestEnable = state.depthTest;
depthStencil.depthWriteEnable = state.depthWrite;
Expand Down Expand Up @@ -851,6 +865,7 @@ void pipelineKey(std::vector<std::byte>& key, const Context& context, const Stat
for (const auto value : state.blendConstants) append(key, value);
append(key, state.samples);
append(key, state.perSampleShading);
append(key, state.mergedCoverage);
append(key, state.customSampleLocations);
if (state.customSampleLocations) {
append(key, state.sampleLocationGrid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 3u;
constexpr std::uint32_t FileFormat = 4u;
constexpr std::uint32_t ModuleRecord = 1u;
constexpr std::uint32_t GraphicsRecord = 2u;
constexpr std::uint32_t ComputeRecord = 3u;
Expand Down Expand Up @@ -215,6 +215,7 @@ void encodeState(Writer& writer, const State& state) {
writer.Bool(state.customSampleLocations);
writer.Bool(state.sampleLocationGrid);
writer.Bool(state.perSampleShading);
writer.Bool(state.mergedCoverage);
for (const auto mask : state.quadSampleMask) writer.Raw(mask);
}

Expand Down Expand Up @@ -273,6 +274,7 @@ void decodeState(Reader& reader, State& state) {
state.customSampleLocations = reader.Bool();
state.sampleLocationGrid = reader.Bool();
state.perSampleShading = reader.Bool();
state.mergedCoverage = reader.Bool();
for (auto& mask : state.quadSampleMask) mask = reader.Raw<std::uint16_t>();
}

Expand Down Expand Up @@ -1036,6 +1038,7 @@ State CanonicalPipelineState(const State& state) {
canonical.customSampleLocations = state.customSampleLocations;
canonical.sampleLocationGrid = state.sampleLocationGrid;
canonical.perSampleShading = state.perSampleShading;
canonical.mergedCoverage = state.mergedCoverage;
canonical.quadSampleMask = state.quadSampleMask;
return canonical;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ ShaderRecompiler::ShaderPixelStageInfo DecodePixelStageInfo(const Registers& con
constexpr std::uint32_t knownMask = PixelInputBit(PixelInput::PerspectiveSample) | PixelInputBit(PixelInput::PerspectiveCenter) | PixelInputBit(PixelInput::PerspectiveCentroid) |
PixelInputBit(PixelInput::LinearSample) | PixelInputBit(PixelInput::LinearCenter) | PixelInputBit(PixelInput::LinearCentroid) |
PixelInputBit(PixelInput::PositionX) | PixelInputBit(PixelInput::PositionY) | PixelInputBit(PixelInput::PositionZ) | PixelInputBit(PixelInput::PositionW) |
PixelInputBit(PixelInput::FrontFace) | PixelInputBit(PixelInput::Ancillary) | PixelInputBit(PixelInput::LineStipple) | PixelInputBit(PixelInput::PositionFixedPoint);
PixelInputBit(PixelInput::FrontFace) | PixelInputBit(PixelInput::Ancillary) | PixelInputBit(PixelInput::SampleCoverage) | PixelInputBit(PixelInput::LineStipple) | PixelInputBit(PixelInput::PositionFixedPoint);
if ((activeInputs & ~knownMask) != 0) {
char message[128];
std::snprintf(message, sizeof(message), "AGC graphics: unsupported SPI_PS_INPUT_ENA/ADDR bit combination (ena 0x%x addr 0x%x)", ena, addr);
Expand Down
24 changes: 22 additions & 2 deletions core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ bool ditheredAlphaLocationsSupported(const Registers& cx) {
constexpr std::uint32_t ScanModeMask = ~0x22u;
constexpr std::uint32_t ScanControlMask = ~0x76033fffu;
constexpr std::uint32_t PixelShaderIteratesSamples = 0x10000u;
constexpr std::uint32_t PixelSampleCoverageInput = 0x4000u;
constexpr std::uint32_t PixelSampleRateInputs = 0x2011u;
constexpr std::uint32_t ScreenOffsetMask = ~0x01ff01ffu;
// Bits 26/27 (ZCLIP_NEAR/FAR_DISABLE) become depth clamping; bit 19 selects the [0, 1] clip space.
constexpr std::uint32_t ClipControlMask = ~(0x80000u | 0x01000000u | 0x0c000000u);
Expand Down Expand Up @@ -461,6 +463,21 @@ constexpr std::uint32_t CoveredCentroidIsCenter = 1u << 29u;
constexpr std::uint32_t SampleZeroRefusedInputs = ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::PerspectiveCentroid) | ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::LinearCentroid) | ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::SampleCoverage);
constexpr std::uint32_t CentroidInputs = ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::PerspectiveCentroid) | ShaderRecompiler::PixelInputBit(ShaderRecompiler::PixelInput::LinearCentroid);

bool overrasterized(const Registers& cx, std::uint32_t samples) {
const auto eqaa = find(cx, 0x201);
const auto mode = find(cx, 0x292);
return samples > 1u && eqaa != cx.end() && mode != cx.end() && (mode->second & 1u) != 0 && ((eqaa->second >> 24u) & 7u) == static_cast<std::uint32_t>(std::countr_zero(samples));
}

bool sampleCoverageSupported(const QueueState& queue, std::uint32_t samples, bool perSampleShading) {
if (samples == 1u || PixelProgramSkipped(queue)) return true;
const auto ena = find(queue.context, 0x1b3);
const auto addr = find(queue.context, 0x1b4);
if (ena == queue.context.end() || addr == queue.context.end()) return true;
const auto inputs = ena->second & addr->second;
return (inputs & PixelSampleCoverageInput) == 0u || (!perSampleShading && (inputs & PixelSampleRateInputs) == 0u);
}

bool coveredCentroidSupported(const QueueState& queue) {
const auto config = find(queue.context, 0x2f8);
if (config == queue.context.end() || (config->second & CoveredCentroidIsCenter) == 0 || PixelProgramSkipped(queue)) return true;
Expand Down Expand Up @@ -1157,6 +1174,7 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
}
zero(cx, 0x293, ScanControlMask, "primitive discard or out-of-order rasterization");
result.perSampleShading = result.samples > 1 && (read(cx, 0x293) & PixelShaderIteratesSamples) != 0;
Require(sampleCoverageSupported(queue, result.samples, result.perSampleShading), "SAMPLE_COVERAGE in a multisampled pixel shader that runs per sample, or reads sample-rate or ancillary inputs, is unsupported (the input holds the whole pixel's coverage, gl_SampleMaskIn only the invocation's samples)");
if (depthKeepsSampleZero && result.samples > 1) {
Require(rasterizesSampleZeroOnly(cx, result), "the depth target's sample count differs from the rasterizer's");
rasterizeSampleZero(result);
Expand Down Expand Up @@ -1241,8 +1259,10 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
result.customSampleLocations = true;
result.sampleLocations.fill(0);
}
if (color.samples == 1 && result.colors.empty() && !result.depth && rasterizesSampleZeroOnly(cx, result)) rasterizeSampleZero(result);
Require(color.samples == result.samples, "a color target's sample count differs from the rasterizer's");
const bool merged = color.samples == 1u && !result.depth && !result.perSampleShading && (result.colors.empty() || result.mergedCoverage) && overrasterized(cx, result.samples);
if (!merged && color.samples == 1 && result.colors.empty() && !result.depth && rasterizesSampleZeroOnly(cx, result)) rasterizeSampleZero(result);
Require((color.samples == result.samples && !result.mergedCoverage) || merged, "a color target's sample count differs from the rasterizer's");
result.mergedCoverage = merged;
APS5_LOG_OUT_DEBUG("Color %u address=0x%llx extent=%ux%u bytes=%llu VkFormat=%u", slot, static_cast<unsigned long long>(color.address), color.extent.width, color.extent.height, static_cast<unsigned long long>(color.bytes), static_cast<unsigned>(color.format));
if (result.colors.empty()) {
result.renderExtent = color.extent;
Expand Down
Loading
Loading