Revert "Buffer allow read (#7)"

This reverts commit e2f444394f.
This commit is contained in:
Dragios 2016-04-16 01:32:36 +08:00
parent 1108438607
commit 373a925693
10 changed files with 37 additions and 367 deletions

View File

@ -422,10 +422,6 @@ ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
n = arm_instruction[i].attribute_value;
base = 0;
// 3DS has no VFP3 support
if (arm_instruction[i].version == ARMVFP3)
continue;
while (n) {
if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
// clrex

View File

@ -560,7 +560,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
if (vdm.exponent >= 1023 + 32) {
d = vdm.sign ? 0 : 0xffffffff;
exceptions = FPSCR_IOC;
} else if (vdm.exponent >= 1023) {
} else if (vdm.exponent >= 1023 - 1) {
int shift = 1023 + 63 - vdm.exponent;
u64 rem, incr = 0;
@ -644,7 +644,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
if (vdm.sign)
d = ~d;
exceptions |= FPSCR_IOC;
} else if (vdm.exponent >= 1023) {
} else if (vdm.exponent >= 1023 - 1) {
int shift = 1023 + 63 - vdm.exponent; /* 58 */
u64 rem, incr = 0;

View File

@ -64,6 +64,8 @@ static void InitScreenCoordinates(OutputVertex& vtx)
viewport.halfsize_y = float24::FromRaw(regs.viewport_size_y);
viewport.offset_x = float24::FromFloat32(static_cast<float>(regs.viewport_corner.x));
viewport.offset_y = float24::FromFloat32(static_cast<float>(regs.viewport_corner.y));
viewport.zscale = float24::FromRaw(regs.viewport_depth_range);
viewport.offset_z = float24::FromRaw(regs.viewport_depth_far_plane);
float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
vtx.color *= inv_w;
@ -76,7 +78,7 @@ static void InitScreenCoordinates(OutputVertex& vtx)
vtx.screenpos[0] = (vtx.pos.x * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x;
vtx.screenpos[1] = (vtx.pos.y * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y;
vtx.screenpos[2] = vtx.pos.z * inv_w;
vtx.screenpos[2] = viewport.offset_z + vtx.pos.z * inv_w * viewport.zscale;
}
void ProcessTriangle(const OutputVertex &v0, const OutputVertex &v1, const OutputVertex &v2) {

View File

@ -23,8 +23,6 @@
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/shader/shader_interpreter.h"
#include <GL/gl.h>
namespace Pica {
namespace CommandProcessor {
@ -171,13 +169,6 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
}
float depth;
uint8_t stencil;
glReadPixels(regs.framebuffer.GetWidth() / 2, regs.framebuffer.GetHeight() / 2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
glReadPixels(regs.framebuffer.GetWidth() / 2, regs.framebuffer.GetHeight() / 2, 1, 1, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &stencil);
printf("Read depth: %f, stencil: 0x%02X\n", depth, stencil);
}
break;

View File

@ -69,7 +69,7 @@ struct Regs {
INSERT_PADDING_WORDS(0x9);
BitField<0, 24, u32> viewport_depth_range; // float24
BitField<0, 24, u32> viewport_depth_near_plane; // float24
BitField<0, 24, u32> viewport_depth_far_plane; // float24
BitField<0, 3, u32> vs_output_total;
@ -121,20 +121,7 @@ struct Regs {
BitField<16, 10, s32> y;
} viewport_corner;
INSERT_PADDING_WORDS(0x1);
//TODO: early depth
INSERT_PADDING_WORDS(0x1);
INSERT_PADDING_WORDS(0x2);
enum DepthBuffering : u32 {
WBuffering = 0,
ZBuffering = 1,
};
BitField< 0, 1, DepthBuffering> depthmap_enable;
INSERT_PADDING_WORDS(0x12);
INSERT_PADDING_WORDS(0x17);
struct TextureConfig {
enum WrapMode : u32 {
@ -591,19 +578,13 @@ struct Regs {
}
struct {
INSERT_PADDING_WORDS(0x2);
union {
BitField<0, 4, u32> allow_color_read; // 0 = disable, else enable
};
INSERT_PADDING_WORDS(0x3);
union {
BitField<0, 4, u32> allow_color_write; // 0 = disable, else enable
};
union {
BitField<0, 2, u32> allow_depth_stencil_read; // 0 = disable, else enable
};
INSERT_PADDING_WORDS(0x1);
union {
BitField<0, 2, u32> allow_depth_stencil_write; // 0 = disable, else enable
@ -1292,11 +1273,10 @@ ASSERT_REG_POSITION(cull_mode, 0x40);
ASSERT_REG_POSITION(viewport_size_x, 0x41);
ASSERT_REG_POSITION(viewport_size_y, 0x43);
ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
ASSERT_REG_POSITION(viewport_depth_near_plane, 0x4e);
ASSERT_REG_POSITION(viewport_depth_far_plane, 0x4e);
ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
ASSERT_REG_POSITION(viewport_corner, 0x68);
ASSERT_REG_POSITION(depthmap_enable, 0x6D);
ASSERT_REG_POSITION(texture0_enable, 0x80);
ASSERT_REG_POSITION(texture0, 0x81);
ASSERT_REG_POSITION(texture0_format, 0x8e);

View File

@ -814,7 +814,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
};
if (stencil_action_enable) {
old_stencil = (regs.framebuffer.allow_depth_stencil_read != 0) ? GetStencil(x >> 4, y >> 4) : 0;
old_stencil = GetStencil(x >> 4, y >> 4);
u8 dest = old_stencil & stencil_test.input_mask;
u8 ref = stencil_test.reference_value & stencil_test.input_mask;
@ -859,34 +859,13 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
}
}
// interpolated_z = z / w
float interpolated_z_over_w = (v0.screenpos[2].ToFloat32() * w0 +
v1.screenpos[2].ToFloat32() * w1 +
v2.screenpos[2].ToFloat32() * w2) / wsum;
// Z-Buffer (z / w * scale + offset)
float depth_scale = float24::FromRaw(regs.viewport_depth_range).ToFloat32();
float depth_offset = float24::FromRaw(regs.viewport_depth_near_plane).ToFloat32();
float depth = interpolated_z_over_w * depth_scale + depth_offset;
// Potentially switch to W-Buffer
if (regs.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
float interpolated_w = interpolated_w_inverse.ToFloat32() * wsum;
// W-Buffer (z * scale + w * offset = (z / w * scale + offset) * w)
depth *= interpolated_w;
}
// Clamp the result
depth = MathUtil::Clamp(depth, 0.0f, 1.0f);
// Convert float to integer
unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
u32 z = (u32)(depth * ((1 << num_bits) - 1));
u32 z = (u32)((v0.screenpos[2].ToFloat32() * w0 +
v1.screenpos[2].ToFloat32() * w1 +
v2.screenpos[2].ToFloat32() * w2) * ((1 << num_bits) - 1) / wsum);
if (output_merger.depth_test_enable) {
u32 ref_z = (regs.framebuffer.allow_depth_stencil_read != 0) ? GetDepth(x >> 4, y >> 4) : 0;
u32 ref_z = GetDepth(x >> 4, y >> 4);
bool pass = false;
@ -938,7 +917,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
if (stencil_action_enable)
UpdateStencil(stencil_test.action_depth_pass);
auto dest = (regs.framebuffer.allow_color_read != 0) ? GetPixel(x >> 4, y >> 4) : Math::Vec4<u8>(0,0,0,0);
auto dest = GetPixel(x >> 4, y >> 4);
Math::Vec4<u8> blend_output = combiner_output;
if (output_merger.alphablend_enable) {
@ -1012,7 +991,6 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
return 255 - combiner_output.a();
case Regs::BlendFactor::DestAlpha:
case Regs::BlendFactor::DestColor:
return dest.a();
case Regs::BlendFactor::OneMinusDestAlpha:

View File

@ -151,8 +151,8 @@ void RasterizerOpenGL::Reset() {
SyncBlendFuncs();
SyncBlendColor();
SyncLogicOp();
SyncDepthTest();
SyncStencilTest();
SyncDepthTest();
SyncColorWriteMask();
SyncStencilWriteMask();
SyncDepthWriteMask();
@ -250,15 +250,10 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
// Depth modifiers
case PICA_REG_INDEX(viewport_depth_range):
case PICA_REG_INDEX(viewport_depth_near_plane):
case PICA_REG_INDEX(viewport_depth_far_plane):
SyncDepthModifiers();
break;
// Depth buffering
case PICA_REG_INDEX(depthmap_enable):
state.draw.shader_dirty = true;
break;
// Blending
case PICA_REG_INDEX(output_merger.alphablend_enable):
SyncBlendEnabled();
@ -291,7 +286,6 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
// (Pica depth test function register also contains a depth and color write mask)
case PICA_REG_INDEX(output_merger.depth_test_enable):
SyncDepthTest();
SyncStencilTest();
SyncDepthWriteMask();
SyncColorWriteMask();
break;
@ -309,18 +303,6 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
SyncColorWriteMask();
break;
// Color read mask
case PICA_REG_INDEX(framebuffer.allow_color_read):
SyncLogicOp();
SyncBlendFuncs();
break;
// Stencil and depth read mask
case PICA_REG_INDEX(framebuffer.allow_stencil_read):
SyncDepthTest();
SyncStencilTest();
break;
// Logic op
case PICA_REG_INDEX(output_merger.logic_op):
SyncLogicOp();
@ -883,9 +865,9 @@ void RasterizerOpenGL::SyncCullMode() {
void RasterizerOpenGL::SyncDepthModifiers() {
float depth_scale = -Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_range).ToFloat32();
float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_near_plane).ToFloat32();
float depth_offset = Pica::float24::FromRaw(Pica::g_state.regs.viewport_depth_far_plane).ToFloat32() / 2.0f;
uniform_block_data.data.depth_scale = depth_scale;
// TODO: Implement scale modifier
uniform_block_data.data.depth_offset = depth_offset;
uniform_block_data.dirty = true;
}
@ -896,33 +878,10 @@ void RasterizerOpenGL::SyncBlendEnabled() {
void RasterizerOpenGL::SyncBlendFuncs() {
const auto& regs = Pica::g_state.regs;
// This function pretends the destination read was 0x00 if the reads are not allowed
auto BlendAllowedFunc = [&](bool dest, Pica::Regs::BlendFactor factor) -> GLenum {
if (regs.framebuffer.allow_color_read == 0x0) {
// Destination would only read zero, so we can multiply by ZERO in blend func
if (dest)
return GL_ZERO;
if (factor == Pica::Regs::BlendFactor::DestColor ||
factor == Pica::Regs::BlendFactor::DestAlpha)
return GL_ZERO;
if (factor == Pica::Regs::BlendFactor::OneMinusDestColor ||
factor == Pica::Regs::BlendFactor::OneMinusDestAlpha)
return GL_ONE;
}
return PicaToGL::BlendFunc(factor);
};
state.blend.src_rgb_func = BlendAllowedFunc(false, regs.output_merger.alpha_blending.factor_source_rgb);
state.blend.dst_rgb_func = BlendAllowedFunc(true, regs.output_merger.alpha_blending.factor_dest_rgb);
state.blend.src_a_func = BlendAllowedFunc(false, regs.output_merger.alpha_blending.factor_source_a);
state.blend.dst_a_func = BlendAllowedFunc(true, regs.output_merger.alpha_blending.factor_dest_a);
state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb);
state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb);
state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a);
state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a);
}
void RasterizerOpenGL::SyncBlendColor() {
@ -942,61 +901,7 @@ void RasterizerOpenGL::SyncAlphaTest() {
}
void RasterizerOpenGL::SyncLogicOp() {
const auto& regs = Pica::g_state.regs;
if (regs.framebuffer.allow_color_read == 0x0) {
// Pretend that the destination reads always return 0
switch (regs.output_merger.logic_op) {
// Always 0
case Pica::Regs::LogicOp::Clear:
case Pica::Regs::LogicOp::And:
case Pica::Regs::LogicOp::AndInverted:
state.logic_op = GL_CLEAR;
break;
// Always s
case Pica::Regs::LogicOp::AndReverse:
case Pica::Regs::LogicOp::Copy:
case Pica::Regs::LogicOp::Or:
case Pica::Regs::LogicOp::Xor:
state.logic_op = GL_COPY;
break;
// Always 1
case Pica::Regs::LogicOp::Set:
case Pica::Regs::LogicOp::Invert:
case Pica::Regs::LogicOp::Nand:
case Pica::Regs::LogicOp::OrReverse:
state.logic_op = GL_SET;
break;
// Always ~s
case Pica::Regs::LogicOp::CopyInverted:
case Pica::Regs::LogicOp::Nor:
case Pica::Regs::LogicOp::Equiv:
case Pica::Regs::LogicOp::OrInverted:
state.logic_op = GL_COPY_INVERTED;
break;
// FIXME: Decide for one of those:
//a. NoOp means reading zero, writing back zero
//b. NoOp means not touching the framebuffer
case Pica::Regs::LogicOp::NoOp:
state.logic_op = GL_CLEAR; // a
state.logic_op = GL_NOOP; // b
break;
default:
LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", regs.output_merger.logic_op);
UNREACHABLE();
break;
}
} else {
state.logic_op = PicaToGL::LogicOp(regs.output_merger.logic_op);
}
state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
}
void RasterizerOpenGL::SyncColorWriteMask() {
@ -1026,143 +931,23 @@ void RasterizerOpenGL::SyncDepthWriteMask() {
: GL_FALSE;
}
// Depends on the correct GL DepthTest state!
void RasterizerOpenGL::SyncStencilTest() {
const auto& regs = Pica::g_state.regs;
const auto& stencil_test = regs.output_merger.stencil_test;
state.stencil.test_enabled = stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
if (state.stencil.test_enabled) {
if (!regs.framebuffer.allow_stencil_read) {
// All stencil reads must be emulated as 0x00
u8 masked_ref = (stencil_test.reference_value & stencil_test.input_mask);
if (masked_ref == 0x00) {
// x = 0x00
state.stencil.test_func = PicaToGL::CompareXToXFunc(stencil_test.func);
} else {
// x = masked stencil ref
state.stencil.test_func = PicaToGL::CompareXToZeroFunc(stencil_test.func);
state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8;
state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func);
state.stencil.test_ref = regs.output_merger.stencil_test.reference_value;
state.stencil.test_mask = regs.output_merger.stencil_test.input_mask;
state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail);
state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail);
state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass);
}
//FIXME: check if writeback is possible, otherwise this is useless
if (true) {
// We need a stencil read if we can't decide the stencil test staticly
bool needs_stencil_read = (state.stencil.test_func != GL_NEVER &&
state.stencil.test_func != GL_ALWAYS);
//TODO: In rare cases the stencil test doesn't depend on the masked ref ('Never' and 'Always') and only 1 specific value for
// the stencil op writes is necessary. In those cases one could set the ref and ref-mask to the required value.
//FIXME: Return value instead..?
auto StencilAllowedOp = [&](Pica::Regs::StencilAction action) -> GLenum {
switch (action) {
// FIXME: Decide for one of those:
//a. Keeping the framebuffer value means reading zero, writing back zero
//b. Keeping the framebuffer value means not touching it
case Pica::Regs::StencilAction::Keep:
return GL_ZERO; // a
return GL_KEEP; // b
// Always 0x01, requires 0x01 in masked_ref to work
case Pica::Regs::StencilAction::Increment:
case Pica::Regs::StencilAction::IncrementWrap:
if (masked_ref != 0x01) {
needs_stencil_read = true;
}
return GL_REPLACE;
// Always 0xFF, requires 0xFF in masked_ref to work
case Pica::Regs::StencilAction::Invert:
case Pica::Regs::StencilAction::DecrementWrap:
if (masked_ref != 0xFF) {
needs_stencil_read = true;
}
return GL_REPLACE;
// Always masked ref
case Pica::Regs::StencilAction::Replace:
return GL_REPLACE;
// Always 0x00
case Pica::Regs::StencilAction::Zero:
case Pica::Regs::StencilAction::Decrement:
return GL_ZERO;
default:
LOG_CRITICAL(Render_OpenGL, "Unknown stencil action %x", (int)action);
UNIMPLEMENTED();
return GL_KEEP;
}
};
// If the stencil test can fail we have to check the stencil op
if (state.depth.test_func != GL_ALWAYS) {
state.stencil.action_stencil_fail = StencilAllowedOp(stencil_test.action_stencil_fail);
}
// If the depth test can pass we have to check the stencil op
if (state.depth.test_func != GL_NEVER) {
state.stencil.action_depth_fail = StencilAllowedOp(stencil_test.action_depth_pass);
}
// If the depth test can fail we have to check the stencil op
if (state.depth.test_func != GL_ALWAYS) {
state.stencil.action_depth_pass = StencilAllowedOp(stencil_test.action_depth_fail);
}
// Now check if we support this mode
if (needs_stencil_read) {
LOG_CRITICAL(Render_OpenGL, "Can't emulate disabled read from stencil yet");
UNIMPLEMENTED();
}
}
} else {
state.stencil.test_func = PicaToGL::CompareFunc(stencil_test.func);
state.stencil.test_ref = stencil_test.reference_value;
state.stencil.test_mask = stencil_test.input_mask;
state.stencil.action_stencil_fail = PicaToGL::StencilOp(stencil_test.action_stencil_fail);
state.stencil.action_depth_fail = PicaToGL::StencilOp(stencil_test.action_depth_fail);
state.stencil.action_depth_pass = PicaToGL::StencilOp(stencil_test.action_depth_pass);
}
}
}
// Always call SyncStencilTest after this returns!
void RasterizerOpenGL::SyncDepthTest() {
const auto& regs = Pica::g_state.regs;
// Enable depth test so depth writes can still occur
state.depth.test_enabled = GL_TRUE;
if (!regs.output_merger.depth_test_enable) {
state.depth.test_func = GL_ALWAYS;
} else {
if (!regs.framebuffer.allow_depth_read) {
// If reads are not allowed we have to patch the depth test accordingly
state.depth.test_func = PicaToGL::CompareXToZeroFunc(regs.output_merger.depth_test_func);
// Check if the result is known at this point, if not it depends on the framebuffer really being zero
if (state.depth.test_func != GL_NEVER && state.depth.test_func != GL_ALWAYS) {
LOG_CRITICAL(Render_OpenGL, "Can't emulate disabled read on depth yet");
UNIMPLEMENTED();
}
} else {
state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func);
}
}
state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 ||
regs.output_merger.depth_write_enable == 1;
state.depth.test_func = regs.output_merger.depth_test_enable == 1 ?
PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS;
}
void RasterizerOpenGL::SyncCombinerColor() {

View File

@ -35,8 +35,6 @@ struct PicaShaderConfig {
PicaShaderConfig res;
const auto& regs = Pica::g_state.regs;
res.depthmap_enable = regs.depthmap_enable;
res.alpha_test_func = regs.output_merger.alpha_test.enable ?
regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
@ -143,8 +141,6 @@ struct PicaShaderConfig {
return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0;
};
Pica::Regs::DepthBuffering depthmap_enable = Pica::Regs::DepthBuffering::WBuffering;
Pica::Regs::CompareFunc alpha_test_func = Pica::Regs::CompareFunc::Never;
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
u8 combiner_buffer_input = 0;
@ -307,7 +303,6 @@ private:
GLvec4 const_color[6];
GLvec4 tev_combiner_buffer_color;
GLint alphatest_ref;
GLfloat depth_scale;
GLfloat depth_offset;
alignas(16) GLvec3 lighting_global_ambient;
LightSrc light_src[8];

View File

@ -525,7 +525,6 @@ layout (std140) uniform shader_data {
vec4 const_color[NUM_TEV_STAGES];
vec4 tev_combiner_buffer_color;
int alphatest_ref;
float depth_scale;
float depth_offset;
vec3 lighting_global_ambient;
LightSrc light_src[NUM_LIGHTS];
@ -567,15 +566,7 @@ vec4 secondary_fragment_color = vec4(0.0);
}
out += "color = last_tex_env_out;\n";
out += "float z_over_w = gl_FragCoord.z * 2.0 - 1.0;\n";
out += "float depth = z_over_w * depth_scale + depth_offset;\n";
if (config.depthmap_enable == Pica::Regs::DepthBuffering::WBuffering) {
out += "depth /= gl_FragCoord.w;\n";
}
out += "gl_FragDepth = depth;\n";
out += "}";
out += "gl_FragDepth = gl_FragCoord.z + depth_offset;\n}";
return out;
}

View File

@ -155,54 +155,6 @@ inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
return compare_func_table[(unsigned)func];
}
/// Pretend we compare 'x FUNC x'
inline GLenum CompareXToXFunc(Pica::Regs::CompareFunc func) {
static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never
GL_ALWAYS, // CompareFunc::Always
GL_ALWAYS, // CompareFunc::Equal
GL_NEVER, // CompareFunc::NotEqual
GL_NEVER, // CompareFunc::LessThan
GL_ALWAYS, // CompareFunc::LessThanOrEqual
GL_NEVER, // CompareFunc::GreaterThan
GL_ALWAYS, // CompareFunc::GreaterThanOrEqual
};
// Range check table for input
if (static_cast<size_t>(func) >= ARRAY_SIZE(compare_func_table)) {
LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func);
UNREACHABLE();
return GL_ALWAYS;
}
return compare_func_table[(unsigned)func];
}
/// Pretend we compare 'x FUNC 0' (unsigned)
inline GLenum CompareXToZeroFunc(Pica::Regs::CompareFunc func) {
static const GLenum compare_func_table[] = {
GL_NEVER, // CompareFunc::Never
GL_ALWAYS, // CompareFunc::Always
GL_EQUAL, // CompareFunc::Equal
GL_NOTEQUAL, // CompareFunc::NotEqual
GL_NEVER, // CompareFunc::LessThan
GL_LEQUAL, // CompareFunc::LessThanOrEqual
GL_GREATER, // CompareFunc::GreaterThan
GL_ALWAYS, // CompareFunc::GreaterThanOrEqual
};
// Range check table for input
if (static_cast<size_t>(func) >= ARRAY_SIZE(compare_func_table)) {
LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func);
UNREACHABLE();
return GL_ALWAYS;
}
return compare_func_table[(unsigned)func];
}
inline GLenum StencilOp(Pica::Regs::StencilAction action) {
static const GLenum stencil_op_table[] = {
GL_KEEP, // StencilAction::Keep