GPU/Scissor: Implemented scissor testing in the hw renderer.
We're doing this in the shader since it's not possible to provide the Exclude functionality using glScissor.
This commit is contained in:
parent
232594bee4
commit
3ec4a6d856
3 changed files with 61 additions and 3 deletions
|
@ -150,6 +150,8 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
SyncFramebuffer();
|
SyncFramebuffer();
|
||||||
SyncDrawState();
|
SyncDrawState();
|
||||||
|
|
||||||
|
SyncScissorTest();
|
||||||
|
|
||||||
if (state.draw.shader_dirty) {
|
if (state.draw.shader_dirty) {
|
||||||
SetShader();
|
SetShader();
|
||||||
state.draw.shader_dirty = false;
|
state.draw.shader_dirty = false;
|
||||||
|
@ -222,6 +224,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
SyncDepthTest();
|
SyncDepthTest();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Scissor test
|
||||||
|
case PICA_REG_INDEX(scissor_test.mode):
|
||||||
|
state.draw.shader_dirty = true;
|
||||||
|
break;
|
||||||
|
|
||||||
// Logic op
|
// Logic op
|
||||||
case PICA_REG_INDEX(output_merger.logic_op):
|
case PICA_REG_INDEX(output_merger.logic_op):
|
||||||
SyncLogicOp();
|
SyncLogicOp();
|
||||||
|
@ -499,6 +506,7 @@ void RasterizerOpenGL::SetShader() {
|
||||||
// Update uniforms
|
// Update uniforms
|
||||||
SyncAlphaTest();
|
SyncAlphaTest();
|
||||||
SyncCombinerColor();
|
SyncCombinerColor();
|
||||||
|
SyncScissorTest();
|
||||||
auto& tev_stages = Pica::g_state.regs.GetTevStages();
|
auto& tev_stages = Pica::g_state.regs.GetTevStages();
|
||||||
for (int index = 0; index < tev_stages.size(); ++index)
|
for (int index = 0; index < tev_stages.size(); ++index)
|
||||||
SyncTevConstColor(index, tev_stages[index]);
|
SyncTevConstColor(index, tev_stages[index]);
|
||||||
|
@ -657,6 +665,32 @@ void RasterizerOpenGL::SyncDepthTest() {
|
||||||
state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
|
state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncScissorTest() {
|
||||||
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
|
GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(regs.viewport_size_y).ToFloat32() * 2;
|
||||||
|
|
||||||
|
GLsizei viewport_corner_y = -(GLsizei)static_cast<float>(regs.viewport_corner.y)
|
||||||
|
+ regs.framebuffer.GetHeight() - viewport_height;
|
||||||
|
|
||||||
|
// OpenGL uses different y coordinates, so negate corner offset and flip origin
|
||||||
|
GLint scissor_bottom = viewport_height - (GLsizei)regs.scissor_test.bottom + viewport_corner_y;
|
||||||
|
|
||||||
|
GLint scissor_top = viewport_height - (GLsizei)regs.scissor_test.top - 1;
|
||||||
|
|
||||||
|
if (uniform_block_data.data.scissor_right != regs.scissor_test.right ||
|
||||||
|
uniform_block_data.data.scissor_bottom != scissor_bottom ||
|
||||||
|
uniform_block_data.data.scissor_left != regs.scissor_test.left + 1 ||
|
||||||
|
uniform_block_data.data.scissor_top != scissor_top) {
|
||||||
|
|
||||||
|
uniform_block_data.data.scissor_right = regs.scissor_test.right;
|
||||||
|
uniform_block_data.data.scissor_bottom = scissor_bottom;
|
||||||
|
uniform_block_data.data.scissor_left = regs.scissor_test.left + 1;
|
||||||
|
uniform_block_data.data.scissor_top = scissor_top;
|
||||||
|
uniform_block_data.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCombinerColor() {
|
void RasterizerOpenGL::SyncCombinerColor() {
|
||||||
auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
|
auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
|
||||||
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
|
if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
|
||||||
|
|
|
@ -36,6 +36,8 @@ struct PicaShaderConfig {
|
||||||
res.alpha_test_func = regs.output_merger.alpha_test.enable ?
|
res.alpha_test_func = regs.output_merger.alpha_test.enable ?
|
||||||
regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
|
regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
|
||||||
|
|
||||||
|
res.scissor_test_mode = regs.scissor_test.mode;
|
||||||
|
|
||||||
// Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling
|
// Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling
|
||||||
// the GetTevStages() function) because BitField explicitly disables copies.
|
// the GetTevStages() function) because BitField explicitly disables copies.
|
||||||
|
|
||||||
|
@ -87,6 +89,7 @@ struct PicaShaderConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
Pica::Regs::CompareFunc alpha_test_func;
|
Pica::Regs::CompareFunc alpha_test_func;
|
||||||
|
Pica::Regs::ScissorMode scissor_test_mode;
|
||||||
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
|
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
|
||||||
u8 combiner_buffer_input;
|
u8 combiner_buffer_input;
|
||||||
};
|
};
|
||||||
|
@ -191,16 +194,19 @@ private:
|
||||||
GLfloat tex_coord2[2];
|
GLfloat tex_coord2[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
|
/// Uniform structure for the Uniform Buffer Object, all members must be aligned as per the OpenGL std140 layout specification
|
||||||
struct UniformData {
|
struct UniformData {
|
||||||
// A vec4 color for each of the six tev stages
|
// A vec4 color for each of the six tev stages
|
||||||
std::array<GLfloat, 4> const_color[6];
|
std::array<GLfloat, 4> const_color[6];
|
||||||
std::array<GLfloat, 4> tev_combiner_buffer_color;
|
std::array<GLfloat, 4> tev_combiner_buffer_color;
|
||||||
GLint alphatest_ref;
|
GLint alphatest_ref;
|
||||||
INSERT_PADDING_BYTES(12);
|
GLint scissor_right;
|
||||||
|
GLint scissor_bottom;
|
||||||
|
GLint scissor_left;
|
||||||
|
GLint scissor_top;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader");
|
static_assert(sizeof(UniformData) == 0x84, "The size of the UniformData structure has changed, update the structure in the shader");
|
||||||
static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec");
|
static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec");
|
||||||
|
|
||||||
/// Reconfigure the OpenGL color texture to use the given format and dimensions
|
/// Reconfigure the OpenGL color texture to use the given format and dimensions
|
||||||
|
@ -239,6 +245,9 @@ private:
|
||||||
/// Syncs the depth test states to match the PICA register
|
/// Syncs the depth test states to match the PICA register
|
||||||
void SyncDepthTest();
|
void SyncDepthTest();
|
||||||
|
|
||||||
|
/// Syncs the scissor test state to match the PICA register
|
||||||
|
void SyncScissorTest();
|
||||||
|
|
||||||
/// Syncs the TEV constant color to match the PICA register
|
/// Syncs the TEV constant color to match the PICA register
|
||||||
void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage);
|
void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage);
|
||||||
|
|
||||||
|
|
|
@ -327,6 +327,7 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
||||||
|
|
||||||
in vec4 primary_color;
|
in vec4 primary_color;
|
||||||
in vec2 texcoord[3];
|
in vec2 texcoord[3];
|
||||||
|
in vec4 gl_FragCoord;
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
@ -334,6 +335,10 @@ layout (std140) uniform shader_data {
|
||||||
vec4 const_color[NUM_TEV_STAGES];
|
vec4 const_color[NUM_TEV_STAGES];
|
||||||
vec4 tev_combiner_buffer_color;
|
vec4 tev_combiner_buffer_color;
|
||||||
int alphatest_ref;
|
int alphatest_ref;
|
||||||
|
int scissor_right;
|
||||||
|
int scissor_bottom;
|
||||||
|
int scissor_left;
|
||||||
|
int scissor_top;
|
||||||
};
|
};
|
||||||
|
|
||||||
uniform sampler2D tex[3];
|
uniform sampler2D tex[3];
|
||||||
|
@ -341,6 +346,16 @@ uniform sampler2D tex[3];
|
||||||
void main() {
|
void main() {
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
// Append the scissor test
|
||||||
|
if (config.scissor_test_mode == Regs::ScissorMode::Include || config.scissor_test_mode == Regs::ScissorMode::Exclude) {
|
||||||
|
out += "if (scissor_left <= scissor_right || scissor_top >= scissor_bottom) discard;\n";
|
||||||
|
out += "if (";
|
||||||
|
// Negate the condition if we have to keep only the pixels outside the scissor box
|
||||||
|
if (config.scissor_test_mode == Regs::ScissorMode::Include)
|
||||||
|
out += "!";
|
||||||
|
out += "(gl_FragCoord.x >= scissor_right && gl_FragCoord.x <= scissor_left && gl_FragCoord.y >= scissor_top && gl_FragCoord.y <= scissor_bottom)) discard;\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
||||||
if (config.alpha_test_func == Regs::CompareFunc::Never) {
|
if (config.alpha_test_func == Regs::CompareFunc::Never) {
|
||||||
out += "discard; }";
|
out += "discard; }";
|
||||||
|
|
Loading…
Reference in a new issue