Skip to content

Commit e32c5d2

Browse files
committed
Tessellation (shadps4-emu#1528)
1 parent 09be037 commit e32c5d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+2142
-186
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
664664
src/shader_recompiler/ir/passes/constant_propagation_pass.cpp
665665
src/shader_recompiler/ir/passes/dead_code_elimination_pass.cpp
666666
src/shader_recompiler/ir/passes/flatten_extended_userdata_pass.cpp
667+
src/shader_recompiler/ir/passes/hull_shader_transform.cpp
667668
src/shader_recompiler/ir/passes/identity_removal_pass.cpp
668669
src/shader_recompiler/ir/passes/ir_passes.h
669670
src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp
@@ -683,6 +684,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
683684
src/shader_recompiler/ir/opcodes.cpp
684685
src/shader_recompiler/ir/opcodes.h
685686
src/shader_recompiler/ir/opcodes.inc
687+
src/shader_recompiler/ir/patch.cpp
688+
src/shader_recompiler/ir/patch.h
686689
src/shader_recompiler/ir/post_order.cpp
687690
src/shader_recompiler/ir/post_order.h
688691
src/shader_recompiler/ir/program.cpp

src/core/debug_state.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,11 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
177177
}
178178
}
179179

180-
void DebugStateImpl::CollectShader(const std::string& name, vk::ShaderModule module,
181-
std::span<const u32> spv, std::span<const u32> raw_code,
182-
std::span<const u32> patch_spv, bool is_patched) {
183-
shader_dump_list.emplace_back(name, module, std::vector<u32>{spv.begin(), spv.end()},
180+
void DebugStateImpl::CollectShader(const std::string& name, Shader::LogicalStage l_stage,
181+
vk::ShaderModule module, std::span<const u32> spv,
182+
std::span<const u32> raw_code, std::span<const u32> patch_spv,
183+
bool is_patched) {
184+
shader_dump_list.emplace_back(name, l_stage, module, std::vector<u32>{spv.begin(), spv.end()},
184185
std::vector<u32>{raw_code.begin(), raw_code.end()},
185186
std::vector<u32>{patch_spv.begin(), patch_spv.end()}, is_patched);
186187
}

src/core/debug_state.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct FrameDump {
7676

7777
struct ShaderDump {
7878
std::string name;
79+
Shader::LogicalStage l_stage;
7980
vk::ShaderModule module;
8081

8182
std::vector<u32> spv;
@@ -90,16 +91,17 @@ struct ShaderDump {
9091
std::string cache_isa_disasm{};
9192
std::string cache_patch_disasm{};
9293

93-
ShaderDump(std::string name, vk::ShaderModule module, std::vector<u32> spv,
94-
std::vector<u32> isa, std::vector<u32> patch_spv, bool is_patched)
95-
: name(std::move(name)), module(module), spv(std::move(spv)), isa(std::move(isa)),
96-
patch_spv(std::move(patch_spv)), is_patched(is_patched) {}
94+
ShaderDump(std::string name, Shader::LogicalStage l_stage, vk::ShaderModule module,
95+
std::vector<u32> spv, std::vector<u32> isa, std::vector<u32> patch_spv,
96+
bool is_patched)
97+
: name(std::move(name)), l_stage(l_stage), module(module), spv(std::move(spv)),
98+
isa(std::move(isa)), patch_spv(std::move(patch_spv)), is_patched(is_patched) {}
9799

98100
ShaderDump(const ShaderDump& other) = delete;
99101
ShaderDump(ShaderDump&& other) noexcept
100-
: name{std::move(other.name)}, module{std::move(other.module)}, spv{std::move(other.spv)},
101-
isa{std::move(other.isa)}, patch_spv{std::move(other.patch_spv)},
102-
patch_source{std::move(other.patch_source)},
102+
: name{std::move(other.name)}, l_stage(other.l_stage), module{std::move(other.module)},
103+
spv{std::move(other.spv)}, isa{std::move(other.isa)},
104+
patch_spv{std::move(other.patch_spv)}, patch_source{std::move(other.patch_source)},
103105
cache_spv_disasm{std::move(other.cache_spv_disasm)},
104106
cache_isa_disasm{std::move(other.cache_isa_disasm)},
105107
cache_patch_disasm{std::move(other.cache_patch_disasm)} {}
@@ -108,6 +110,7 @@ struct ShaderDump {
108110
if (this == &other)
109111
return *this;
110112
name = std::move(other.name);
113+
l_stage = other.l_stage;
111114
module = std::move(other.module);
112115
spv = std::move(other.spv);
113116
isa = std::move(other.isa);
@@ -203,7 +206,8 @@ class DebugStateImpl {
203206
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
204207
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
205208

206-
void CollectShader(const std::string& name, vk::ShaderModule module, std::span<const u32> spv,
209+
void CollectShader(const std::string& name, Shader::LogicalStage l_stage,
210+
vk::ShaderModule module, std::span<const u32> spv,
207211
std::span<const u32> raw_code, std::span<const u32> patch_spv,
208212
bool is_patched);
209213
};

src/core/devtools/widget/shader_list.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,17 @@ bool ShaderList::Selection::DrawShader(DebugStateType::ShaderDump& value) {
158158
DebugState.ShowDebugMessage(msg);
159159
}
160160
if (compile) {
161-
static std::map<std::string, std::string> stage_arg = {
162-
{"vs", "vert"},
163-
{"gs", "geom"},
164-
{"fs", "frag"},
165-
{"cs", "comp"},
161+
static std::map<Shader::LogicalStage, std::string> stage_arg = {
162+
{Shader::LogicalStage::Vertex, "vert"},
163+
{Shader::LogicalStage::TessellationControl, "tesc"},
164+
{Shader::LogicalStage::TessellationEval, "tese"},
165+
{Shader::LogicalStage::Geometry, "geom"},
166+
{Shader::LogicalStage::Fragment, "frag"},
167+
{Shader::LogicalStage::Compute, "comp"},
166168
};
167-
auto stage = stage_arg.find(value.name.substr(0, 2));
169+
auto stage = stage_arg.find(value.l_stage);
168170
if (stage == stage_arg.end()) {
169-
DebugState.ShowDebugMessage(std::string{"Invalid shader stage: "} +
170-
value.name.substr(0, 2));
171+
DebugState.ShowDebugMessage(std::string{"Invalid shader stage"});
171172
} else {
172173
std::string cmd =
173174
fmt::format("glslc --target-env=vulkan1.3 --target-spv=spv1.6 "

src/core/libraries/gnmdriver/gnmdriver.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,7 +1642,6 @@ s32 PS4_SYSV_ABI sceGnmSetGsShader(u32* cmdbuf, u32 size, const u32* gs_regs) {
16421642

16431643
s32 PS4_SYSV_ABI sceGnmSetHsShader(u32* cmdbuf, u32 size, const u32* hs_regs, u32 param4) {
16441644
LOG_TRACE(Lib_GnmDriver, "called");
1645-
16461645
if (!cmdbuf || size < 0x1E) {
16471646
return -1;
16481647
}
@@ -1660,11 +1659,13 @@ s32 PS4_SYSV_ABI sceGnmSetHsShader(u32* cmdbuf, u32 size, const u32* hs_regs, u3
16601659
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x108u, hs_regs[0], 0u); // SPI_SHADER_PGM_LO_HS
16611660
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x10au, hs_regs[2],
16621661
hs_regs[3]); // SPI_SHADER_PGM_RSRC1_HS/SPI_SHADER_PGM_RSRC2_HS
1663-
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x286u, hs_regs[5],
1664-
hs_regs[5]); // VGT_HOS_MAX_TESS_LEVEL
1662+
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x286u,
1663+
hs_regs[5], // VGT_HOS_MAX_TESS_LEVEL
1664+
hs_regs[6]); // VGT_HOS_MIN_TESS_LEVEL
16651665
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x2dbu, hs_regs[4]); // VGT_TF_PARAM
16661666
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x2d6u, param4); // VGT_LS_HS_CONFIG
16671667

1668+
// right padding?
16681669
WriteTrailingNop<11>(cmdbuf);
16691670
return ORBIS_OK;
16701671
}

src/shader_recompiler/backend/spirv/emit_spirv.cpp

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
22
// SPDX-License-Identifier: GPL-2.0-or-later
3-
43
#include <span>
54
#include <type_traits>
65
#include <utility>
@@ -13,6 +12,7 @@
1312
#include "shader_recompiler/frontend/translate/translate.h"
1413
#include "shader_recompiler/ir/basic_block.h"
1514
#include "shader_recompiler/ir/program.h"
15+
#include "shader_recompiler/runtime_info.h"
1616
#include "video_core/amdgpu/types.h"
1717

1818
namespace Shader::Backend::SPIRV {
@@ -72,7 +72,10 @@ ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
7272
return arg.VectorReg();
7373
} else if constexpr (std::is_same_v<ArgType, const char*>) {
7474
return arg.StringLiteral();
75+
} else if constexpr (std::is_same_v<ArgType, IR::Patch>) {
76+
return arg.Patch();
7577
}
78+
UNREACHABLE();
7679
}
7780

7881
template <auto func, bool is_first_arg_inst, size_t... I>
@@ -206,6 +209,32 @@ Id DefineMain(EmitContext& ctx, const IR::Program& program) {
206209
return main;
207210
}
208211

212+
spv::ExecutionMode ExecutionMode(AmdGpu::TessellationType primitive) {
213+
switch (primitive) {
214+
case AmdGpu::TessellationType::Isoline:
215+
return spv::ExecutionMode::Isolines;
216+
case AmdGpu::TessellationType::Triangle:
217+
return spv::ExecutionMode::Triangles;
218+
case AmdGpu::TessellationType::Quad:
219+
return spv::ExecutionMode::Quads;
220+
}
221+
UNREACHABLE_MSG("Tessellation primitive {}", primitive);
222+
}
223+
224+
spv::ExecutionMode ExecutionMode(AmdGpu::TessellationPartitioning spacing) {
225+
switch (spacing) {
226+
case AmdGpu::TessellationPartitioning::Integer:
227+
return spv::ExecutionMode::SpacingEqual;
228+
case AmdGpu::TessellationPartitioning::FracOdd:
229+
return spv::ExecutionMode::SpacingFractionalOdd;
230+
case AmdGpu::TessellationPartitioning::FracEven:
231+
return spv::ExecutionMode::SpacingFractionalEven;
232+
default:
233+
break;
234+
}
235+
UNREACHABLE_MSG("Tessellation spacing {}", spacing);
236+
}
237+
209238
void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ctx) {
210239
ctx.AddCapability(spv::Capability::Image1D);
211240
ctx.AddCapability(spv::Capability::Sampled1D);
@@ -248,36 +277,55 @@ void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ct
248277
if (info.uses_group_ballot) {
249278
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
250279
}
251-
if (info.stage == Stage::Export || info.stage == Stage::Vertex) {
280+
const auto stage = info.l_stage;
281+
if (stage == LogicalStage::Vertex) {
252282
ctx.AddExtension("SPV_KHR_shader_draw_parameters");
253283
ctx.AddCapability(spv::Capability::DrawParameters);
254284
}
255-
if (info.stage == Stage::Geometry) {
285+
if (stage == LogicalStage::Geometry) {
256286
ctx.AddCapability(spv::Capability::Geometry);
257287
}
258288
if (info.stage == Stage::Fragment && profile.needs_manual_interpolation) {
259289
ctx.AddExtension("SPV_KHR_fragment_shader_barycentric");
260290
ctx.AddCapability(spv::Capability::FragmentBarycentricKHR);
261291
}
292+
if (stage == LogicalStage::TessellationControl || stage == LogicalStage::TessellationEval) {
293+
ctx.AddCapability(spv::Capability::Tessellation);
294+
}
262295
}
263296

264-
void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
265-
const auto& info = program.info;
297+
void DefineEntryPoint(const Info& info, EmitContext& ctx, Id main) {
266298
const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size());
267299
spv::ExecutionModel execution_model{};
268-
switch (program.info.stage) {
269-
case Stage::Compute: {
300+
switch (info.l_stage) {
301+
case LogicalStage::Compute: {
270302
const std::array<u32, 3> workgroup_size{ctx.runtime_info.cs_info.workgroup_size};
271303
execution_model = spv::ExecutionModel::GLCompute;
272304
ctx.AddExecutionMode(main, spv::ExecutionMode::LocalSize, workgroup_size[0],
273305
workgroup_size[1], workgroup_size[2]);
274306
break;
275307
}
276-
case Stage::Export:
277-
case Stage::Vertex:
308+
case LogicalStage::Vertex:
278309
execution_model = spv::ExecutionModel::Vertex;
279310
break;
280-
case Stage::Fragment:
311+
case LogicalStage::TessellationControl:
312+
execution_model = spv::ExecutionModel::TessellationControl;
313+
ctx.AddCapability(spv::Capability::Tessellation);
314+
ctx.AddExecutionMode(main, spv::ExecutionMode::OutputVertices,
315+
ctx.runtime_info.hs_info.NumOutputControlPoints());
316+
break;
317+
case LogicalStage::TessellationEval: {
318+
execution_model = spv::ExecutionModel::TessellationEvaluation;
319+
const auto& vs_info = ctx.runtime_info.vs_info;
320+
ctx.AddExecutionMode(main, ExecutionMode(vs_info.tess_type));
321+
ctx.AddExecutionMode(main, ExecutionMode(vs_info.tess_partitioning));
322+
ctx.AddExecutionMode(main,
323+
vs_info.tess_topology == AmdGpu::TessellationTopology::TriangleCcw
324+
? spv::ExecutionMode::VertexOrderCcw
325+
: spv::ExecutionMode::VertexOrderCw);
326+
break;
327+
}
328+
case LogicalStage::Fragment:
281329
execution_model = spv::ExecutionModel::Fragment;
282330
if (ctx.profile.lower_left_origin_mode) {
283331
ctx.AddExecutionMode(main, spv::ExecutionMode::OriginLowerLeft);
@@ -292,7 +340,7 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
292340
ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
293341
}
294342
break;
295-
case Stage::Geometry:
343+
case LogicalStage::Geometry:
296344
execution_model = spv::ExecutionModel::Geometry;
297345
ctx.AddExecutionMode(main, GetInputPrimitiveType(ctx.runtime_info.gs_info.in_primitive));
298346
ctx.AddExecutionMode(main,
@@ -303,7 +351,7 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
303351
ctx.runtime_info.gs_info.num_invocations);
304352
break;
305353
default:
306-
throw NotImplementedException("Stage {}", u32(program.info.stage));
354+
UNREACHABLE_MSG("Stage {}", u32(info.stage));
307355
}
308356
ctx.AddEntryPoint(execution_model, main, "main", interfaces);
309357
}
@@ -349,7 +397,7 @@ std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in
349397
const IR::Program& program, Bindings& binding) {
350398
EmitContext ctx{profile, runtime_info, program.info, binding};
351399
const Id main{DefineMain(ctx, program)};
352-
DefineEntryPoint(program, ctx, main);
400+
DefineEntryPoint(program.info, ctx, main);
353401
SetupCapabilities(program.info, profile, ctx);
354402
SetupFloatMode(ctx, profile, runtime_info, main);
355403
PatchPhiNodes(program, ctx);

src/shader_recompiler/backend/spirv/emit_spirv_barriers.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ void MemoryBarrier(EmitContext& ctx, spv::Scope scope) {
1818

1919
void EmitBarrier(EmitContext& ctx) {
2020
const auto execution{spv::Scope::Workgroup};
21-
const auto memory{spv::Scope::Workgroup};
22-
const auto memory_semantics{spv::MemorySemanticsMask::AcquireRelease |
23-
spv::MemorySemanticsMask::WorkgroupMemory};
21+
spv::Scope memory;
22+
spv::MemorySemanticsMask memory_semantics;
23+
if (ctx.l_stage == Shader::LogicalStage::TessellationControl) {
24+
memory = spv::Scope::Invocation;
25+
memory_semantics = spv::MemorySemanticsMask::MaskNone;
26+
} else {
27+
memory = spv::Scope::Workgroup;
28+
memory_semantics =
29+
spv::MemorySemanticsMask::AcquireRelease | spv::MemorySemanticsMask::WorkgroupMemory;
30+
}
2431
ctx.OpControlBarrier(ctx.ConstU32(static_cast<u32>(execution)),
2532
ctx.ConstU32(static_cast<u32>(memory)),
2633
ctx.ConstU32(static_cast<u32>(memory_semantics)));

0 commit comments

Comments
 (0)