mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
renderer: emulate clip-disabled screen-space positions
This commit is contained in:
@@ -490,7 +490,7 @@ static void ClipCheck(const HW::ClipControl& c) {
|
|||||||
// dx_linear_attr_clip_enable preserves linear (noperspective) attributes at clip-generated
|
// dx_linear_attr_clip_enable preserves linear (noperspective) attributes at clip-generated
|
||||||
// vertices, which Vulkan provides as part of clipping and interpolation.
|
// vertices, which Vulkan provides as part of clipping and interpolation.
|
||||||
EXIT_NOT_IMPLEMENTED(c.user_clip_planes != 0 || c.user_clip_plane_mode != 0 ||
|
EXIT_NOT_IMPLEMENTED(c.user_clip_planes != 0 || c.user_clip_plane_mode != 0 ||
|
||||||
c.vertex_kill_any || c.user_clip_plane_negate_y || c.clip_disable ||
|
c.vertex_kill_any || c.user_clip_plane_negate_y ||
|
||||||
c.user_clip_plane_cull_only || c.cull_on_clipping_error_disable ||
|
c.user_clip_plane_cull_only || c.cull_on_clipping_error_disable ||
|
||||||
c.force_viewport_index_from_vs_enable);
|
c.force_viewport_index_from_vs_enable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ struct PipelineCache::ProgramCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::size_t MaxStaticKeyWords =
|
static constexpr std::size_t MaxStaticKeyWords =
|
||||||
5 + ShaderVertexInputInfo::RES_MAX * 17;
|
12 + ShaderVertexInputInfo::RES_MAX * 17;
|
||||||
|
|
||||||
template <typename InputInfo>
|
template <typename InputInfo>
|
||||||
ShaderProgram Get(const ShaderParams& params, InputInfo& input_info) {
|
ShaderProgram Get(const ShaderParams& params, InputInfo& input_info) {
|
||||||
@@ -340,8 +340,23 @@ void PipelineCache::Save() {
|
|||||||
|
|
||||||
ShaderProgram PipelineCache::GetVertexProgram(const HW::VertexShaderInfo& regs,
|
ShaderProgram PipelineCache::GetVertexProgram(const HW::VertexShaderInfo& regs,
|
||||||
const HW::ShaderRegisters& sh,
|
const HW::ShaderRegisters& sh,
|
||||||
|
const HW::Context& context,
|
||||||
ShaderVertexInputInfo& input_info) {
|
ShaderVertexInputInfo& input_info) {
|
||||||
const auto params = PrepareProgram(regs, sh, input_info);
|
const auto params = PrepareProgram(regs, sh, input_info);
|
||||||
|
if (context.GetClipControl().clip_disable) {
|
||||||
|
const auto& viewport = context.GetScreenViewport().viewports[0];
|
||||||
|
const auto& limits = m_graphics.GetPhysicalDeviceProperties().limits;
|
||||||
|
auto& clip = input_info.clip_space;
|
||||||
|
clip.scale[0] = viewport.xscale;
|
||||||
|
clip.scale[1] = viewport.yscale;
|
||||||
|
clip.offset[0] = viewport.xoffset;
|
||||||
|
clip.offset[1] = viewport.yoffset;
|
||||||
|
clip.half_extent[0] =
|
||||||
|
static_cast<float>(std::min(limits.maxViewportDimensions[0], 16384u)) * 0.5f;
|
||||||
|
clip.half_extent[1] =
|
||||||
|
static_cast<float>(std::min(limits.maxViewportDimensions[1], 16384u)) * 0.5f;
|
||||||
|
clip.enabled = true;
|
||||||
|
}
|
||||||
Common::LockGuard lock(m_mutex);
|
Common::LockGuard lock(m_mutex);
|
||||||
return m_program_cache->Get(params, input_info);
|
return m_program_cache->Get(params, input_info);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ public:
|
|||||||
|
|
||||||
ShaderProgram GetVertexProgram(const HW::VertexShaderInfo& regs,
|
ShaderProgram GetVertexProgram(const HW::VertexShaderInfo& regs,
|
||||||
const HW::ShaderRegisters& sh,
|
const HW::ShaderRegisters& sh,
|
||||||
|
const HW::Context& context,
|
||||||
ShaderVertexInputInfo& input_info);
|
ShaderVertexInputInfo& input_info);
|
||||||
ShaderProgram
|
ShaderProgram
|
||||||
GetPixelProgram(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
GetPixelProgram(const HW::PixelShaderInfo& regs, const HW::ShaderRegisters& sh,
|
||||||
|
|||||||
@@ -331,10 +331,18 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
|
|||||||
const auto final_scissor = calc_final_scissor(vp, ctx.GetScanModeControl(), framebuffer_extent);
|
const auto final_scissor = calc_final_scissor(vp, ctx.GetScanModeControl(), framebuffer_extent);
|
||||||
|
|
||||||
vk::Viewport viewport {};
|
vk::Viewport viewport {};
|
||||||
viewport.x = vp.viewports[0].xoffset - vp.viewports[0].xscale;
|
if (ctx.GetClipControl().clip_disable) {
|
||||||
viewport.y = vp.viewports[0].yoffset - vp.viewports[0].yscale;
|
const auto& limits = buffer.GetGraphics().GetPhysicalDeviceProperties().limits;
|
||||||
viewport.width = vp.viewports[0].xscale * 2.0f;
|
viewport.x = 0.0f;
|
||||||
viewport.height = vp.viewports[0].yscale * 2.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;
|
||||||
|
}
|
||||||
viewport.minDepth = vp.viewports[0].zoffset;
|
viewport.minDepth = vp.viewports[0].zoffset;
|
||||||
viewport.maxDepth = vp.viewports[0].zscale + vp.viewports[0].zoffset;
|
viewport.maxDepth = vp.viewports[0].zscale + vp.viewports[0].zoffset;
|
||||||
vk_buffer.setViewport(0, 1, &viewport);
|
vk_buffer.setViewport(0, 1, &viewport);
|
||||||
@@ -1013,8 +1021,8 @@ static void RefreshShaders(CommandBuffer& buffer, const DrawCallInfo& draw, bool
|
|||||||
LogDrawPhase(draw.name, "GetVertexProgram");
|
LogDrawPhase(draw.name, "GetVertexProgram");
|
||||||
}
|
}
|
||||||
auto& pipeline_cache = buffer.GetContext().GetPipelineCache();
|
auto& pipeline_cache = buffer.GetContext().GetPipelineCache();
|
||||||
state.vertex_program =
|
state.vertex_program = pipeline_cache.GetVertexProgram(vertex_shader_info, shader_regs, ctx,
|
||||||
pipeline_cache.GetVertexProgram(vertex_shader_info, shader_regs, state.vs_input_info);
|
state.vs_input_info);
|
||||||
|
|
||||||
if (!state.ps_active) {
|
if (!state.ps_active) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -408,6 +408,41 @@ void EmitAuxPositionExport(ValueEmitContext& ctx, uint32_t data, const IR::Expor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ConvertClipCoordinate(EmitterState& state, uint32_t coordinate, float scale,
|
||||||
|
float offset, float half_extent) {
|
||||||
|
const auto window = state.builder.AllocateId();
|
||||||
|
const auto biased = state.builder.AllocateId();
|
||||||
|
const auto divided = state.builder.AllocateId();
|
||||||
|
const auto ndc = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpFMul, TypeF32(state), window, coordinate, ConstantF32Value(state, scale)});
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpFAdd, TypeF32(state), biased, window, ConstantF32Value(state, offset)});
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpFDiv, TypeF32(state), divided, biased, ConstantF32Value(state, half_extent)});
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpFSub, TypeF32(state), ndc, divided, ConstantF32Value(state, 1.0f)});
|
||||||
|
return ndc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ConvertPositionToClipSpace(EmitterState& state, uint32_t position) {
|
||||||
|
const auto& transform = state.input_info.vertex->clip_space;
|
||||||
|
uint32_t components[4] {};
|
||||||
|
for (uint32_t i = 0; i < 4; i++) {
|
||||||
|
components[i] = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpCompositeExtract, TypeF32(state), components[i], position, i});
|
||||||
|
}
|
||||||
|
components[0] = ConvertClipCoordinate(state, components[0], transform.scale[0],
|
||||||
|
transform.offset[0], transform.half_extent[0]);
|
||||||
|
components[1] = ConvertClipCoordinate(state, components[1], transform.scale[1],
|
||||||
|
transform.offset[1], transform.half_extent[1]);
|
||||||
|
const auto converted = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpCompositeConstruct, TypeF32Vector(state, 4), converted,
|
||||||
|
components[0], components[1], components[2], components[3]});
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||||
auto& state = ctx.state;
|
auto& state = ctx.state;
|
||||||
const auto& exp = ctx.Export(inst);
|
const auto& exp = ctx.Export(inst);
|
||||||
@@ -467,6 +502,9 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (exp.kind == IR::ExportTargetKind::Position) {
|
if (exp.kind == IR::ExportTargetKind::Position) {
|
||||||
|
if (state.stage == ShaderType::Vertex && state.input_info.vertex->clip_space.enabled) {
|
||||||
|
value = ConvertPositionToClipSpace(state, value);
|
||||||
|
}
|
||||||
const auto pointer = state.builder.AllocateId();
|
const auto pointer = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(
|
state.builder.AddFunction(
|
||||||
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeF32Vector(state, 4)),
|
{OpAccessChain, TypePointer(state, StorageClassOutput, TypeF32Vector(state, 4)),
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <bit>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
@@ -897,6 +898,18 @@ void BuildStageStaticKey(const ShaderVertexInputInfo& info, std::vector<uint32_t
|
|||||||
key.push_back(info.resources_num);
|
key.push_back(info.resources_num);
|
||||||
key.push_back(info.scratch_size_dwords);
|
key.push_back(info.scratch_size_dwords);
|
||||||
key.push_back(info.pa_cl_vs_out_cntl);
|
key.push_back(info.pa_cl_vs_out_cntl);
|
||||||
|
key.push_back(static_cast<uint32_t>(info.clip_space.enabled));
|
||||||
|
if (info.clip_space.enabled) {
|
||||||
|
for (const float value: info.clip_space.scale) {
|
||||||
|
key.push_back(std::bit_cast<uint32_t>(value));
|
||||||
|
}
|
||||||
|
for (const float value: info.clip_space.offset) {
|
||||||
|
key.push_back(std::bit_cast<uint32_t>(value));
|
||||||
|
}
|
||||||
|
for (const float value: info.clip_space.half_extent) {
|
||||||
|
key.push_back(std::bit_cast<uint32_t>(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < info.resources_num; i++) {
|
for (int i = 0; i < info.resources_num; i++) {
|
||||||
const auto& resource = info.resources[i];
|
const auto& resource = info.resources[i];
|
||||||
|
|||||||
@@ -68,6 +68,13 @@ inline uint8_t GetDstSel(uint32_t swizzle, uint32_t channel) {
|
|||||||
return (swizzle >> (channel * 3u)) & 0x7u;
|
return (swizzle >> (channel * 3u)) & 0x7u;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ShaderClipSpaceTransform {
|
||||||
|
float scale[2] = {};
|
||||||
|
float offset[2] = {};
|
||||||
|
float half_extent[2] = {};
|
||||||
|
bool enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
struct ShaderVertexInputInfo {
|
struct ShaderVertexInputInfo {
|
||||||
static constexpr int RES_MAX = 32;
|
static constexpr int RES_MAX = 32;
|
||||||
|
|
||||||
@@ -84,6 +91,7 @@ struct ShaderVertexInputInfo {
|
|||||||
uint32_t scratch_size_dwords = 0;
|
uint32_t scratch_size_dwords = 0;
|
||||||
uint32_t param_export_mask = 0;
|
uint32_t param_export_mask = 0;
|
||||||
uint32_t pa_cl_vs_out_cntl = 0;
|
uint32_t pa_cl_vs_out_cntl = 0;
|
||||||
|
ShaderClipSpaceTransform clip_space;
|
||||||
bool fetch_external = false;
|
bool fetch_external = false;
|
||||||
bool fetch_embedded = false;
|
bool fetch_embedded = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8811,6 +8811,45 @@ void TestNewShaderRecompilerExpVertexOutputs() {
|
|||||||
CheckSpirvBinaryValidates(result.spirv);
|
CheckSpirvBinaryValidates(result.spirv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestNewShaderRecompilerClipDisabledPosition() {
|
||||||
|
const uint32_t shader[] = {
|
||||||
|
EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 2, 3), 0xbf810000u,
|
||||||
|
};
|
||||||
|
const auto compile = [&](const ShaderVertexInputInfo &vertex) {
|
||||||
|
auto options = MakeCompileOptions(ShaderType::Vertex);
|
||||||
|
options.input_info.vertex = &vertex;
|
||||||
|
return ShaderRecompiler::Recompile(shader, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderVertexInputInfo regular{};
|
||||||
|
auto clipped = regular;
|
||||||
|
clipped.clip_space = {
|
||||||
|
.scale = {640.0f, 360.0f},
|
||||||
|
.offset = {640.0f, 360.0f},
|
||||||
|
.half_extent = {8192.0f, 8192.0f},
|
||||||
|
.enabled = true,
|
||||||
|
};
|
||||||
|
const auto regular_result = compile(regular);
|
||||||
|
const auto clipped_result = compile(clipped);
|
||||||
|
CheckSpirvBinaryValidates(clipped_result.spirv);
|
||||||
|
Check(SpirvInstructionOpcodeCount(regular_result.spirv, 136u) == 0u &&
|
||||||
|
SpirvInstructionOpcodeCount(clipped_result.spirv, 133u) == 2u &&
|
||||||
|
SpirvInstructionOpcodeCount(clipped_result.spirv, 129u) == 2u &&
|
||||||
|
SpirvInstructionOpcodeCount(clipped_result.spirv, 136u) == 2u &&
|
||||||
|
SpirvInstructionOpcodeCount(clipped_result.spirv, 131u) == 2u,
|
||||||
|
"clip-disabled position export did not convert both screen coordinates to NDC");
|
||||||
|
Check(MakeStageStaticKey(regular) != MakeStageStaticKey(clipped),
|
||||||
|
"clip-disabled vertex shader shared the regular shader cache key");
|
||||||
|
auto disabled = clipped;
|
||||||
|
disabled.clip_space.enabled = false;
|
||||||
|
Check(MakeStageStaticKey(regular) == MakeStageStaticKey(disabled),
|
||||||
|
"disabled clip-space payload affected the shader cache key");
|
||||||
|
auto shifted = clipped;
|
||||||
|
shifted.clip_space.offset[0] += 1.0f;
|
||||||
|
Check(MakeStageStaticKey(clipped) != MakeStageStaticKey(shifted),
|
||||||
|
"clip-disabled viewport transform is absent from the shader cache key");
|
||||||
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerAuxPositionExports() {
|
void TestNewShaderRecompilerAuxPositionExports() {
|
||||||
const auto compile = [](std::span<const uint32_t> shader, uint32_t control) {
|
const auto compile = [](std::span<const uint32_t> shader, uint32_t control) {
|
||||||
ShaderVertexInputInfo vertex{};
|
ShaderVertexInputInfo vertex{};
|
||||||
@@ -11908,6 +11947,7 @@ int main() {
|
|||||||
TestNewShaderRecompilerSpirvSizeBaselines();
|
TestNewShaderRecompilerSpirvSizeBaselines();
|
||||||
TestDemandDrivenSpirvDeclarations();
|
TestDemandDrivenSpirvDeclarations();
|
||||||
TestNewShaderRecompilerSMovB32();
|
TestNewShaderRecompilerSMovB32();
|
||||||
|
TestNewShaderRecompilerClipDisabledPosition();
|
||||||
TestNewShaderRecompilerAuxPositionExports();
|
TestNewShaderRecompilerAuxPositionExports();
|
||||||
TestNewShaderRecompilerNativeWideScalarMemoryIr();
|
TestNewShaderRecompilerNativeWideScalarMemoryIr();
|
||||||
TestNewShaderRecompilerNativeWideBufferIr();
|
TestNewShaderRecompilerNativeWideBufferIr();
|
||||||
|
|||||||
Reference in New Issue
Block a user