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:
nmzik
2026-09-06 10:16:38 +04:00
parent dcaf4205cb
commit f9f8e12c35
11 changed files with 140 additions and 84 deletions
+3 -2
View File
@@ -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};
+1 -1
View File
@@ -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,
+42 -26
View File
@@ -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) {