mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
shader: add viewport-index exports and indexed raster state
Co-authored-by: Ettore Sartori <85788613+Ekt0re@users.noreply.github.com>
This commit is contained in:
@@ -939,7 +939,8 @@ static bool ScissorClipRuleToIntersectionMask(uint16_t rule, uint8_t* mask) {
|
||||
}
|
||||
|
||||
ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc,
|
||||
vk::Extent2D extent) {
|
||||
vk::Extent2D extent, uint32_t viewport_index) {
|
||||
EXIT_IF(viewport_index >= std::size(vp.viewports));
|
||||
ScissorRect screen {vp.screen_scissor_left, vp.screen_scissor_top, vp.screen_scissor_right,
|
||||
vp.screen_scissor_bottom};
|
||||
ScissorRect final = screen;
|
||||
@@ -972,7 +973,7 @@ ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeC
|
||||
final = ScissorRectIntersect(final, generic);
|
||||
}
|
||||
|
||||
const auto& viewport = vp.viewports[0];
|
||||
const auto& viewport = vp.viewports[viewport_index];
|
||||
ScissorRect viewport_scissor {viewport.viewport_scissor_left, viewport.viewport_scissor_top,
|
||||
viewport.viewport_scissor_right,
|
||||
viewport.viewport_scissor_bottom};
|
||||
|
||||
@@ -39,7 +39,7 @@ void hw_print(const CommandBuffer& buffer);
|
||||
void hw_check(const CommandBuffer& buffer);
|
||||
void LogDrawPhase(const char* draw_name, const char* phase);
|
||||
ScissorRect calc_final_scissor(const HW::ScreenViewport& vp, const HW::ScanModeControl& smc,
|
||||
vk::Extent2D extent);
|
||||
vk::Extent2D extent, uint32_t viewport_index);
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
|
||||
@@ -573,9 +573,7 @@ void CreatePipelineInternal(
|
||||
depth_clip_control.negativeOneToOne = (static_params.negative_one_to_one ? VK_TRUE : VK_FALSE);
|
||||
|
||||
vk::PipelineViewportStateCreateInfo viewport_state {};
|
||||
viewport_state.pNext = &depth_clip_control;
|
||||
viewport_state.viewportCount = 1;
|
||||
viewport_state.scissorCount = 1;
|
||||
viewport_state.pNext = &depth_clip_control;
|
||||
|
||||
vk::CullModeFlags cull_mode = vk::CullModeFlagBits::eNone;
|
||||
if (static_params.cull_back) {
|
||||
@@ -704,8 +702,8 @@ void CreatePipelineInternal(
|
||||
depth_stencil_info.maxDepthBounds = static_params.depth_max_bounds;
|
||||
|
||||
const vk::DynamicState dynamic_states[] = {
|
||||
vk::DynamicState::eViewport,
|
||||
vk::DynamicState::eScissor,
|
||||
vk::DynamicState::eViewportWithCount,
|
||||
vk::DynamicState::eScissorWithCount,
|
||||
vk::DynamicState::eLineWidth,
|
||||
vk::DynamicState::eDepthTestEnable,
|
||||
vk::DynamicState::eDepthWriteEnable,
|
||||
|
||||
@@ -210,7 +210,7 @@ static void LogDrawTargetState(const char* draw_name, const RenderColorInfo& col
|
||||
});
|
||||
|
||||
const auto extent = color.Extent();
|
||||
const auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent);
|
||||
const auto sc = calc_final_scissor(vp, ctx.GetScanModeControl(), extent, 0);
|
||||
|
||||
LOGF(
|
||||
"DrawTargetState[%u]: frame=%d %s target=%s addr=0x%010" PRIx64
|
||||
@@ -315,6 +315,7 @@ static void LogDrawInputState(const CommandBuffer& buffer, const RenderColorInfo
|
||||
}
|
||||
|
||||
static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuffer vk_buffer,
|
||||
const ShaderVertexInputInfo& vs_input_info,
|
||||
const RenderColorInfo* colors, uint32_t color_count,
|
||||
const RenderDepthInfo& depth) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
@@ -333,31 +334,46 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
|
||||
framebuffer_extent = {limits.maxFramebufferWidth, limits.maxFramebufferHeight};
|
||||
}
|
||||
|
||||
const auto final_scissor = calc_final_scissor(vp, ctx.GetScanModeControl(), framebuffer_extent);
|
||||
const auto& outputs = vs_input_info.stage.program->info.outputs;
|
||||
const bool indexed_viewports =
|
||||
std::any_of(outputs.begin(), outputs.end(), [](const auto& output) {
|
||||
return output.kind == ShaderRecompiler::IR::StageOutputKind::ViewportIndex;
|
||||
});
|
||||
constexpr uint32_t viewport_slots = std::size(HW::ScreenViewport {}.viewports);
|
||||
std::array<vk::Viewport, viewport_slots> viewports {};
|
||||
std::array<vk::Rect2D, viewport_slots> scissors {};
|
||||
const uint32_t viewport_count = indexed_viewports ? viewport_slots : 1;
|
||||
for (uint32_t i = 0; i < viewport_count; i++) {
|
||||
const auto& guest = vp.viewports[i];
|
||||
auto& viewport = viewports[i];
|
||||
if (ctx.GetClipControl().clip_disable) {
|
||||
const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits;
|
||||
viewport.width = static_cast<float>(std::min(limits.maxViewportDimensions[0], 16384u));
|
||||
viewport.height = static_cast<float>(std::min(limits.maxViewportDimensions[1], 16384u));
|
||||
} else {
|
||||
viewport.x = guest.xoffset - guest.xscale;
|
||||
viewport.y = guest.yoffset - guest.yscale;
|
||||
viewport.width = guest.xscale * 2.0f;
|
||||
viewport.height = guest.yscale * 2.0f;
|
||||
}
|
||||
viewport.minDepth =
|
||||
guest.zoffset - (ctx.GetClipControl().dx_clip_space ? 0.0f : guest.zscale);
|
||||
viewport.maxDepth = guest.zscale + guest.zoffset;
|
||||
|
||||
vk::Viewport viewport {};
|
||||
if (ctx.GetClipControl().clip_disable) {
|
||||
const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(std::min(limits.maxViewportDimensions[0], 16384u));
|
||||
viewport.height = static_cast<float>(std::min(limits.maxViewportDimensions[1], 16384u));
|
||||
} else {
|
||||
viewport.x = vp.viewports[0].xoffset - vp.viewports[0].xscale;
|
||||
viewport.y = vp.viewports[0].yoffset - vp.viewports[0].yscale;
|
||||
viewport.width = vp.viewports[0].xscale * 2.0f;
|
||||
viewport.height = vp.viewports[0].yscale * 2.0f;
|
||||
const auto final_scissor =
|
||||
calc_final_scissor(vp, ctx.GetScanModeControl(), framebuffer_extent, i);
|
||||
auto& scissor = scissors[i];
|
||||
scissor.offset = {final_scissor.left, final_scissor.top};
|
||||
scissor.extent = {static_cast<uint32_t>(final_scissor.right - final_scissor.left),
|
||||
static_cast<uint32_t>(final_scissor.bottom - final_scissor.top)};
|
||||
if (viewport.width == 0.0f) {
|
||||
// Keep empty slots at their guest index; Vulkan requires a positive viewport width.
|
||||
viewport.width = 1.0f;
|
||||
scissor.extent = {0, 0};
|
||||
}
|
||||
}
|
||||
viewport.minDepth = vp.viewports[0].zoffset -
|
||||
(ctx.GetClipControl().dx_clip_space ? 0.0f : vp.viewports[0].zscale);
|
||||
viewport.maxDepth = vp.viewports[0].zscale + vp.viewports[0].zoffset;
|
||||
vk_buffer.setViewport(0, 1, &viewport);
|
||||
|
||||
vk::Rect2D scissor {};
|
||||
scissor.offset = {final_scissor.left, final_scissor.top};
|
||||
scissor.extent = {static_cast<uint32_t>(final_scissor.right - final_scissor.left),
|
||||
static_cast<uint32_t>(final_scissor.bottom - final_scissor.top)};
|
||||
vk_buffer.setScissor(0, 1, &scissor);
|
||||
vk_buffer.setViewportWithCount(viewport_count, viewports.data());
|
||||
vk_buffer.setScissorWithCount(viewport_count, scissors.data());
|
||||
|
||||
float line_width = ctx.GetLineWidth();
|
||||
if (line_width != 1.0f) {
|
||||
@@ -1125,8 +1141,8 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
|
||||
CommitIndexBuffer(vk_buffer, index_binding);
|
||||
}
|
||||
|
||||
SetGraphicsDynamicParams(buffer, vk_buffer, state.color_info, state.color_count,
|
||||
state.depth_info);
|
||||
SetGraphicsDynamicParams(buffer, vk_buffer, state.vs_input_info, state.color_info,
|
||||
state.color_count, state.depth_info);
|
||||
|
||||
LogDrawPhase(draw.name, "BeginRendering");
|
||||
if (set_auto_debug) {
|
||||
|
||||
@@ -65,12 +65,13 @@ struct VulkanExtensions {
|
||||
|
||||
vk::PhysicalDeviceVulkan12Features WindowContext::RequiredVulkan12Features() noexcept {
|
||||
vk::PhysicalDeviceVulkan12Features features {};
|
||||
features.sType = vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
features.samplerMirrorClampToEdge = VK_TRUE;
|
||||
features.timelineSemaphore = VK_TRUE;
|
||||
features.shaderOutputLayer = VK_TRUE;
|
||||
features.bufferDeviceAddress = VK_TRUE;
|
||||
features.shaderBufferInt64Atomics = VK_TRUE;
|
||||
features.sType = vk::StructureType::ePhysicalDeviceVulkan12Features;
|
||||
features.samplerMirrorClampToEdge = VK_TRUE;
|
||||
features.timelineSemaphore = VK_TRUE;
|
||||
features.shaderOutputLayer = VK_TRUE;
|
||||
features.shaderOutputViewportIndex = VK_TRUE;
|
||||
features.bufferDeviceAddress = VK_TRUE;
|
||||
features.shaderBufferInt64Atomics = VK_TRUE;
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -276,6 +277,11 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
||||
LOGF("shaderOutputLayer is not supported\n");
|
||||
skip_device = true;
|
||||
}
|
||||
if (required_features12.shaderOutputViewportIndex == VK_TRUE &&
|
||||
features12.shaderOutputViewportIndex != VK_TRUE) {
|
||||
LOGF("shaderOutputViewportIndex is not supported\n");
|
||||
skip_device = true;
|
||||
}
|
||||
if (required_features12.bufferDeviceAddress == VK_TRUE &&
|
||||
features12.bufferDeviceAddress != VK_TRUE) {
|
||||
LOGF("bufferDeviceAddress is not supported\n");
|
||||
@@ -320,6 +326,10 @@ static void VulkanFindPhysicalDevice(vk::Instance instance, vk::SurfaceKHR surfa
|
||||
LOGF("largePoints is not supported\n");
|
||||
skip_device = true;
|
||||
}
|
||||
if (device_features2.features.multiViewport != VK_TRUE) {
|
||||
LOGF("multiViewport is not supported\n");
|
||||
skip_device = true;
|
||||
}
|
||||
if (device_features2.features.fragmentStoresAndAtomics != VK_TRUE) {
|
||||
LOGF("fragmentStoresAndAtomics is not supported\n");
|
||||
skip_device = true;
|
||||
@@ -636,10 +646,13 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderClipDistance != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderCullDistance != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.largePoints != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.multiViewport != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.shaderInt64 != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(supported_features2.features.vertexPipelineStoresAndAtomics != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(required_features12.shaderOutputLayer == VK_TRUE &&
|
||||
supported_features12.shaderOutputLayer != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(required_features12.shaderOutputViewportIndex == VK_TRUE &&
|
||||
supported_features12.shaderOutputViewportIndex != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(required_features12.bufferDeviceAddress == VK_TRUE &&
|
||||
supported_features12.bufferDeviceAddress != VK_TRUE);
|
||||
EXIT_NOT_IMPLEMENTED(required_features12.shaderBufferInt64Atomics == VK_TRUE &&
|
||||
@@ -663,6 +676,7 @@ static vk::Device VulkanCreateDevice(vk::PhysicalDevice physical_device, const V
|
||||
device_features.shaderClipDistance = VK_TRUE;
|
||||
device_features.shaderCullDistance = VK_TRUE;
|
||||
device_features.largePoints = VK_TRUE;
|
||||
device_features.multiViewport = VK_TRUE;
|
||||
device_features.vertexPipelineStoresAndAtomics = VK_TRUE;
|
||||
graphics.sample_rate_shading_enabled = true;
|
||||
device_features.shaderInt64 = VK_TRUE;
|
||||
|
||||
@@ -338,15 +338,24 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
|
||||
}
|
||||
const auto output = IR::DecodePositionExportComponent(
|
||||
state.input_info.vertex->pa_cl_vs_out_cntl, exp.index, component);
|
||||
if (output.layer) {
|
||||
const auto raw = ExportRawComponent(ctx, data, component);
|
||||
const auto layer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), layer, raw,
|
||||
ConstantU32(state, 0x7ffu)});
|
||||
const auto pointer = state.stage == ShaderType::Mesh
|
||||
? MeshOutputPointer(state, IR::StageOutputKind::Layer)
|
||||
: state.layer_variable;
|
||||
state.builder.AddFunction({OpStore, pointer, layer});
|
||||
if (output.layer || output.viewport) {
|
||||
const auto raw = ExportRawComponent(ctx, data, component);
|
||||
if (output.layer) {
|
||||
const auto layer = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitwiseAnd, TypeU32(state), layer, raw,
|
||||
ConstantU32(state, 0x7ffu)});
|
||||
const auto pointer = state.stage == ShaderType::Mesh
|
||||
? MeshOutputPointer(state, IR::StageOutputKind::Layer)
|
||||
: state.layer_variable;
|
||||
state.builder.AddFunction({OpStore, pointer, layer});
|
||||
}
|
||||
if (output.viewport) {
|
||||
// GFX10 MISC.z packs the viewport index in bits 16..19 alongside the layer.
|
||||
const auto viewport = state.builder.AllocateId();
|
||||
state.builder.AddFunction({OpBitFieldUExtract, TypeU32(state), viewport, raw,
|
||||
ConstantU32(state, 16), ConstantU32(state, 4)});
|
||||
state.builder.AddFunction({OpStore, state.viewport_index_variable, viewport});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!output.point_size && output.clip_distance == UINT32_MAX &&
|
||||
|
||||
@@ -52,6 +52,7 @@ enum : uint32_t {
|
||||
CapabilityGroupNonUniformBallot = 64,
|
||||
CapabilityGroupNonUniformShuffle = 65,
|
||||
CapabilityShaderLayer = 69,
|
||||
CapabilityShaderViewportIndex = 70,
|
||||
CapabilitySignedZeroInfNanPreserve = 4466,
|
||||
CapabilityFragmentBarycentricKHR = 5284,
|
||||
CapabilityComputeDerivativeGroupQuadsKHR = 5288,
|
||||
@@ -91,6 +92,7 @@ enum : uint32_t {
|
||||
BuiltInClipDistance = 3,
|
||||
BuiltInCullDistance = 4,
|
||||
BuiltInLayer = 9,
|
||||
BuiltInViewportIndex = 10,
|
||||
BuiltInFragCoord = 15,
|
||||
BuiltInFrontFacing = 17,
|
||||
BuiltInSampleId = 18,
|
||||
@@ -391,6 +393,7 @@ struct EmitterState {
|
||||
uint32_t clip_distance_variable = 0;
|
||||
uint32_t cull_distance_variable = 0;
|
||||
uint32_t layer_variable = 0;
|
||||
uint32_t viewport_index_variable = 0;
|
||||
uint32_t clip_distance_count = 0;
|
||||
uint32_t cull_distance_count = 0;
|
||||
uint32_t depth_variable = 0;
|
||||
|
||||
@@ -490,6 +490,10 @@ void AllocateOutputVariables(EmitterState& state) {
|
||||
case IR::StageOutputKind::Layer:
|
||||
binding.variable_id = AllocateSharedOutputVariable(state, state.layer_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::ViewportIndex:
|
||||
binding.variable_id =
|
||||
AllocateSharedOutputVariable(state, state.viewport_index_variable);
|
||||
break;
|
||||
case IR::StageOutputKind::Depth:
|
||||
binding.variable_id = AllocateSharedOutputVariable(state, state.depth_variable);
|
||||
break;
|
||||
@@ -583,6 +587,7 @@ void AddOutputAnnotationsAndNames(EmitterState& state) {
|
||||
AddBuiltIn(state.clip_distance_variable, "gl_ClipDistance", BuiltInClipDistance);
|
||||
AddBuiltIn(state.cull_distance_variable, "gl_CullDistance", BuiltInCullDistance);
|
||||
AddBuiltIn(state.layer_variable, "gl_Layer", BuiltInLayer);
|
||||
AddBuiltIn(state.viewport_index_variable, "gl_ViewportIndex", BuiltInViewportIndex);
|
||||
if (state.depth_variable != 0) {
|
||||
state.builder.AddName(state.depth_variable, "gl_FragDepth");
|
||||
state.builder.AddAnnotation(
|
||||
@@ -712,6 +717,10 @@ void DefineModule(EmitterState& state) {
|
||||
state.builder.RequireVersion(0x00010500u);
|
||||
state.builder.RequireCapability(CapabilityShaderLayer);
|
||||
}
|
||||
if (state.viewport_index_variable != 0) {
|
||||
state.builder.RequireVersion(0x00010500u);
|
||||
state.builder.RequireCapability(CapabilityShaderViewportIndex);
|
||||
}
|
||||
if (InputVariableForKind(state, IR::StageInputKind::SampleId) != 0) {
|
||||
state.builder.RequireCapability(CapabilitySampleRateShading);
|
||||
}
|
||||
@@ -874,6 +883,11 @@ void DefineModule(EmitterState& state) {
|
||||
state.layer_variable, TypePointer(state, StorageClassOutput, TypeU32(state)),
|
||||
StorageClassOutput);
|
||||
}
|
||||
if (state.viewport_index_variable != 0) {
|
||||
state.builder.DefineGlobalVariable(
|
||||
state.viewport_index_variable, TypePointer(state, StorageClassOutput, TypeU32(state)),
|
||||
StorageClassOutput);
|
||||
}
|
||||
for (const auto& binding: state.outputs) {
|
||||
if (binding.kind == IR::StageOutputKind::Parameter ||
|
||||
binding.kind == IR::StageOutputKind::Mrt) {
|
||||
|
||||
@@ -181,7 +181,8 @@ enum class StageOutputKind {
|
||||
PointSize,
|
||||
ClipDistance,
|
||||
CullDistance,
|
||||
Layer
|
||||
Layer,
|
||||
ViewportIndex
|
||||
};
|
||||
|
||||
struct PositionExportComponent {
|
||||
|
||||
@@ -324,7 +324,7 @@ void CollectOutputs(const Program& program, const ShaderVertexInputInfo* vertex,
|
||||
const auto output = DecodePositionExportComponent(
|
||||
vertex->pa_cl_vs_out_cntl, export_info.index, component);
|
||||
if (output.viewport) {
|
||||
return Fail("vertex viewport-index export is unsupported");
|
||||
AddOutput(info, StageOutputKind::ViewportIndex, 0, 0, "gl_ViewportIndex");
|
||||
}
|
||||
if (output.point_size) {
|
||||
AddOutput(info, StageOutputKind::PointSize, 0, 0, "gl_PointSize");
|
||||
|
||||
+33
-33
@@ -37,6 +37,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <span>
|
||||
#include <sstream>
|
||||
@@ -907,12 +908,12 @@ SpirvStoredBuiltInElements(const std::vector<uint32_t> &binary,
|
||||
return elements;
|
||||
}
|
||||
|
||||
bool SpirvBuiltInStoreUsesAndConstant(const std::vector<uint32_t> &binary,
|
||||
uint32_t builtin,
|
||||
uint32_t constant) {
|
||||
bool SpirvBuiltInStoreUsesOperation(const std::vector<uint32_t> &binary,
|
||||
uint32_t builtin, uint32_t operation,
|
||||
std::initializer_list<uint32_t> literals) {
|
||||
std::unordered_set<uint32_t> variables;
|
||||
std::unordered_map<uint32_t, uint32_t> constants;
|
||||
std::unordered_map<uint32_t, std::array<uint32_t, 2>> bitwise_ands;
|
||||
std::unordered_map<uint32_t, std::vector<uint32_t>> operations;
|
||||
std::unordered_map<uint32_t, uint32_t> stores;
|
||||
for (size_t i = 5; i < binary.size();) {
|
||||
const uint32_t opcode = binary[i] & 0xffffu;
|
||||
@@ -925,8 +926,8 @@ bool SpirvBuiltInStoreUsesAndConstant(const std::vector<uint32_t> &binary,
|
||||
variables.insert(binary[i + 1]);
|
||||
} else if (opcode == 43u && count >= 4u) {
|
||||
constants[binary[i + 2]] = binary[i + 3];
|
||||
} else if (opcode == 199u && count == 5u) {
|
||||
bitwise_ands[binary[i + 2]] = {binary[i + 3], binary[i + 4]};
|
||||
} else if (opcode == operation && count == 4u + literals.size()) {
|
||||
operations[binary[i + 2]] = {binary.begin() + i + 4, binary.begin() + i + count};
|
||||
} else if (opcode == 62u && count >= 3u) {
|
||||
stores[binary[i + 1]] = binary[i + 2];
|
||||
}
|
||||
@@ -937,15 +938,16 @@ bool SpirvBuiltInStoreUsesAndConstant(const std::vector<uint32_t> &binary,
|
||||
if (store == stores.end()) {
|
||||
continue;
|
||||
}
|
||||
const auto value = bitwise_ands.find(store->second);
|
||||
if (value == bitwise_ands.end()) {
|
||||
const auto value = operations.find(store->second);
|
||||
if (value == operations.end()) {
|
||||
continue;
|
||||
}
|
||||
for (const auto operand : value->second) {
|
||||
const auto literal = constants.find(operand);
|
||||
if (literal != constants.end() && literal->second == constant) {
|
||||
return true;
|
||||
}
|
||||
if (std::equal(value->second.begin(), value->second.end(), literals.begin(),
|
||||
[&](uint32_t id, uint32_t expected) {
|
||||
const auto literal = constants.find(id);
|
||||
return literal != constants.end() && literal->second == expected;
|
||||
})) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -9722,7 +9724,7 @@ void TestNewShaderRecompilerAuxPositionExports() {
|
||||
const auto all_source = DisassembleSpirvBinary(all.spirv);
|
||||
Check(all.spirv[1] == 0x00010500u &&
|
||||
!Common::ContainsStr(all_source, "SPV_EXT_shader_viewport_index_layer") &&
|
||||
SpirvBuiltInStoreUsesAndConstant(all.spirv, 9u, 0x7ffu),
|
||||
SpirvBuiltInStoreUsesOperation(all.spirv, 9u, 199u, {0x7ffu}),
|
||||
"layer export module version or GFX10 layer mask is incorrect");
|
||||
const auto positions = std::count_if(
|
||||
all.program.info.outputs.begin(), all.program.info.outputs.end(),
|
||||
@@ -9776,25 +9778,23 @@ void TestNewShaderRecompilerAuxPositionExports() {
|
||||
ShaderRecompiler::IR::StageOutputKind::Position,
|
||||
"unmapped auxiliary position export was not ignored");
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
const auto rejects = [](uint32_t control, uint32_t en,
|
||||
const char *message) {
|
||||
const uint32_t shader[] = {
|
||||
EncodeExp0(0x0c, 0xf, false), EncodeExp1(0, 1, 2, 3),
|
||||
EncodeExp0(0x0d, en), EncodeExp1(4, 5, 6, 7),
|
||||
0xbf810000u,
|
||||
};
|
||||
ShaderVertexInputInfo vertex{};
|
||||
vertex.pa_cl_vs_out_cntl = control;
|
||||
auto options = MakeCompileOptions(ShaderType::Vertex);
|
||||
options.input_info.vertex = &vertex;
|
||||
ExpectFatal([&] { (void)RecompileForTest(shader, options); },
|
||||
message);
|
||||
};
|
||||
rejects(0x00280000u, 0x4u,
|
||||
"viewport-index auxiliary position export did not terminate "
|
||||
"compilation");
|
||||
#endif
|
||||
// R-Type Final 3 packs a dynamic viewport index into POS1.z bits 16..19.
|
||||
// The same component can carry an independent render-target layer in bits 0..10.
|
||||
for (const uint32_t control : {0x01280000u, 0x012c0000u}) {
|
||||
const auto indexed = compile(unmapped, control);
|
||||
CheckSpirvBinaryValidates(indexed.spirv);
|
||||
Check(indexed.spirv[1] == 0x00010500u &&
|
||||
SpirvContainsCapability(indexed.spirv, 70u) &&
|
||||
SpirvBuiltInStoreUsesOperation(indexed.spirv, 10u, 203u, {16u, 4u}),
|
||||
"viewport export did not store the GFX10 four-bit index");
|
||||
const bool layered = (control & (1u << 18u)) != 0;
|
||||
Check(SpirvBuiltInStoreUsesOperation(indexed.spirv, 9u, 199u, {0x7ffu}) == layered,
|
||||
"packed layer/viewport export dropped or invented a layer store");
|
||||
Check(std::ranges::any_of(indexed.program.info.outputs, [](const auto &output) {
|
||||
return output.kind == ShaderRecompiler::IR::StageOutputKind::ViewportIndex;
|
||||
}),
|
||||
"viewport export was omitted from shader reflection");
|
||||
}
|
||||
|
||||
ShaderVertexInputInfo key0{};
|
||||
ShaderVertexInputInfo key1{};
|
||||
|
||||
Reference in New Issue
Block a user