Merge pull request #1124 from Subv/logic_ops
GPU: Implemented logic ops.
This commit is contained in:
commit
125d7122ac
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue