Merge pull request #1124 from Subv/logic_ops

GPU: Implemented logic ops.
merge-requests/60/head
bunnei 2018-08-22 01:05:25 +07: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

@ -311,6 +311,25 @@ public:
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 {
enum class FrontFace : u32 {
ClockWise = 0x0900,
@ -695,7 +714,14 @@ public:
Cull cull;
INSERT_PADDING_WORDS(0x2B);
INSERT_PADDING_WORDS(0x28);
struct {
u32 enable;
LogicOperation operation;
} logic_op;
INSERT_PADDING_WORDS(0x1);
union {
u32 raw;
@ -942,6 +968,7 @@ ASSERT_REG_POSITION(draw, 0x585);
ASSERT_REG_POSITION(index_array, 0x5F2);
ASSERT_REG_POSITION(instanced_arrays, 0x620);
ASSERT_REG_POSITION(cull, 0x646);
ASSERT_REG_POSITION(logic_op, 0x671);
ASSERT_REG_POSITION(clear_buffers, 0x674);
ASSERT_REG_POSITION(query, 0x6C0);
ASSERT_REG_POSITION(vertex_array[0], 0x700);

@ -450,6 +450,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncDepthTestState();
SyncBlendState();
SyncLogicOpState();
SyncCullMode();
// TODO(bunnei): Sync framebuffer_scale uniform here
@ -847,6 +848,9 @@ void RasterizerOpenGL::SyncBlendState() {
if (!state.blend.enabled)
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[0].separate_alpha, "Unimplemented");
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.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);
}

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

@ -45,7 +45,8 @@ OpenGLState::OpenGLState() {
blend.color.blue = 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) {
texture_unit.Reset();
@ -148,11 +149,10 @@ void OpenGLState::Apply() const {
// Blending
if (blend.enabled != cur_state.blend.enabled) {
if (blend.enabled) {
ASSERT(!logic_op.enabled);
glEnable(GL_BLEND);
glDisable(GL_COLOR_LOGIC_OP);
} else {
glDisable(GL_BLEND);
glEnable(GL_COLOR_LOGIC_OP);
}
}
@ -176,8 +176,18 @@ void OpenGLState::Apply() const {
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
}
if (logic_op != cur_state.logic_op) {
glLogicOp(logic_op);
// Logic Operation
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

@ -83,7 +83,10 @@ public:
} color; // GL_BLEND_COLOR
} 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
struct TextureUnit {

@ -317,4 +317,44 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
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