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