mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-20 18:59:26 +02:00
[TEST] Add clipping distances to GS
This commit is contained in:
parent
faacc62b10
commit
8206c7abac
8 changed files with 121 additions and 29 deletions
|
|
@ -217,6 +217,22 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr,
|
|||
ctx.AddF32("{}={}{}.{};", inst, input_decorator, ctx.position_name, swizzle);
|
||||
break;
|
||||
}
|
||||
case IR::Attribute::ClipDistance0:
|
||||
case IR::Attribute::ClipDistance1:
|
||||
case IR::Attribute::ClipDistance2:
|
||||
case IR::Attribute::ClipDistance3:
|
||||
case IR::Attribute::ClipDistance4:
|
||||
case IR::Attribute::ClipDistance5:
|
||||
case IR::Attribute::ClipDistance6:
|
||||
case IR::Attribute::ClipDistance7: {
|
||||
const u32 index{static_cast<u32>(attr) - static_cast<u32>(IR::Attribute::ClipDistance0)};
|
||||
if (IsInputArray(ctx.stage)) {
|
||||
ctx.AddF32("{}=gl_in[{}].gl_ClipDistance[{}];", inst, vertex, index);
|
||||
} else {
|
||||
ctx.AddF32("{}=gl_ClipDistance[{}];", inst, index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IR::Attribute::PointSpriteS:
|
||||
case IR::Attribute::PointSpriteT:
|
||||
ctx.AddF32("{}=gl_PointCoord.{};", inst, swizzle);
|
||||
|
|
|
|||
|
|
@ -306,9 +306,12 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
|
|||
} else if (program.is_geometry_passthrough && !profile.support_geometry_shader_passthrough) {
|
||||
LOG_WARNING(Shader_GLSL, "Passthrough geometry program used but not supported");
|
||||
}
|
||||
header += fmt::format(
|
||||
"layout({},max_vertices={})out;in gl_PerVertex{{vec4 gl_Position;}}gl_in[];",
|
||||
OutputPrimitive(program.output_topology), program.output_vertices);
|
||||
header += fmt::format("layout({},max_vertices={})out;in gl_PerVertex{{vec4 gl_Position;",
|
||||
OutputPrimitive(program.output_topology), program.output_vertices);
|
||||
if (program.info.loads.ClipDistances()) {
|
||||
header += "float gl_ClipDistance[];";
|
||||
}
|
||||
header += "}gl_in[];";
|
||||
break;
|
||||
case Stage::Fragment:
|
||||
stage_name = "fs";
|
||||
|
|
|
|||
|
|
@ -367,6 +367,23 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) {
|
|||
return ctx.OpSelect(ctx.F32[1], ctx.OpLoad(ctx.U1, ctx.front_face),
|
||||
ctx.OpBitcast(ctx.F32[1], ctx.Const((std::numeric_limits<u32>::max)())),
|
||||
ctx.f32_zero_value);
|
||||
case IR::Attribute::ClipDistance0:
|
||||
case IR::Attribute::ClipDistance1:
|
||||
case IR::Attribute::ClipDistance2:
|
||||
case IR::Attribute::ClipDistance3:
|
||||
case IR::Attribute::ClipDistance4:
|
||||
case IR::Attribute::ClipDistance5:
|
||||
case IR::Attribute::ClipDistance6:
|
||||
case IR::Attribute::ClipDistance7: {
|
||||
const u32 base{static_cast<u32>(IR::Attribute::ClipDistance0)};
|
||||
const u32 index{static_cast<u32>(attr) - base};
|
||||
if (!ValidId(ctx.input_clip_distances) || index >= ctx.profile.max_user_clip_distances) {
|
||||
return ctx.Const(1.0f);
|
||||
}
|
||||
const Id pointer{
|
||||
AttrPointer(ctx, ctx.input_f32, vertex, ctx.input_clip_distances, ctx.Const(index))};
|
||||
return ctx.OpLoad(ctx.F32[1], pointer);
|
||||
}
|
||||
case IR::Attribute::PointSpriteS:
|
||||
return ctx.OpLoad(ctx.F32[1],
|
||||
ctx.OpAccessChain(ctx.input_f32, ctx.point_coord, ctx.u32_zero_value));
|
||||
|
|
|
|||
|
|
@ -1522,6 +1522,12 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (stage == Stage::Geometry && info.loads.ClipDistances() &&
|
||||
profile.max_user_clip_distances > 0) {
|
||||
const u32 used{(std::min)(profile.max_user_clip_distances, 8u)};
|
||||
const Id type{TypeArray(F32[1], Const(used))};
|
||||
input_clip_distances = DefineInput(*this, type, true, spv::BuiltIn::ClipDistance);
|
||||
}
|
||||
if (loads[IR::Attribute::InstanceId]) {
|
||||
if (profile.support_vertex_instance_id) {
|
||||
instance_id = DefineInput(*this, U32[1], true, spv::BuiltIn::InstanceId);
|
||||
|
|
|
|||
|
|
@ -285,6 +285,7 @@ public:
|
|||
Id point_coord{};
|
||||
Id tess_coord{};
|
||||
Id clip_distances{};
|
||||
Id input_clip_distances{};
|
||||
Id layer{};
|
||||
Id viewport_index{};
|
||||
Id viewport_mask{};
|
||||
|
|
|
|||
|
|
@ -178,6 +178,20 @@ struct PassthroughVertices {
|
|||
u32 stride;
|
||||
};
|
||||
|
||||
OutputTopology GetPassthroughTopology(InputTopology input_topology) {
|
||||
switch (input_topology) {
|
||||
case InputTopology::Points:
|
||||
return OutputTopology::PointList;
|
||||
case InputTopology::Lines:
|
||||
case InputTopology::LinesAdjacency:
|
||||
return OutputTopology::LineStrip;
|
||||
case InputTopology::Triangles:
|
||||
case InputTopology::TrianglesAdjacency:
|
||||
return OutputTopology::TriangleStrip;
|
||||
}
|
||||
return OutputTopology::TriangleStrip;
|
||||
}
|
||||
|
||||
PassthroughVertices GetPassthroughVertices(InputTopology input_topology) {
|
||||
switch (input_topology) {
|
||||
case InputTopology::Points:
|
||||
|
|
@ -239,6 +253,14 @@ void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program,
|
|||
copy_vec4(attr);
|
||||
}
|
||||
|
||||
for (u32 j = 0; j < 8; j++) {
|
||||
const IR::Attribute attr = IR::Attribute::ClipDistance0 + j;
|
||||
if (!passthrough_mask[attr]) {
|
||||
continue;
|
||||
}
|
||||
ir.SetAttribute(attr, ir.GetAttribute(attr, ir.Imm32(i)), ir.Imm32(0));
|
||||
}
|
||||
|
||||
if (passthrough_position) {
|
||||
// Assign position from input
|
||||
copy_vec4(IR::Attribute::PositionX);
|
||||
|
|
@ -304,6 +326,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
|||
}
|
||||
|
||||
if (!normalized_host_info.support_geometry_shader_passthrough) {
|
||||
program.output_topology = GetPassthroughTopology(input_topology);
|
||||
program.output_vertices = GetPassthroughVertices(input_topology).count;
|
||||
LowerGeometryPassthrough(program, normalized_host_info, input_topology);
|
||||
program.is_geometry_passthrough = false;
|
||||
|
|
|
|||
|
|
@ -55,22 +55,25 @@ using VideoCommon::LoadPipelines;
|
|||
using VideoCommon::SerializePipeline;
|
||||
using Context = ShaderContext::Context;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 18;
|
||||
constexpr u32 CACHE_VERSION = 19;
|
||||
|
||||
template <typename Container>
|
||||
auto MakeSpan(Container& container) {
|
||||
return std::span(container.data(), container.size());
|
||||
}
|
||||
|
||||
Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) {
|
||||
Shader::OutputTopology InputToOutputTopology(Shader::InputTopology topology) {
|
||||
switch (topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
case Shader::InputTopology::Points:
|
||||
return Shader::OutputTopology::PointList;
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
case Shader::InputTopology::Lines:
|
||||
case Shader::InputTopology::LinesAdjacency:
|
||||
return Shader::OutputTopology::LineStrip;
|
||||
default:
|
||||
case Shader::InputTopology::Triangles:
|
||||
case Shader::InputTopology::TrianglesAdjacency:
|
||||
return Shader::OutputTopology::TriangleStrip;
|
||||
}
|
||||
return Shader::OutputTopology::TriangleStrip;
|
||||
}
|
||||
|
||||
Shader::InputTopology MaxwellToInputTopology(Maxwell::PrimitiveTopology topology) {
|
||||
|
|
@ -92,6 +95,16 @@ Shader::InputTopology MaxwellToInputTopology(Maxwell::PrimitiveTopology topology
|
|||
}
|
||||
}
|
||||
|
||||
Shader::InputTopology GeometryInputTopology(const GraphicsPipelineKey& key) {
|
||||
if (key.unique_hashes[static_cast<size_t>(Maxwell::ShaderType::Tessellation)] == 0) {
|
||||
return MaxwellToInputTopology(key.gs_input_topology);
|
||||
}
|
||||
if (key.tessellation_primitive == Maxwell::Tessellation::DomainType::Isolines) {
|
||||
return Shader::InputTopology::Lines;
|
||||
}
|
||||
return Shader::InputTopology::Triangles;
|
||||
}
|
||||
|
||||
Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
|
||||
const Shader::IR::Program& program,
|
||||
const Shader::IR::Program* previous_program,
|
||||
|
|
@ -147,7 +160,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
info.input_topology = MaxwellToInputTopology(key.gs_input_topology);
|
||||
info.input_topology = GeometryInputTopology(key);
|
||||
info.glasm_use_storage_buffers = glasm_use_storage_buffers;
|
||||
return info;
|
||||
}
|
||||
|
|
@ -476,11 +489,10 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
|||
const bool is_emulated_stage = layer_source_program != nullptr
|
||||
&& index == u32(Maxwell::ShaderType::Geometry);
|
||||
if (key.unique_hashes[index] == 0 && is_emulated_stage) {
|
||||
auto topology = MaxwellToOutputTopology(key.gs_input_topology);
|
||||
programs[index] =
|
||||
GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
|
||||
*layer_source_program, topology,
|
||||
MaxwellToInputTopology(key.gs_input_topology));
|
||||
const auto input_topology = GeometryInputTopology(key);
|
||||
programs[index] = GenerateGeometryPassthrough(
|
||||
pools.inst, pools.block, host_info, *layer_source_program,
|
||||
InputToOutputTopology(input_topology), input_topology);
|
||||
continue;
|
||||
}
|
||||
if (key.unique_hashes[index] == 0) {
|
||||
|
|
@ -499,14 +511,14 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
|
|||
if (!uses_vertex_a || index != 1) {
|
||||
// Normal path
|
||||
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
|
||||
MaxwellToInputTopology(key.gs_input_topology));
|
||||
GeometryInputTopology(key));
|
||||
|
||||
total_storage_buffers += Shader::NumDescriptors(programs[index].info.storage_buffers_descriptors);
|
||||
} else {
|
||||
// VertexB path when VertexA is present.
|
||||
auto& program_va{programs[0]};
|
||||
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
|
||||
MaxwellToInputTopology(key.gs_input_topology))};
|
||||
GeometryInputTopology(key))};
|
||||
total_storage_buffers += Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors);
|
||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ using VideoCommon::FileEnvironment;
|
|||
using VideoCommon::GenericEnvironment;
|
||||
using VideoCommon::GraphicsEnvironment;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 21;
|
||||
constexpr u32 CACHE_VERSION = 22;
|
||||
constexpr size_t VULKAN_CACHE_FLUSH_PIPELINES = 128;
|
||||
constexpr size_t VULKAN_CACHE_FLUSH_MIN_SECONDS = 30;
|
||||
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
|
||||
|
|
@ -73,15 +73,18 @@ auto MakeSpan(Container& container) {
|
|||
return std::span(container.data(), container.size());
|
||||
}
|
||||
|
||||
Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topology) {
|
||||
Shader::OutputTopology InputToOutputTopology(Shader::InputTopology topology) {
|
||||
switch (topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
case Shader::InputTopology::Points:
|
||||
return Shader::OutputTopology::PointList;
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
case Shader::InputTopology::Lines:
|
||||
case Shader::InputTopology::LinesAdjacency:
|
||||
return Shader::OutputTopology::LineStrip;
|
||||
default:
|
||||
case Shader::InputTopology::Triangles:
|
||||
case Shader::InputTopology::TrianglesAdjacency:
|
||||
return Shader::OutputTopology::TriangleStrip;
|
||||
}
|
||||
return Shader::OutputTopology::TriangleStrip;
|
||||
}
|
||||
|
||||
Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp comparison) {
|
||||
|
|
@ -172,6 +175,18 @@ Shader::InputTopology MaxwellToInputTopology(Maxwell::PrimitiveTopology topology
|
|||
}
|
||||
}
|
||||
|
||||
Shader::InputTopology GeometryInputTopology(const GraphicsPipelineCacheKey& key) {
|
||||
if (key.unique_hashes[static_cast<size_t>(Maxwell::ShaderType::Tessellation)] == 0) {
|
||||
return MaxwellToInputTopology(key.state.topology);
|
||||
}
|
||||
const auto domain{
|
||||
static_cast<Maxwell::Tessellation::DomainType>(key.state.tessellation_primitive.Value())};
|
||||
if (domain == Maxwell::Tessellation::DomainType::Isolines) {
|
||||
return Shader::InputTopology::Lines;
|
||||
}
|
||||
return Shader::InputTopology::Triangles;
|
||||
}
|
||||
|
||||
Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> programs,
|
||||
const GraphicsPipelineCacheKey& key,
|
||||
const Shader::IR::Program& program,
|
||||
|
|
@ -290,7 +305,7 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
|||
default:
|
||||
break;
|
||||
}
|
||||
info.input_topology = MaxwellToInputTopology(key.state.topology);
|
||||
info.input_topology = GeometryInputTopology(key);
|
||||
info.force_early_z = key.state.early_z != 0;
|
||||
info.y_negate = key.state.y_negate != 0;
|
||||
return info;
|
||||
|
|
@ -786,11 +801,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||
const bool is_emulated_stage = layer_source_program != nullptr &&
|
||||
index == static_cast<u32>(Maxwell::ShaderType::Geometry);
|
||||
if (key.unique_hashes[index] == 0 && is_emulated_stage) {
|
||||
auto topology = MaxwellToOutputTopology(key.state.topology);
|
||||
programs[index] =
|
||||
GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
|
||||
*layer_source_program, topology,
|
||||
MaxwellToInputTopology(key.state.topology));
|
||||
const auto input_topology = GeometryInputTopology(key);
|
||||
programs[index] = GenerateGeometryPassthrough(
|
||||
pools.inst, pools.block, host_info, *layer_source_program,
|
||||
InputToOutputTopology(input_topology), input_topology);
|
||||
continue;
|
||||
}
|
||||
if (key.unique_hashes[index] == 0) {
|
||||
|
|
@ -804,12 +818,12 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
|||
if (!uses_vertex_a || index != 1) {
|
||||
// Normal path
|
||||
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
|
||||
MaxwellToInputTopology(key.state.topology));
|
||||
GeometryInputTopology(key));
|
||||
} else {
|
||||
// VertexB path when VertexA is present.
|
||||
auto& program_va{programs[0]};
|
||||
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
|
||||
MaxwellToInputTopology(key.state.topology))};
|
||||
GeometryInputTopology(key))};
|
||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue