mirror of
https://github.com/yuzu-emu/yuzu-mainline.git
synced 2024-12-26 17:25:26 +00:00
glsl: Implement tessellation shaders
This commit is contained in:
parent
c7d085b505
commit
8c684b3e23
|
@ -21,10 +21,21 @@ std::string_view InterpDecorator(Interpolation interp) {
|
||||||
throw InvalidArgument("Invalid interpolation {}", interp);
|
throw InvalidArgument("Invalid interpolation {}", interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view ArrayDecorator(Stage stage) {
|
std::string_view InputArrayDecorator(Stage stage) {
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case Stage::Geometry:
|
case Stage::Geometry:
|
||||||
return "[1]";
|
case Stage::TessellationControl:
|
||||||
|
case Stage::TessellationEval:
|
||||||
|
return "[]";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OutputDecorator(Stage stage, u32 size) {
|
||||||
|
switch (stage) {
|
||||||
|
case Stage::TessellationControl:
|
||||||
|
return fmt::format("[{}]", size);
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -73,6 +84,30 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string_view GetTessMode(TessPrimitive primitive) {
|
||||||
|
switch (primitive) {
|
||||||
|
case TessPrimitive::Triangles:
|
||||||
|
return "triangles";
|
||||||
|
case TessPrimitive::Quads:
|
||||||
|
return "quads";
|
||||||
|
case TessPrimitive::Isolines:
|
||||||
|
return "isolines";
|
||||||
|
}
|
||||||
|
throw InvalidArgument("Invalid tessellation primitive {}", primitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view GetTessSpacing(TessSpacing spacing) {
|
||||||
|
switch (spacing) {
|
||||||
|
case TessSpacing::Equal:
|
||||||
|
return "equal_spacing";
|
||||||
|
case TessSpacing::FractionalOdd:
|
||||||
|
return "fractional_odd_spacing";
|
||||||
|
case TessSpacing::FractionalEven:
|
||||||
|
return "fractional_even_spacing";
|
||||||
|
}
|
||||||
|
throw InvalidArgument("Invalid tessellation spacing {}", spacing);
|
||||||
|
}
|
||||||
|
|
||||||
std::string_view InputPrimitive(InputTopology topology) {
|
std::string_view InputPrimitive(InputTopology topology) {
|
||||||
switch (topology) {
|
switch (topology) {
|
||||||
case InputTopology::Points:
|
case InputTopology::Points:
|
||||||
|
@ -100,6 +135,23 @@ std::string_view OutputPrimitive(OutputTopology topology) {
|
||||||
}
|
}
|
||||||
throw InvalidArgument("Invalid output topology {}", topology);
|
throw InvalidArgument("Invalid output topology {}", topology);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupOutPerVertex(Stage stage, const Info& info, std::string& header) {
|
||||||
|
if (stage != Stage::VertexA && stage != Stage::VertexB && stage != Stage::Geometry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
header += "out gl_PerVertex{";
|
||||||
|
if (info.stores_position) {
|
||||||
|
header += "vec4 gl_Position;";
|
||||||
|
}
|
||||||
|
if (info.stores_point_size) {
|
||||||
|
header += "float gl_PointSize;";
|
||||||
|
}
|
||||||
|
if (info.stores_clip_distance) {
|
||||||
|
header += "float gl_ClipDistance[];";
|
||||||
|
}
|
||||||
|
header += "};";
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
|
||||||
|
@ -111,17 +163,20 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||||
case Stage::VertexA:
|
case Stage::VertexA:
|
||||||
case Stage::VertexB:
|
case Stage::VertexB:
|
||||||
stage_name = "vs";
|
stage_name = "vs";
|
||||||
// TODO: add only what's used by the shader
|
|
||||||
header +=
|
|
||||||
"out gl_PerVertex {vec4 gl_Position;float gl_PointSize;float gl_ClipDistance[];};";
|
|
||||||
break;
|
break;
|
||||||
case Stage::TessellationControl:
|
case Stage::TessellationControl:
|
||||||
|
stage_name = "tsc";
|
||||||
|
header += fmt::format("layout(vertices={})out;\n", program.invocations);
|
||||||
|
break;
|
||||||
case Stage::TessellationEval:
|
case Stage::TessellationEval:
|
||||||
stage_name = "ts";
|
stage_name = "tse";
|
||||||
|
header += fmt::format("layout({},{},{})in;\n", GetTessMode(runtime_info.tess_primitive),
|
||||||
|
GetTessSpacing(runtime_info.tess_spacing),
|
||||||
|
runtime_info.tess_clockwise ? "cw" : "ccw");
|
||||||
break;
|
break;
|
||||||
case Stage::Geometry:
|
case Stage::Geometry:
|
||||||
stage_name = "gs";
|
stage_name = "gs";
|
||||||
header += fmt::format("layout({})in;layout({}, max_vertices={})out;\n",
|
header += fmt::format("layout({})in;layout({},max_vertices={})out;\n",
|
||||||
InputPrimitive(runtime_info.input_topology),
|
InputPrimitive(runtime_info.input_topology),
|
||||||
OutputPrimitive(program.output_topology), program.output_vertices);
|
OutputPrimitive(program.output_topology), program.output_vertices);
|
||||||
break;
|
break;
|
||||||
|
@ -135,12 +190,23 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||||
program.workgroup_size[2]);
|
program.workgroup_size[2]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
SetupOutPerVertex(stage, info, header);
|
||||||
for (size_t index = 0; index < info.input_generics.size(); ++index) {
|
for (size_t index = 0; index < info.input_generics.size(); ++index) {
|
||||||
const auto& generic{info.input_generics[index]};
|
const auto& generic{info.input_generics[index]};
|
||||||
if (generic.used) {
|
if (generic.used) {
|
||||||
header +=
|
header += fmt::format("layout(location={}){} in vec4 in_attr{}{};", index,
|
||||||
fmt::format("layout(location={}){} in vec4 in_attr{}{};", index,
|
InterpDecorator(generic.interpolation), index,
|
||||||
InterpDecorator(generic.interpolation), index, ArrayDecorator(stage));
|
InputArrayDecorator(stage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t index = 0; index < info.uses_patches.size(); ++index) {
|
||||||
|
if (!info.uses_patches[index]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (stage == Stage::TessellationControl) {
|
||||||
|
header += fmt::format("layout(location={})patch out vec4 patch{};", index, index);
|
||||||
|
} else {
|
||||||
|
header += fmt::format("layout(location={})patch in vec4 patch{};", index, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
|
for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
|
||||||
|
@ -151,8 +217,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < info.stores_generics.size(); ++index) {
|
for (size_t index = 0; index < info.stores_generics.size(); ++index) {
|
||||||
// TODO: Properly resolve attribute issues
|
// TODO: Properly resolve attribute issues
|
||||||
const auto declaration{
|
const auto declaration{fmt::format("layout(location={}) out vec4 out_attr{}{};", index,
|
||||||
fmt::format("layout(location={}) out vec4 out_attr{};", index, index)};
|
index, OutputDecorator(stage, program.invocations))};
|
||||||
if (info.stores_generics[index] || stage == Stage::VertexA || stage == Stage::VertexB) {
|
if (info.stores_generics[index] || stage == Stage::VertexA || stage == Stage::VertexB) {
|
||||||
header += declaration;
|
header += declaration;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,24 @@ bool IsInputArray(Stage stage) {
|
||||||
stage == Stage::TessellationEval;
|
stage == Stage::TessellationEval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VertexIndex(EmitContext& ctx, std::string_view vertex) {
|
std::string InputVertexIndex(EmitContext& ctx, std::string_view vertex) {
|
||||||
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsOutputArray(Stage stage) {
|
||||||
|
return stage == Stage::Geometry || stage == Stage::TessellationControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OutputVertexIndex(EmitContext& ctx, std::string_view vertex) {
|
||||||
|
switch (ctx.stage) {
|
||||||
|
case Stage::Geometry:
|
||||||
|
return fmt::format("[{}]", vertex);
|
||||||
|
case Stage::TessellationControl:
|
||||||
|
return "[gl_InvocationID]";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void EmitGetCbufU8([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitGetCbufU8([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
|
@ -132,12 +147,12 @@ void EmitGetCbufU32x2(EmitContext& ctx, IR::Inst& inst, const IR::Value& binding
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
||||||
[[maybe_unused]] std::string_view vertex) {
|
std::string_view vertex) {
|
||||||
const u32 element{static_cast<u32>(attr) % 4};
|
const u32 element{static_cast<u32>(attr) % 4};
|
||||||
const char swizzle{"xyzw"[element]};
|
const char swizzle{"xyzw"[element]};
|
||||||
if (IR::IsGeneric(attr)) {
|
if (IR::IsGeneric(attr)) {
|
||||||
const u32 index{IR::GenericAttributeIndex(attr)};
|
const u32 index{IR::GenericAttributeIndex(attr)};
|
||||||
ctx.AddF32("{}=in_attr{}{}.{};", inst, index, VertexIndex(ctx, vertex), swizzle);
|
ctx.AddF32("{}=in_attr{}{}.{};", inst, index, InputVertexIndex(ctx, vertex), swizzle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
|
@ -150,6 +165,10 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
||||||
case Stage::VertexB:
|
case Stage::VertexB:
|
||||||
ctx.AddF32("{}=gl_Position.{};", inst, swizzle);
|
ctx.AddF32("{}=gl_Position.{};", inst, swizzle);
|
||||||
break;
|
break;
|
||||||
|
case Stage::TessellationEval:
|
||||||
|
ctx.AddF32("{}=gl_TessCoord.{};", inst, swizzle);
|
||||||
|
break;
|
||||||
|
case Stage::TessellationControl:
|
||||||
case Stage::Geometry:
|
case Stage::Geometry:
|
||||||
ctx.AddF32("{}=gl_in[{}].gl_Position.{};", inst, vertex, swizzle);
|
ctx.AddF32("{}=gl_in[{}].gl_Position.{};", inst, vertex, swizzle);
|
||||||
break;
|
break;
|
||||||
|
@ -173,6 +192,10 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
||||||
case IR::Attribute::FrontFace:
|
case IR::Attribute::FrontFace:
|
||||||
ctx.AddF32("{}=intBitsToFloat(gl_FrontFacing?-1:0);", inst);
|
ctx.AddF32("{}=intBitsToFloat(gl_FrontFacing?-1:0);", inst);
|
||||||
break;
|
break;
|
||||||
|
case IR::Attribute::TessellationEvaluationPointU:
|
||||||
|
case IR::Attribute::TessellationEvaluationPointV:
|
||||||
|
ctx.AddF32("{}=gl_TessCoord.{};", inst, swizzle);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fmt::print("Get attribute {}", attr);
|
fmt::print("Get attribute {}", attr);
|
||||||
throw NotImplementedException("Get attribute {}", attr);
|
throw NotImplementedException("Get attribute {}", attr);
|
||||||
|
@ -185,7 +208,7 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
||||||
const char swizzle{"xyzw"[element]};
|
const char swizzle{"xyzw"[element]};
|
||||||
if (IR::IsGeneric(attr)) {
|
if (IR::IsGeneric(attr)) {
|
||||||
const u32 index{IR::GenericAttributeIndex(attr)};
|
const u32 index{IR::GenericAttributeIndex(attr)};
|
||||||
ctx.Add("out_attr{}.{}={};", index, swizzle, value);
|
ctx.Add("out_attr{}{}.{}={};", index, OutputVertexIndex(ctx, vertex), swizzle, value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
|
@ -219,6 +242,44 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitGetPatch([[maybe_unused]] EmitContext& ctx, IR::Inst& inst,
|
||||||
|
[[maybe_unused]] IR::Patch patch) {
|
||||||
|
if (!IR::IsGeneric(patch)) {
|
||||||
|
throw NotImplementedException("Non-generic patch load");
|
||||||
|
}
|
||||||
|
const u32 index{IR::GenericPatchIndex(patch)};
|
||||||
|
const u32 element{IR::GenericPatchElement(patch)};
|
||||||
|
const char swizzle{"xyzw"[element]};
|
||||||
|
ctx.AddF32("{}=patch{}.{};", inst, index, swizzle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitSetPatch(EmitContext& ctx, IR::Patch patch, std::string_view value) {
|
||||||
|
if (IR::IsGeneric(patch)) {
|
||||||
|
const u32 index{IR::GenericPatchIndex(patch)};
|
||||||
|
const u32 element{IR::GenericPatchElement(patch)};
|
||||||
|
ctx.Add("patch{}.{}={};", index, "xyzw"[element], value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (patch) {
|
||||||
|
case IR::Patch::TessellationLodLeft:
|
||||||
|
case IR::Patch::TessellationLodRight:
|
||||||
|
case IR::Patch::TessellationLodTop:
|
||||||
|
case IR::Patch::TessellationLodBottom: {
|
||||||
|
const u32 index{static_cast<u32>(patch) - u32(IR::Patch::TessellationLodLeft)};
|
||||||
|
ctx.Add("gl_TessLevelOuter[{}]={};", index, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::Patch::TessellationLodInteriorU:
|
||||||
|
ctx.Add("gl_TessLevelInner[0]={};", value);
|
||||||
|
break;
|
||||||
|
case IR::Patch::TessellationLodInteriorV:
|
||||||
|
ctx.Add("gl_TessLevelInner[1]={};", value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw NotImplementedException("Patch {}", patch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, std::string_view value) {
|
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, std::string_view value) {
|
||||||
const char swizzle{"xyzw"[component]};
|
const char swizzle{"xyzw"[component]};
|
||||||
ctx.Add("frag_color{}.{}={};", index, swizzle, value);
|
ctx.Add("frag_color{}.{}={};", index, swizzle, value);
|
||||||
|
|
|
@ -161,7 +161,7 @@ void EmitFPRecip64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
|
||||||
|
|
||||||
void EmitFPRecipSqrt32([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitFPRecipSqrt32([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
[[maybe_unused]] std::string_view value) {
|
[[maybe_unused]] std::string_view value) {
|
||||||
ctx.AddF32("{}=(1.0f)/sqrt({});", inst, value);
|
ctx.AddF32("{}=inversesqrt({});", inst, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitFPRecipSqrt64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
void EmitFPRecipSqrt64([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||||
|
|
|
@ -75,7 +75,7 @@ void EmitSetAttribute(EmitContext& ctx, IR::Attribute attr, std::string_view val
|
||||||
void EmitGetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view vertex);
|
void EmitGetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view vertex);
|
||||||
void EmitSetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view value,
|
void EmitSetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::string_view value,
|
||||||
std::string_view vertex);
|
std::string_view vertex);
|
||||||
void EmitGetPatch(EmitContext& ctx, IR::Patch patch);
|
void EmitGetPatch(EmitContext& ctx, IR::Inst& inst, IR::Patch patch);
|
||||||
void EmitSetPatch(EmitContext& ctx, IR::Patch patch, std::string_view value);
|
void EmitSetPatch(EmitContext& ctx, IR::Patch patch, std::string_view value);
|
||||||
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, std::string_view value);
|
void EmitSetFragColor(EmitContext& ctx, u32 index, u32 component, std::string_view value);
|
||||||
void EmitSetSampleMask(EmitContext& ctx, std::string_view value);
|
void EmitSetSampleMask(EmitContext& ctx, std::string_view value);
|
||||||
|
|
|
@ -151,14 +151,6 @@ void EmitSetAttributeIndexed(EmitContext& ctx, std::string_view offset, std::str
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitGetPatch(EmitContext& ctx, IR::Patch patch) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitSetPatch(EmitContext& ctx, IR::Patch patch, std::string_view value) {
|
|
||||||
NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmitSetSampleMask(EmitContext& ctx, std::string_view value) {
|
void EmitSetSampleMask(EmitContext& ctx, std::string_view value) {
|
||||||
NotImplemented();
|
NotImplemented();
|
||||||
}
|
}
|
||||||
|
@ -204,7 +196,7 @@ void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
|
||||||
NotImplemented();
|
ctx.AddU32("{}=uint(gl_InvocationID);", inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
|
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
|
||||||
|
|
Loading…
Reference in a new issue