opengl: remove hw geometry shader related stuff
This commit is contained in:
parent
1cf75e55c2
commit
dd3ba7bd21
|
@ -104,8 +104,6 @@ RasterizerOpenGL::RasterizerOpenGL(Frontend::EmuWindow& window)
|
||||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
||||||
uniform_size_aligned_vs =
|
uniform_size_aligned_vs =
|
||||||
Common::AlignUp<std::size_t>(sizeof(VSUniformData), uniform_buffer_alignment);
|
Common::AlignUp<std::size_t>(sizeof(VSUniformData), uniform_buffer_alignment);
|
||||||
uniform_size_aligned_gs =
|
|
||||||
Common::AlignUp<std::size_t>(sizeof(GSUniformData), uniform_buffer_alignment);
|
|
||||||
uniform_size_aligned_fs =
|
uniform_size_aligned_fs =
|
||||||
Common::AlignUp<std::size_t>(sizeof(UniformData), uniform_buffer_alignment);
|
Common::AlignUp<std::size_t>(sizeof(UniformData), uniform_buffer_alignment);
|
||||||
|
|
||||||
|
@ -392,8 +390,7 @@ bool RasterizerOpenGL::SetupGeometryShader() {
|
||||||
shader_program_manager->UseFixedGeometryShader(gs_config);
|
shader_program_manager->UseFixedGeometryShader(gs_config);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
PicaGSConfig gs_config(regs, Pica::g_state.gs);
|
LOG_ERROR(Render_OpenGL, "Accelerate draw doesn't support geometry shader");
|
||||||
return shader_program_manager->UseProgrammableGeometryShader(gs_config, Pica::g_state.gs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,25 +414,8 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
|
||||||
return Draw(true, is_indexed);
|
return Draw(true, is_indexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLenum GetCurrentPrimitiveMode(bool use_gs) {
|
static GLenum GetCurrentPrimitiveMode() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
if (use_gs) {
|
|
||||||
switch ((regs.gs.max_input_attribute_index + 1) /
|
|
||||||
(regs.pipeline.vs_outmap_total_minus_1_a + 1)) {
|
|
||||||
case 1:
|
|
||||||
return GL_POINTS;
|
|
||||||
case 2:
|
|
||||||
return GL_LINES;
|
|
||||||
case 4:
|
|
||||||
return GL_LINES_ADJACENCY;
|
|
||||||
case 3:
|
|
||||||
return GL_TRIANGLES;
|
|
||||||
case 6:
|
|
||||||
return GL_TRIANGLES_ADJACENCY;
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (regs.pipeline.triangle_topology) {
|
switch (regs.pipeline.triangle_topology) {
|
||||||
case Pica::PipelineRegs::TriangleTopology::Shader:
|
case Pica::PipelineRegs::TriangleTopology::Shader:
|
||||||
case Pica::PipelineRegs::TriangleTopology::List:
|
case Pica::PipelineRegs::TriangleTopology::List:
|
||||||
|
@ -447,12 +427,11 @@ static GLenum GetCurrentPrimitiveMode(bool use_gs) {
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed, bool use_gs) {
|
bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed) {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
GLenum primitive_mode = GetCurrentPrimitiveMode(use_gs);
|
GLenum primitive_mode = GetCurrentPrimitiveMode();
|
||||||
|
|
||||||
auto [vs_input_index_min, vs_input_index_max, vs_input_size] = AnalyzeVertexArray(is_indexed);
|
auto [vs_input_index_min, vs_input_index_max, vs_input_size] = AnalyzeVertexArray(is_indexed);
|
||||||
|
|
||||||
|
@ -787,8 +766,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
||||||
SyncAndUploadLUTs();
|
SyncAndUploadLUTs();
|
||||||
|
|
||||||
// Sync the uniform data
|
// Sync the uniform data
|
||||||
const bool use_gs = regs.pipeline.use_gs == Pica::PipelineRegs::UseGS::Yes;
|
UploadUniforms(accelerate);
|
||||||
UploadUniforms(accelerate, use_gs);
|
|
||||||
|
|
||||||
// Viewport can have negative offsets or larger
|
// Viewport can have negative offsets or larger
|
||||||
// dimensions than our framebuffer sub-rect.
|
// dimensions than our framebuffer sub-rect.
|
||||||
|
@ -804,7 +782,7 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
||||||
// Draw the vertex batch
|
// Draw the vertex batch
|
||||||
bool succeeded = true;
|
bool succeeded = true;
|
||||||
if (accelerate) {
|
if (accelerate) {
|
||||||
succeeded = AccelerateDrawBatchInternal(is_indexed, use_gs);
|
succeeded = AccelerateDrawBatchInternal(is_indexed);
|
||||||
} else {
|
} else {
|
||||||
state.draw.vertex_array = sw_vao.handle;
|
state.draw.vertex_array = sw_vao.handle;
|
||||||
state.draw.vertex_buffer = vertex_buffer.GetHandle();
|
state.draw.vertex_buffer = vertex_buffer.GetHandle();
|
||||||
|
@ -2119,21 +2097,19 @@ void RasterizerOpenGL::SyncAndUploadLUTs() {
|
||||||
texture_buffer.Unmap(bytes_used);
|
texture_buffer.Unmap(bytes_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::UploadUniforms(bool accelerate_draw, bool use_gs) {
|
void RasterizerOpenGL::UploadUniforms(bool accelerate_draw) {
|
||||||
// glBindBufferRange below also changes the generic buffer binding point, so we sync the state
|
// glBindBufferRange below also changes the generic buffer binding point, so we sync the state
|
||||||
// first
|
// first
|
||||||
state.draw.uniform_buffer = uniform_buffer.GetHandle();
|
state.draw.uniform_buffer = uniform_buffer.GetHandle();
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
bool sync_vs = accelerate_draw;
|
bool sync_vs = accelerate_draw;
|
||||||
bool sync_gs = accelerate_draw && use_gs;
|
|
||||||
bool sync_fs = uniform_block_data.dirty;
|
bool sync_fs = uniform_block_data.dirty;
|
||||||
|
|
||||||
if (!sync_vs && !sync_gs && !sync_fs)
|
if (!sync_vs && !sync_fs)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::size_t uniform_size =
|
std::size_t uniform_size = uniform_size_aligned_vs + uniform_size_aligned_fs;
|
||||||
uniform_size_aligned_vs + uniform_size_aligned_gs + uniform_size_aligned_fs;
|
|
||||||
std::size_t used_bytes = 0;
|
std::size_t used_bytes = 0;
|
||||||
u8* uniforms;
|
u8* uniforms;
|
||||||
GLintptr offset;
|
GLintptr offset;
|
||||||
|
@ -2150,15 +2126,6 @@ void RasterizerOpenGL::UploadUniforms(bool accelerate_draw, bool use_gs) {
|
||||||
used_bytes += uniform_size_aligned_vs;
|
used_bytes += uniform_size_aligned_vs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync_gs) {
|
|
||||||
GSUniformData gs_uniforms;
|
|
||||||
gs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.gs, Pica::g_state.gs);
|
|
||||||
std::memcpy(uniforms + used_bytes, &gs_uniforms, sizeof(gs_uniforms));
|
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::GS),
|
|
||||||
uniform_buffer.GetHandle(), offset + used_bytes, sizeof(GSUniformData));
|
|
||||||
used_bytes += uniform_size_aligned_gs;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sync_fs || invalidate) {
|
if (sync_fs || invalidate) {
|
||||||
std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData));
|
std::memcpy(uniforms + used_bytes, &uniform_block_data.data, sizeof(UniformData));
|
||||||
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::Common),
|
glBindBufferRange(GL_UNIFORM_BUFFER, static_cast<GLuint>(UniformBindings::Common),
|
||||||
|
|
|
@ -231,13 +231,13 @@ private:
|
||||||
void SyncAndUploadLUTs();
|
void SyncAndUploadLUTs();
|
||||||
|
|
||||||
/// Upload the uniform blocks to the uniform buffer object
|
/// Upload the uniform blocks to the uniform buffer object
|
||||||
void UploadUniforms(bool accelerate_draw, bool use_gs);
|
void UploadUniforms(bool accelerate_draw);
|
||||||
|
|
||||||
/// Generic draw function for DrawTriangles and AccelerateDrawBatch
|
/// Generic draw function for DrawTriangles and AccelerateDrawBatch
|
||||||
bool Draw(bool accelerate, bool is_indexed);
|
bool Draw(bool accelerate, bool is_indexed);
|
||||||
|
|
||||||
/// Internal implementation for AccelerateDrawBatch
|
/// Internal implementation for AccelerateDrawBatch
|
||||||
bool AccelerateDrawBatchInternal(bool is_indexed, bool use_gs);
|
bool AccelerateDrawBatchInternal(bool is_indexed);
|
||||||
|
|
||||||
struct VertexArrayInfo {
|
struct VertexArrayInfo {
|
||||||
u32 vs_input_index_min;
|
u32 vs_input_index_min;
|
||||||
|
@ -304,7 +304,6 @@ private:
|
||||||
OGLFramebuffer framebuffer;
|
OGLFramebuffer framebuffer;
|
||||||
GLint uniform_buffer_alignment;
|
GLint uniform_buffer_alignment;
|
||||||
std::size_t uniform_size_aligned_vs;
|
std::size_t uniform_size_aligned_vs;
|
||||||
std::size_t uniform_size_aligned_gs;
|
|
||||||
std::size_t uniform_size_aligned_fs;
|
std::size_t uniform_size_aligned_fs;
|
||||||
|
|
||||||
SamplerInfo texture_cube_sampler;
|
SamplerInfo texture_cube_sampler;
|
||||||
|
|
|
@ -249,10 +249,10 @@ public:
|
||||||
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
|
GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
|
||||||
const SwizzleData& swizzle_data, u32 main_offset,
|
const SwizzleData& swizzle_data, u32 main_offset,
|
||||||
const RegGetter& inputreg_getter, const RegGetter& outputreg_getter,
|
const RegGetter& inputreg_getter, const RegGetter& outputreg_getter,
|
||||||
bool sanitize_mul, bool is_gs)
|
bool sanitize_mul)
|
||||||
: subroutines(subroutines), program_code(program_code), swizzle_data(swizzle_data),
|
: subroutines(subroutines), program_code(program_code), swizzle_data(swizzle_data),
|
||||||
main_offset(main_offset), inputreg_getter(inputreg_getter),
|
main_offset(main_offset), inputreg_getter(inputreg_getter),
|
||||||
outputreg_getter(outputreg_getter), sanitize_mul(sanitize_mul), is_gs(is_gs) {
|
outputreg_getter(outputreg_getter), sanitize_mul(sanitize_mul) {
|
||||||
|
|
||||||
Generate();
|
Generate();
|
||||||
}
|
}
|
||||||
|
@ -342,13 +342,6 @@ private:
|
||||||
|
|
||||||
/// Generates code representing a bool uniform
|
/// Generates code representing a bool uniform
|
||||||
std::string GetUniformBool(u32 index) const {
|
std::string GetUniformBool(u32 index) const {
|
||||||
if (is_gs && index == 15) {
|
|
||||||
// In PICA geometry shader, b15 is set to true after every geometry shader invocation.
|
|
||||||
// Accessing b15 usually indicates that the program relies on register value
|
|
||||||
// preservation across invocation (and therefore it uses b15 to determine whether to
|
|
||||||
// initialize the registers), which cannot be implemented in GL shaders.
|
|
||||||
throw DecompileFail("b15 access in geometry shader");
|
|
||||||
}
|
|
||||||
return "uniforms.b[" + std::to_string(index) + "]";
|
return "uniforms.b[" + std::to_string(index) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,22 +744,10 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpCode::Id::EMIT: {
|
case OpCode::Id::EMIT:
|
||||||
if (is_gs) {
|
case OpCode::Id::SETEMIT:
|
||||||
shader.AddLine("emit();");
|
LOG_ERROR(HW_GPU, "Geometry shader operation detected in vertex shader");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case OpCode::Id::SETEMIT: {
|
|
||||||
if (is_gs) {
|
|
||||||
ASSERT(instr.setemit.vertex_id < 3);
|
|
||||||
shader.AddLine("setemit(" + std::to_string(instr.setemit.vertex_id) + "u, " +
|
|
||||||
((instr.setemit.prim_emit != 0) ? "true" : "false") + ", " +
|
|
||||||
((instr.setemit.winding != 0) ? "true" : "false") + ");");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
LOG_ERROR(HW_GPU, "Unhandled instruction: 0x{:02x} ({}): 0x{:08x}",
|
LOG_ERROR(HW_GPU, "Unhandled instruction: 0x{:02x} ({}): 0x{:08x}",
|
||||||
|
@ -890,7 +871,6 @@ private:
|
||||||
const RegGetter& inputreg_getter;
|
const RegGetter& inputreg_getter;
|
||||||
const RegGetter& outputreg_getter;
|
const RegGetter& outputreg_getter;
|
||||||
const bool sanitize_mul;
|
const bool sanitize_mul;
|
||||||
const bool is_gs;
|
|
||||||
|
|
||||||
ShaderWriter shader;
|
ShaderWriter shader;
|
||||||
};
|
};
|
||||||
|
@ -911,13 +891,12 @@ bool exec_shader();
|
||||||
std::optional<std::string> DecompileProgram(const ProgramCode& program_code,
|
std::optional<std::string> DecompileProgram(const ProgramCode& program_code,
|
||||||
const SwizzleData& swizzle_data, u32 main_offset,
|
const SwizzleData& swizzle_data, u32 main_offset,
|
||||||
const RegGetter& inputreg_getter,
|
const RegGetter& inputreg_getter,
|
||||||
const RegGetter& outputreg_getter, bool sanitize_mul,
|
const RegGetter& outputreg_getter, bool sanitize_mul) {
|
||||||
bool is_gs) {
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines();
|
auto subroutines = ControlFlowAnalyzer(program_code, main_offset).MoveSubroutines();
|
||||||
GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset,
|
GLSLGenerator generator(subroutines, program_code, swizzle_data, main_offset,
|
||||||
inputreg_getter, outputreg_getter, sanitize_mul, is_gs);
|
inputreg_getter, outputreg_getter, sanitize_mul);
|
||||||
return generator.MoveShaderCode();
|
return generator.MoveShaderCode();
|
||||||
} catch (const DecompileFail& exception) {
|
} catch (const DecompileFail& exception) {
|
||||||
LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
LOG_INFO(HW_GPU, "Shader decompilation failed: {}", exception.what());
|
||||||
|
|
|
@ -20,7 +20,6 @@ std::string GetCommonDeclarations();
|
||||||
std::optional<std::string> DecompileProgram(const ProgramCode& program_code,
|
std::optional<std::string> DecompileProgram(const ProgramCode& program_code,
|
||||||
const SwizzleData& swizzle_data, u32 main_offset,
|
const SwizzleData& swizzle_data, u32 main_offset,
|
||||||
const RegGetter& inputreg_getter,
|
const RegGetter& inputreg_getter,
|
||||||
const RegGetter& outputreg_getter, bool sanitize_mul,
|
const RegGetter& outputreg_getter, bool sanitize_mul);
|
||||||
bool is_gs);
|
|
||||||
|
|
||||||
} // namespace OpenGL::ShaderDecompiler
|
} // namespace OpenGL::ShaderDecompiler
|
||||||
|
|
|
@ -283,22 +283,6 @@ void PicaGSConfigCommonRaw::Init(const Pica::Regs& regs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PicaGSConfigRaw::Init(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup) {
|
|
||||||
PicaShaderConfigCommon::Init(regs.gs, setup);
|
|
||||||
PicaGSConfigCommonRaw::Init(regs);
|
|
||||||
|
|
||||||
num_inputs = regs.gs.max_input_attribute_index + 1;
|
|
||||||
input_map.fill(16);
|
|
||||||
|
|
||||||
for (u32 attr = 0; attr < num_inputs; ++attr) {
|
|
||||||
input_map[regs.gs.GetRegisterForAttribute(attr)] = attr;
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes_per_vertex = regs.pipeline.vs_outmap_total_minus_1_a + 1;
|
|
||||||
|
|
||||||
gs_output_attributes = num_outputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
|
/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
|
||||||
static bool IsPassThroughTevStage(const TevStageConfig& stage) {
|
static bool IsPassThroughTevStage(const TevStageConfig& stage) {
|
||||||
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
||||||
|
@ -1675,7 +1659,7 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup&
|
||||||
|
|
||||||
auto program_source_opt = ShaderDecompiler::DecompileProgram(
|
auto program_source_opt = ShaderDecompiler::DecompileProgram(
|
||||||
setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg,
|
setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg,
|
||||||
get_output_reg, config.state.sanitize_mul, false);
|
get_output_reg, config.state.sanitize_mul);
|
||||||
|
|
||||||
if (!program_source_opt)
|
if (!program_source_opt)
|
||||||
return {};
|
return {};
|
||||||
|
@ -1727,11 +1711,6 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool s
|
||||||
}
|
}
|
||||||
|
|
||||||
out += R"(
|
out += R"(
|
||||||
#define uniforms gs_uniforms
|
|
||||||
layout (std140) uniform gs_config {
|
|
||||||
pica_uniforms uniforms;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
)";
|
)";
|
||||||
out += " vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n";
|
out += " vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n";
|
||||||
|
@ -1838,116 +1817,4 @@ void main() {
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup,
|
|
||||||
const PicaGSConfig& config,
|
|
||||||
bool separable_shader) {
|
|
||||||
std::string out = "";
|
|
||||||
if (separable_shader) {
|
|
||||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.state.num_inputs % config.state.attributes_per_vertex != 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
switch (config.state.num_inputs / config.state.attributes_per_vertex) {
|
|
||||||
case 1:
|
|
||||||
out += "layout(points) in;\n";
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
out += "layout(lines) in;\n";
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
out += "layout(lines_adjacency) in;\n";
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
out += "layout(triangles) in;\n";
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
out += "layout(triangles_adjacency) in;\n";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
out += "layout(triangle_strip, max_vertices = 30) out;\n\n";
|
|
||||||
|
|
||||||
out += GetGSCommonSource(config.state, separable_shader);
|
|
||||||
|
|
||||||
auto get_input_reg = [&](u32 reg) -> std::string {
|
|
||||||
ASSERT(reg < 16);
|
|
||||||
u32 attr = config.state.input_map[reg];
|
|
||||||
if (attr < config.state.num_inputs) {
|
|
||||||
return "vs_out_attr" + std::to_string(attr % config.state.attributes_per_vertex) + "[" +
|
|
||||||
std::to_string(attr / config.state.attributes_per_vertex) + "]";
|
|
||||||
}
|
|
||||||
return "vec4(0.0, 0.0, 0.0, 1.0)";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto get_output_reg = [&](u32 reg) -> std::string {
|
|
||||||
ASSERT(reg < 16);
|
|
||||||
if (config.state.output_map[reg] < config.state.num_outputs) {
|
|
||||||
return "output_buffer.attributes[" + std::to_string(config.state.output_map[reg]) + "]";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto program_source_opt = ShaderDecompiler::DecompileProgram(
|
|
||||||
setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg,
|
|
||||||
get_output_reg, config.state.sanitize_mul, true);
|
|
||||||
|
|
||||||
if (!program_source_opt)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
std::string& program_source = *program_source_opt;
|
|
||||||
|
|
||||||
out += R"(
|
|
||||||
Vertex output_buffer;
|
|
||||||
Vertex prim_buffer[3];
|
|
||||||
uint vertex_id = 0u;
|
|
||||||
bool prim_emit = false;
|
|
||||||
bool winding = false;
|
|
||||||
|
|
||||||
void setemit(uint vertex_id_, bool prim_emit_, bool winding_);
|
|
||||||
void emit();
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
)";
|
|
||||||
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
|
||||||
out +=
|
|
||||||
" output_buffer.attributes[" + std::to_string(i) + "] = vec4(0.0, 0.0, 0.0, 1.0);\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute shader
|
|
||||||
out += "\n exec_shader();\n\n";
|
|
||||||
|
|
||||||
out += "}\n\n";
|
|
||||||
|
|
||||||
// Put the definition of setemit and emit after main to avoid spurious warning about
|
|
||||||
// uninitialized output_buffer in some drivers
|
|
||||||
out += R"(
|
|
||||||
void setemit(uint vertex_id_, bool prim_emit_, bool winding_) {
|
|
||||||
vertex_id = vertex_id_;
|
|
||||||
prim_emit = prim_emit_;
|
|
||||||
winding = winding_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void emit() {
|
|
||||||
prim_buffer[vertex_id] = output_buffer;
|
|
||||||
|
|
||||||
if (prim_emit) {
|
|
||||||
if (winding) {
|
|
||||||
EmitPrim(prim_buffer[1], prim_buffer[0], prim_buffer[2]);
|
|
||||||
winding = false;
|
|
||||||
} else {
|
|
||||||
EmitPrim(prim_buffer[0], prim_buffer[1], prim_buffer[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
out += program_source;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -195,26 +195,6 @@ struct PicaFixedGSConfig : Common::HashableStruct<PicaGSConfigCommonRaw> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PicaGSConfigRaw : PicaShaderConfigCommon, PicaGSConfigCommonRaw {
|
|
||||||
void Init(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup);
|
|
||||||
|
|
||||||
u32 num_inputs;
|
|
||||||
u32 attributes_per_vertex;
|
|
||||||
|
|
||||||
// input_map[input register index] -> input attribute index
|
|
||||||
std::array<u32, 16> input_map;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This struct contains information to identify a GL geometry shader generated from PICA geometry
|
|
||||||
* shader.
|
|
||||||
*/
|
|
||||||
struct PicaGSConfig : Common::HashableStruct<PicaGSConfigRaw> {
|
|
||||||
explicit PicaGSConfig(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setups) {
|
|
||||||
state.Init(regs, setups);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the GLSL vertex shader program source code that accepts vertices from software shader
|
* Generates the GLSL vertex shader program source code that accepts vertices from software shader
|
||||||
* and directly passes them to the fragment shader.
|
* and directly passes them to the fragment shader.
|
||||||
|
@ -236,15 +216,6 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup&
|
||||||
*/
|
*/
|
||||||
std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader);
|
std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader);
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the GLSL geometry shader program source code for the given GS program and its
|
|
||||||
* configuration
|
|
||||||
* @returns String of the shader source code; boost::none on failure
|
|
||||||
*/
|
|
||||||
std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup,
|
|
||||||
const PicaGSConfig& config,
|
|
||||||
bool separable_shader);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the GLSL fragment shader program source code for the current Pica state
|
* Generates the GLSL fragment shader program source code for the current Pica state
|
||||||
* @param config ShaderCacheKey object generated for the current Pica state, used for the shader
|
* @param config ShaderCacheKey object generated for the current Pica state, used for the shader
|
||||||
|
@ -277,11 +248,4 @@ struct hash<OpenGL::PicaFixedGSConfig> {
|
||||||
return k.Hash();
|
return k.Hash();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
struct hash<OpenGL::PicaGSConfig> {
|
|
||||||
std::size_t operator()(const OpenGL::PicaGSConfig& k) const {
|
|
||||||
return k.Hash();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
|
@ -27,7 +27,6 @@ static void SetShaderUniformBlockBindings(GLuint shader) {
|
||||||
SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common,
|
SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common,
|
||||||
sizeof(UniformData));
|
sizeof(UniformData));
|
||||||
SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData));
|
SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS, sizeof(VSUniformData));
|
||||||
SetShaderUniformBlockBinding(shader, "gs_config", UniformBindings::GS, sizeof(GSUniformData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetShaderSamplerBinding(GLuint shader, const char* name,
|
static void SetShaderSamplerBinding(GLuint shader, const char* name,
|
||||||
|
@ -205,9 +204,6 @@ private:
|
||||||
using ProgrammableVertexShaders =
|
using ProgrammableVertexShaders =
|
||||||
ShaderDoubleCache<PicaVSConfig, &GenerateVertexShader, GL_VERTEX_SHADER>;
|
ShaderDoubleCache<PicaVSConfig, &GenerateVertexShader, GL_VERTEX_SHADER>;
|
||||||
|
|
||||||
using ProgrammableGeometryShaders =
|
|
||||||
ShaderDoubleCache<PicaGSConfig, &GenerateGeometryShader, GL_GEOMETRY_SHADER>;
|
|
||||||
|
|
||||||
using FixedGeometryShaders =
|
using FixedGeometryShaders =
|
||||||
ShaderCache<PicaFixedGSConfig, &GenerateFixedGeometryShader, GL_GEOMETRY_SHADER>;
|
ShaderCache<PicaFixedGSConfig, &GenerateFixedGeometryShader, GL_GEOMETRY_SHADER>;
|
||||||
|
|
||||||
|
@ -217,8 +213,8 @@ class ShaderProgramManager::Impl {
|
||||||
public:
|
public:
|
||||||
explicit Impl(bool separable, bool is_amd)
|
explicit Impl(bool separable, bool is_amd)
|
||||||
: is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable),
|
: is_amd(is_amd), separable(separable), programmable_vertex_shaders(separable),
|
||||||
trivial_vertex_shader(separable), programmable_geometry_shaders(separable),
|
trivial_vertex_shader(separable), fixed_geometry_shaders(separable),
|
||||||
fixed_geometry_shaders(separable), fragment_shaders(separable) {
|
fragment_shaders(separable) {
|
||||||
if (separable)
|
if (separable)
|
||||||
pipeline.Create();
|
pipeline.Create();
|
||||||
}
|
}
|
||||||
|
@ -254,7 +250,6 @@ public:
|
||||||
ProgrammableVertexShaders programmable_vertex_shaders;
|
ProgrammableVertexShaders programmable_vertex_shaders;
|
||||||
TrivialVertexShader trivial_vertex_shader;
|
TrivialVertexShader trivial_vertex_shader;
|
||||||
|
|
||||||
ProgrammableGeometryShaders programmable_geometry_shaders;
|
|
||||||
FixedGeometryShaders fixed_geometry_shaders;
|
FixedGeometryShaders fixed_geometry_shaders;
|
||||||
|
|
||||||
FragmentShaders fragment_shaders;
|
FragmentShaders fragment_shaders;
|
||||||
|
@ -282,15 +277,6 @@ void ShaderProgramManager::UseTrivialVertexShader() {
|
||||||
impl->current.vs = impl->trivial_vertex_shader.Get();
|
impl->current.vs = impl->trivial_vertex_shader.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShaderProgramManager::UseProgrammableGeometryShader(const PicaGSConfig& config,
|
|
||||||
const Pica::Shader::ShaderSetup setup) {
|
|
||||||
GLuint handle = impl->programmable_geometry_shaders.Get(config, setup);
|
|
||||||
if (handle == 0)
|
|
||||||
return false;
|
|
||||||
impl->current.gs = handle;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShaderProgramManager::UseFixedGeometryShader(const PicaFixedGSConfig& config) {
|
void ShaderProgramManager::UseFixedGeometryShader(const PicaFixedGSConfig& config) {
|
||||||
impl->current.gs = impl->fixed_geometry_shaders.Get(config);
|
impl->current.gs = impl->fixed_geometry_shaders.Get(config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,15 +91,6 @@ static_assert(
|
||||||
static_assert(sizeof(VSUniformData) < 16384,
|
static_assert(sizeof(VSUniformData) < 16384,
|
||||||
"VSUniformData structure must be less than 16kb as per the OpenGL spec");
|
"VSUniformData structure must be less than 16kb as per the OpenGL spec");
|
||||||
|
|
||||||
struct GSUniformData {
|
|
||||||
PicaUniformsData uniforms;
|
|
||||||
};
|
|
||||||
static_assert(
|
|
||||||
sizeof(GSUniformData) == 1856,
|
|
||||||
"The size of the GSUniformData structure has changed, update the structure in the shader");
|
|
||||||
static_assert(sizeof(GSUniformData) < 16384,
|
|
||||||
"GSUniformData structure must be less than 16kb as per the OpenGL spec");
|
|
||||||
|
|
||||||
/// A class that manage different shader stages and configures them with given config data.
|
/// A class that manage different shader stages and configures them with given config data.
|
||||||
class ShaderProgramManager {
|
class ShaderProgramManager {
|
||||||
public:
|
public:
|
||||||
|
@ -111,9 +102,6 @@ public:
|
||||||
|
|
||||||
void UseTrivialVertexShader();
|
void UseTrivialVertexShader();
|
||||||
|
|
||||||
bool UseProgrammableGeometryShader(const PicaGSConfig& config,
|
|
||||||
const Pica::Shader::ShaderSetup setup);
|
|
||||||
|
|
||||||
void UseFixedGeometryShader(const PicaFixedGSConfig& config);
|
void UseFixedGeometryShader(const PicaFixedGSConfig& config);
|
||||||
|
|
||||||
void UseTrivialGeometryShader();
|
void UseTrivialGeometryShader();
|
||||||
|
|
Reference in New Issue