1
0
Fork 0
forked from suyu/suyu

Merge pull request #1124 from Subv/logic_ops

GPU: Implemented logic ops.
This commit is contained in:
bunnei 2018-08-22 01:05:25 -04:00 committed by GitHub
commit 125d7122ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 7 deletions

View file

@ -311,6 +311,25 @@ public:
AlwaysOld = 8, AlwaysOld = 8,
}; };
enum class LogicOperation : u32 {
Clear = 0x1500,
And = 0x1501,
AndReverse = 0x1502,
Copy = 0x1503,
AndInverted = 0x1504,
NoOp = 0x1505,
Xor = 0x1506,
Or = 0x1507,
Nor = 0x1508,
Equiv = 0x1509,
Invert = 0x150A,
OrReverse = 0x150B,
CopyInverted = 0x150C,
OrInverted = 0x150D,
Nand = 0x150E,
Set = 0x150F,
};
struct Cull { struct Cull {
enum class FrontFace : u32 { enum class FrontFace : u32 {
ClockWise = 0x0900, ClockWise = 0x0900,
@ -695,7 +714,14 @@ public:
Cull cull; Cull cull;
INSERT_PADDING_WORDS(0x2B); INSERT_PADDING_WORDS(0x28);
struct {
u32 enable;
LogicOperation operation;
} logic_op;
INSERT_PADDING_WORDS(0x1);
union { union {
u32 raw; u32 raw;
@ -942,6 +968,7 @@ ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(index_array, 0x5F2); ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(instanced_arrays, 0x620); ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646); ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(logic_op, 0x671);
ASSERT_REG_POSITION(clear_buffers, 0x674); ASSERT_REG_POSITION(clear_buffers, 0x674);
ASSERT_REG_POSITION(query, 0x6C0); ASSERT_REG_POSITION(query, 0x6C0);
ASSERT_REG_POSITION(vertex_array[0], 0x700); ASSERT_REG_POSITION(vertex_array[0], 0x700);

View file

@ -450,6 +450,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncDepthTestState(); SyncDepthTestState();
SyncBlendState(); SyncBlendState();
SyncLogicOpState();
SyncCullMode(); SyncCullMode();
// TODO(bunnei): Sync framebuffer_scale uniform here // TODO(bunnei): Sync framebuffer_scale uniform here
@ -847,6 +848,9 @@ void RasterizerOpenGL::SyncBlendState() {
if (!state.blend.enabled) if (!state.blend.enabled)
return; return;
ASSERT_MSG(regs.logic_op.enable == 0,
"Blending and logic op can't be enabled at the same time.");
ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented");
ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented");
state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb);
@ -856,3 +860,17 @@ void RasterizerOpenGL::SyncBlendState() {
state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a);
state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a);
} }
void RasterizerOpenGL::SyncLogicOpState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
// TODO(Subv): Support more than just render target 0.
state.logic_op.enabled = regs.logic_op.enable != 0;
if (!state.logic_op.enabled)
return;
ASSERT_MSG(regs.blend.enable == 0, "Blending and logic op can't be enabled at the same time.");
state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
}

View file

@ -142,6 +142,9 @@ private:
/// Syncs the blend state to match the guest state /// Syncs the blend state to match the guest state
void SyncBlendState(); void SyncBlendState();
/// Syncs the LogicOp state to match the guest state
void SyncLogicOpState();
bool has_ARB_direct_state_access = false; bool has_ARB_direct_state_access = false;
bool has_ARB_separate_shader_objects = false; bool has_ARB_separate_shader_objects = false;
bool has_ARB_vertex_attrib_binding = false; bool has_ARB_vertex_attrib_binding = false;

View file

@ -45,7 +45,8 @@ OpenGLState::OpenGLState() {
blend.color.blue = 0.0f; blend.color.blue = 0.0f;
blend.color.alpha = 0.0f; blend.color.alpha = 0.0f;
logic_op = GL_COPY; logic_op.enabled = false;
logic_op.operation = GL_COPY;
for (auto& texture_unit : texture_units) { for (auto& texture_unit : texture_units) {
texture_unit.Reset(); texture_unit.Reset();
@ -148,11 +149,10 @@ void OpenGLState::Apply() const {
// Blending // Blending
if (blend.enabled != cur_state.blend.enabled) { if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) { if (blend.enabled) {
ASSERT(!logic_op.enabled);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glDisable(GL_COLOR_LOGIC_OP);
} else { } else {
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_COLOR_LOGIC_OP);
} }
} }
@ -176,8 +176,18 @@ void OpenGLState::Apply() const {
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation); glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
} }
if (logic_op != cur_state.logic_op) { // Logic Operation
glLogicOp(logic_op); if (logic_op.enabled != cur_state.logic_op.enabled) {
if (logic_op.enabled) {
ASSERT(!blend.enabled);
glEnable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_COLOR_LOGIC_OP);
}
}
if (logic_op.operation != cur_state.logic_op.operation) {
glLogicOp(logic_op.operation);
} }
// Textures // Textures

View file

@ -83,7 +83,10 @@ public:
} color; // GL_BLEND_COLOR } color; // GL_BLEND_COLOR
} blend; } blend;
GLenum logic_op; // GL_LOGIC_OP_MODE struct {
bool enabled; // GL_LOGIC_OP_MODE
GLenum operation;
} logic_op;
// 3 texture units - one for each that is used in PICA fragment shader emulation // 3 texture units - one for each that is used in PICA fragment shader emulation
struct TextureUnit { struct TextureUnit {

View file

@ -317,4 +317,44 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
return {}; return {};
} }
inline GLenum LogicOp(Maxwell::LogicOperation operation) {
switch (operation) {
case Maxwell::LogicOperation::Clear:
return GL_CLEAR;
case Maxwell::LogicOperation::And:
return GL_AND;
case Maxwell::LogicOperation::AndReverse:
return GL_AND_REVERSE;
case Maxwell::LogicOperation::Copy:
return GL_COPY;
case Maxwell::LogicOperation::AndInverted:
return GL_AND_INVERTED;
case Maxwell::LogicOperation::NoOp:
return GL_NOOP;
case Maxwell::LogicOperation::Xor:
return GL_XOR;
case Maxwell::LogicOperation::Or:
return GL_OR;
case Maxwell::LogicOperation::Nor:
return GL_NOR;
case Maxwell::LogicOperation::Equiv:
return GL_EQUIV;
case Maxwell::LogicOperation::Invert:
return GL_INVERT;
case Maxwell::LogicOperation::OrReverse:
return GL_OR_REVERSE;
case Maxwell::LogicOperation::CopyInverted:
return GL_COPY_INVERTED;
case Maxwell::LogicOperation::OrInverted:
return GL_OR_INVERTED;
case Maxwell::LogicOperation::Nand:
return GL_NAND;
case Maxwell::LogicOperation::Set:
return GL_SET;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation));
UNREACHABLE();
return {};
}
} // namespace MaxwellToGL } // namespace MaxwellToGL