mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 08:41:04 +00:00
Pica reg state triggers, outmaps removed, cleanup
Some state now updates when PICA registers actually change Made rast state persistent and renderer state only during swap Removed outmaps as they are only needed for hw vtx shaders Made util func for IsNotPassThroughTevStage
This commit is contained in:
parent
863edeefe0
commit
4171d6e7b1
@ -358,6 +358,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
|
||||||
|
|
||||||
if (g_debug_context)
|
if (g_debug_context)
|
||||||
g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
|
g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,12 @@ public:
|
|||||||
/// Draw the current batch of triangles
|
/// Draw the current batch of triangles
|
||||||
virtual void DrawTriangles() = 0;
|
virtual void DrawTriangles() = 0;
|
||||||
|
|
||||||
|
/// Notify rasterizer that the specified PICA register has been changed
|
||||||
|
virtual void NotifyPicaRegisterChanged(u32 id) = 0;
|
||||||
|
|
||||||
/// Notify rasterizer that the specified 3DS memory region will be read from after this notification
|
/// Notify rasterizer that the specified 3DS memory region will be read from after this notification
|
||||||
virtual void NotifyPreRead(u32 paddr, u32 size) = 0;
|
virtual void NotifyPreRead(PAddr addr, u32 size) = 0;
|
||||||
|
|
||||||
/// Notify rasterizer that a 3DS memory region has been changed
|
/// Notify rasterizer that a 3DS memory region has been changed
|
||||||
virtual void NotifyFlush(u32 addr, u32 size) = 0;
|
virtual void NotifyFlush(PAddr addr, u32 size) = 0;
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,17 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
static bool IsNotPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
|
||||||
|
return (stage.color_op != Pica::Regs::TevStageConfig::Operation::Replace ||
|
||||||
|
stage.alpha_op != Pica::Regs::TevStageConfig::Operation::Replace ||
|
||||||
|
stage.color_source1 != Pica::Regs::TevStageConfig::Source::Previous ||
|
||||||
|
stage.alpha_source1 != Pica::Regs::TevStageConfig::Source::Previous ||
|
||||||
|
stage.color_modifier1 != Pica::Regs::TevStageConfig::ColorModifier::SourceColor ||
|
||||||
|
stage.alpha_modifier1 != Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha ||
|
||||||
|
stage.GetColorMultiplier() != 1 ||
|
||||||
|
stage.GetAlphaMultiplier() != 1);
|
||||||
|
}
|
||||||
|
|
||||||
RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) {
|
RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -32,6 +43,7 @@ void RasterizerOpenGL::InitObjects() {
|
|||||||
attrib_color = glGetAttribLocation(shader.GetHandle(), "vert_color");
|
attrib_color = glGetAttribLocation(shader.GetHandle(), "vert_color");
|
||||||
attrib_texcoords = glGetAttribLocation(shader.GetHandle(), "vert_texcoords");
|
attrib_texcoords = glGetAttribLocation(shader.GetHandle(), "vert_texcoords");
|
||||||
|
|
||||||
|
uniform_alphatest_enabled = glGetUniformLocation(shader.GetHandle(), "alphatest_enabled");
|
||||||
uniform_alphatest_func = glGetUniformLocation(shader.GetHandle(), "alphatest_func");
|
uniform_alphatest_func = glGetUniformLocation(shader.GetHandle(), "alphatest_func");
|
||||||
uniform_alphatest_ref = glGetUniformLocation(shader.GetHandle(), "alphatest_ref");
|
uniform_alphatest_ref = glGetUniformLocation(shader.GetHandle(), "alphatest_ref");
|
||||||
|
|
||||||
@ -54,8 +66,6 @@ void RasterizerOpenGL::InitObjects() {
|
|||||||
uniform_tev.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.GetHandle(), (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str());
|
uniform_tev.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.GetHandle(), (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
uniform_out_maps = glGetUniformLocation(shader.GetHandle(), "out_maps");
|
|
||||||
|
|
||||||
// Generate VBO and VAO
|
// Generate VBO and VAO
|
||||||
vertex_buffer.Create();
|
vertex_buffer.Create();
|
||||||
vertex_array.Create();
|
vertex_array.Create();
|
||||||
@ -132,8 +142,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::DrawTriangles() {
|
void RasterizerOpenGL::DrawTriangles() {
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
SyncFramebuffer();
|
SyncFramebuffer();
|
||||||
SyncDrawState();
|
SyncDrawState();
|
||||||
|
|
||||||
@ -143,11 +151,224 @@ void RasterizerOpenGL::DrawTriangles() {
|
|||||||
vertex_batch.clear();
|
vertex_batch.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
|
void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
if (!Settings::values.use_hw_renderer)
|
if (!Settings::values.use_hw_renderer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
state.Apply();
|
switch(id) {
|
||||||
|
// Culling
|
||||||
|
case PICA_REG_INDEX(cull_mode):
|
||||||
|
{
|
||||||
|
switch (Pica::registers.cull_mode) {
|
||||||
|
case Pica::Regs::CullMode::KeepAll:
|
||||||
|
state.cull.enabled = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pica::Regs::CullMode::KeepClockWise:
|
||||||
|
state.cull.enabled = true;
|
||||||
|
state.cull.mode = GL_BACK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Pica::Regs::CullMode::KeepCounterClockWise:
|
||||||
|
state.cull.enabled = true;
|
||||||
|
state.cull.mode = GL_FRONT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value());
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blending
|
||||||
|
case PICA_REG_INDEX(output_merger.alphablend_enable):
|
||||||
|
{
|
||||||
|
state.blend.enabled = Pica::registers.output_merger.alphablend_enable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PICA_REG_INDEX(output_merger.alpha_blending):
|
||||||
|
{
|
||||||
|
state.blend.src_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_rgb);
|
||||||
|
state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb);
|
||||||
|
state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a);
|
||||||
|
state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PICA_REG_INDEX(output_merger.blend_const):
|
||||||
|
{
|
||||||
|
state.blend.color.red = (GLclampf)Pica::registers.output_merger.blend_const.r / 255.0f;
|
||||||
|
state.blend.color.green = (GLclampf)Pica::registers.output_merger.blend_const.g / 255.0f;
|
||||||
|
state.blend.color.blue = (GLclampf)Pica::registers.output_merger.blend_const.b / 255.0f;
|
||||||
|
state.blend.color.alpha = (GLclampf)Pica::registers.output_merger.blend_const.a / 255.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpha test
|
||||||
|
case PICA_REG_INDEX(output_merger.alpha_test):
|
||||||
|
{
|
||||||
|
glUniform1i(uniform_alphatest_enabled, Pica::registers.output_merger.alpha_test.enable);
|
||||||
|
glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func);
|
||||||
|
glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref / 255.0f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stencil test
|
||||||
|
case PICA_REG_INDEX(output_merger.stencil_test):
|
||||||
|
{
|
||||||
|
// TODO: Implement stencil test, mask, and op
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth test
|
||||||
|
case PICA_REG_INDEX(output_merger.depth_test_enable):
|
||||||
|
{
|
||||||
|
state.depth.test_enabled = Pica::registers.output_merger.depth_test_enable;
|
||||||
|
state.depth.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.depth_test_func);
|
||||||
|
|
||||||
|
if (Pica::registers.output_merger.depth_write_enable) {
|
||||||
|
state.depth.write_mask = GL_TRUE;
|
||||||
|
} else {
|
||||||
|
state.depth.write_mask = GL_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEV stage 0
|
||||||
|
case PICA_REG_INDEX(tev_stage0.color_source1):
|
||||||
|
SyncTevSources(0, Pica::registers.tev_stage0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage0.color_modifier1):
|
||||||
|
SyncTevModifiers(0, Pica::registers.tev_stage0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage0.color_op):
|
||||||
|
SyncTevOps(0, Pica::registers.tev_stage0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage0.const_r):
|
||||||
|
SyncTevColor(0, Pica::registers.tev_stage0);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage0.color_scale):
|
||||||
|
SyncTevMultipliers(0, Pica::registers.tev_stage0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV stage 1
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_source1):
|
||||||
|
SyncTevSources(1, Pica::registers.tev_stage1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_modifier1):
|
||||||
|
SyncTevModifiers(1, Pica::registers.tev_stage1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_op):
|
||||||
|
SyncTevOps(1, Pica::registers.tev_stage1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage1.const_r):
|
||||||
|
SyncTevColor(1, Pica::registers.tev_stage1);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_scale):
|
||||||
|
SyncTevMultipliers(1, Pica::registers.tev_stage1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV stage 2
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_source1):
|
||||||
|
SyncTevSources(2, Pica::registers.tev_stage2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_modifier1):
|
||||||
|
SyncTevModifiers(2, Pica::registers.tev_stage2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_op):
|
||||||
|
SyncTevOps(2, Pica::registers.tev_stage2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage2.const_r):
|
||||||
|
SyncTevColor(2, Pica::registers.tev_stage2);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_scale):
|
||||||
|
SyncTevMultipliers(2, Pica::registers.tev_stage2);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV stage 3
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_source1):
|
||||||
|
SyncTevSources(3, Pica::registers.tev_stage3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_modifier1):
|
||||||
|
SyncTevModifiers(3, Pica::registers.tev_stage3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_op):
|
||||||
|
SyncTevOps(3, Pica::registers.tev_stage3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage3.const_r):
|
||||||
|
SyncTevColor(3, Pica::registers.tev_stage3);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_scale):
|
||||||
|
SyncTevMultipliers(3, Pica::registers.tev_stage3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV stage 4
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_source1):
|
||||||
|
SyncTevSources(4, Pica::registers.tev_stage4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_modifier1):
|
||||||
|
SyncTevModifiers(4, Pica::registers.tev_stage4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_op):
|
||||||
|
SyncTevOps(4, Pica::registers.tev_stage4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage4.const_r):
|
||||||
|
SyncTevColor(4, Pica::registers.tev_stage4);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_scale):
|
||||||
|
SyncTevMultipliers(4, Pica::registers.tev_stage4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV stage 5
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_source1):
|
||||||
|
SyncTevSources(5, Pica::registers.tev_stage5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_modifier1):
|
||||||
|
SyncTevModifiers(5, Pica::registers.tev_stage5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_op):
|
||||||
|
SyncTevOps(5, Pica::registers.tev_stage5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage5.const_r):
|
||||||
|
SyncTevColor(5, Pica::registers.tev_stage5);
|
||||||
|
break;
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_scale):
|
||||||
|
SyncTevMultipliers(5, Pica::registers.tev_stage5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TEV combiner buffer color
|
||||||
|
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
||||||
|
{
|
||||||
|
GLfloat combiner_color[4] = { Pica::registers.tev_combiner_buffer_color.r / 255.0f,
|
||||||
|
Pica::registers.tev_combiner_buffer_color.g / 255.0f,
|
||||||
|
Pica::registers.tev_combiner_buffer_color.b / 255.0f,
|
||||||
|
Pica::registers.tev_combiner_buffer_color.a / 255.0f };
|
||||||
|
|
||||||
|
glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEV combiner buffer write flags
|
||||||
|
case PICA_REG_INDEX(tev_combiner_buffer_input):
|
||||||
|
{
|
||||||
|
for (int tev_stage_idx = 0; tev_stage_idx < 6; ++tev_stage_idx) {
|
||||||
|
glUniform2i(uniform_tev_cfgs[tev_stage_idx].updates_combiner_buffer_color_alpha,
|
||||||
|
Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_idx),
|
||||||
|
Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_idx));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
|
||||||
|
if (!Settings::values.use_hw_renderer)
|
||||||
|
return;
|
||||||
|
|
||||||
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
|
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
|
||||||
u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
|
u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
|
||||||
@ -177,8 +398,6 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) {
|
|||||||
if (!Settings::values.use_hw_renderer)
|
if (!Settings::values.use_hw_renderer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
|
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
|
||||||
u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
|
u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
|
||||||
* Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight();
|
* Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight();
|
||||||
@ -361,6 +580,47 @@ void RasterizerOpenGL::SyncFramebuffer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncTevSources(int stage_index, const Pica::Regs::TevStageConfig& config) {
|
||||||
|
GLint color_srcs[3] = { (GLint)config.color_source1.Value(),
|
||||||
|
(GLint)config.color_source2.Value(),
|
||||||
|
(GLint)config.color_source3.Value() };
|
||||||
|
GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(),
|
||||||
|
(GLint)config.alpha_source2.Value(),
|
||||||
|
(GLint)config.alpha_source3.Value() };
|
||||||
|
|
||||||
|
glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs);
|
||||||
|
glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncTevModifiers(int stage_index, const Pica::Regs::TevStageConfig& config) {
|
||||||
|
GLint color_mods[3] = { (GLint)config.color_modifier1.Value(),
|
||||||
|
(GLint)config.color_modifier2.Value(),
|
||||||
|
(GLint)config.color_modifier3.Value() };
|
||||||
|
GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(),
|
||||||
|
(GLint)config.alpha_modifier2.Value(),
|
||||||
|
(GLint)config.alpha_modifier3.Value() };
|
||||||
|
|
||||||
|
glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods);
|
||||||
|
glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncTevOps(int stage_index, const Pica::Regs::TevStageConfig& config) {
|
||||||
|
glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncTevColor(int stage_index, const Pica::Regs::TevStageConfig& config) {
|
||||||
|
GLfloat const_color[4] = { config.const_r / 255.0f,
|
||||||
|
config.const_g / 255.0f,
|
||||||
|
config.const_b / 255.0f,
|
||||||
|
config.const_a / 255.0f };
|
||||||
|
|
||||||
|
glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SyncTevMultipliers(int stage_index, const Pica::Regs::TevStageConfig& config) {
|
||||||
|
glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier());
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDrawState() {
|
void RasterizerOpenGL::SyncDrawState() {
|
||||||
// Sync the viewport
|
// Sync the viewport
|
||||||
GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x).ToFloat32() * 2;
|
GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x).ToFloat32() * 2;
|
||||||
@ -373,63 +633,7 @@ void RasterizerOpenGL::SyncDrawState() {
|
|||||||
+ Pica::registers.framebuffer.GetHeight() - viewport_height,
|
+ Pica::registers.framebuffer.GetHeight() - viewport_height,
|
||||||
viewport_width, viewport_height);
|
viewport_width, viewport_height);
|
||||||
|
|
||||||
// Sync the cull mode
|
// Sync bound texture(s), upload if not cached
|
||||||
switch (Pica::registers.cull_mode) {
|
|
||||||
case Pica::Regs::CullMode::KeepAll:
|
|
||||||
state.cull.enabled = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Pica::Regs::CullMode::KeepClockWise:
|
|
||||||
state.cull.enabled = true;
|
|
||||||
state.cull.mode = GL_BACK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Pica::Regs::CullMode::KeepCounterClockWise:
|
|
||||||
state.cull.enabled = true;
|
|
||||||
state.cull.mode = GL_FRONT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value());
|
|
||||||
UNIMPLEMENTED();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync depth test
|
|
||||||
if (Pica::registers.output_merger.depth_test_enable) {
|
|
||||||
state.depth.test_enabled = true;
|
|
||||||
state.depth.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.depth_test_func);
|
|
||||||
} else {
|
|
||||||
state.depth.test_enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync depth writing
|
|
||||||
if (Pica::registers.output_merger.depth_write_enable) {
|
|
||||||
state.depth.write_mask = GL_TRUE;
|
|
||||||
} else {
|
|
||||||
state.depth.write_mask = GL_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement stencil test, mask, and op via: state.stencil.* = Pica::registers.output_merger.stencil_test.*
|
|
||||||
|
|
||||||
// Sync blend state
|
|
||||||
if (Pica::registers.output_merger.alphablend_enable) {
|
|
||||||
state.blend.enabled = true;
|
|
||||||
|
|
||||||
state.blend.color.red = (GLclampf)Pica::registers.output_merger.blend_const.r / 255.0f;
|
|
||||||
state.blend.color.green = (GLclampf)Pica::registers.output_merger.blend_const.g / 255.0f;
|
|
||||||
state.blend.color.blue = (GLclampf)Pica::registers.output_merger.blend_const.b / 255.0f;
|
|
||||||
state.blend.color.alpha = (GLclampf)Pica::registers.output_merger.blend_const.a / 255.0f;
|
|
||||||
|
|
||||||
state.blend.src_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_rgb);
|
|
||||||
state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb);
|
|
||||||
state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a);
|
|
||||||
state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a);
|
|
||||||
} else {
|
|
||||||
state.blend.enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync bound texture(s), upload if uncached
|
|
||||||
const auto pica_textures = Pica::registers.GetTextures();
|
const auto pica_textures = Pica::registers.GetTextures();
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
@ -443,84 +647,13 @@ void RasterizerOpenGL::SyncDrawState() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.Apply();
|
// Skip processing TEV stages that simply pass the previous stage results through
|
||||||
|
|
||||||
// Sync shader output register mapping to hw shader - 7 vectors with 4 components
|
|
||||||
for (int i = 0; i < 7 * 4; ++i) {
|
|
||||||
glUniform1i(uniform_out_maps + i, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 7; ++i) {
|
|
||||||
const auto& output_register_map = Pica::registers.vs_output_attributes[i];
|
|
||||||
|
|
||||||
u32 semantics[4] = {
|
|
||||||
output_register_map.map_x, output_register_map.map_y,
|
|
||||||
output_register_map.map_z, output_register_map.map_w
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Might only need to do this once per shader? Not sure when/if out maps are modified.
|
|
||||||
for (int comp = 0; comp < 4; ++comp) {
|
|
||||||
if (semantics[comp] != Pica::Regs::VSOutputAttributes::INVALID) {
|
|
||||||
glUniform1i(uniform_out_maps + semantics[comp], 4 * i + comp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync intial combiner buffer color
|
|
||||||
GLfloat initial_combiner_color[4] = { Pica::registers.tev_combiner_buffer_color.r / 255.0f,
|
|
||||||
Pica::registers.tev_combiner_buffer_color.g / 255.0f,
|
|
||||||
Pica::registers.tev_combiner_buffer_color.b / 255.0f,
|
|
||||||
Pica::registers.tev_combiner_buffer_color.a / 255.0f };
|
|
||||||
|
|
||||||
glUniform4fv(uniform_tev_combiner_buffer_color, 1, initial_combiner_color);
|
|
||||||
|
|
||||||
// Sync texture environment configurations to hw shader
|
|
||||||
const auto tev_stages = Pica::registers.GetTevStages();
|
const auto tev_stages = Pica::registers.GetTevStages();
|
||||||
for (unsigned tev_stage_idx = 0; tev_stage_idx < tev_stages.size(); ++tev_stage_idx) {
|
for (unsigned tev_stage_idx = 0; tev_stage_idx < tev_stages.size(); ++tev_stage_idx) {
|
||||||
const auto& stage = tev_stages[tev_stage_idx];
|
glUniform1i(uniform_tev_cfgs[tev_stage_idx].enabled, IsNotPassThroughTevStage(tev_stages[tev_stage_idx]));
|
||||||
const auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_idx];
|
|
||||||
|
|
||||||
// No need to process the tev stage if it simply passes the previous stage results through
|
|
||||||
if (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
|
||||||
stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
|
|
||||||
stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
|
||||||
stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
|
|
||||||
stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
|
|
||||||
stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
|
|
||||||
stage.GetColorMultiplier() == 1 &&
|
|
||||||
stage.GetAlphaMultiplier() == 1) {
|
|
||||||
glUniform1i(uniform_tev_cfg.enabled, 0);
|
|
||||||
} else {
|
|
||||||
GLint color_srcs[3] = { (GLint)stage.color_source1.Value(), (GLint)stage.color_source2.Value(), (GLint)stage.color_source3.Value() };
|
|
||||||
GLint alpha_srcs[3] = { (GLint)stage.alpha_source1.Value(), (GLint)stage.alpha_source2.Value(), (GLint)stage.alpha_source3.Value() };
|
|
||||||
GLint color_mods[3] = { (GLint)stage.color_modifier1.Value(), (GLint)stage.color_modifier2.Value(), (GLint)stage.color_modifier3.Value() };
|
|
||||||
GLint alpha_mods[3] = { (GLint)stage.alpha_modifier1.Value(), (GLint)stage.alpha_modifier2.Value(), (GLint)stage.alpha_modifier3.Value() };
|
|
||||||
GLfloat const_color[4] = { stage.const_r / 255.0f,
|
|
||||||
stage.const_g / 255.0f,
|
|
||||||
stage.const_b / 255.0f,
|
|
||||||
stage.const_a / 255.0f };
|
|
||||||
|
|
||||||
glUniform1i(uniform_tev_cfg.enabled, 1);
|
|
||||||
glUniform3iv(uniform_tev_cfg.color_sources, 1, color_srcs);
|
|
||||||
glUniform3iv(uniform_tev_cfg.alpha_sources, 1, alpha_srcs);
|
|
||||||
glUniform3iv(uniform_tev_cfg.color_modifiers, 1, color_mods);
|
|
||||||
glUniform3iv(uniform_tev_cfg.alpha_modifiers, 1, alpha_mods);
|
|
||||||
glUniform2i(uniform_tev_cfg.color_alpha_op, (GLint)stage.color_op.Value(), (GLint)stage.alpha_op.Value());
|
|
||||||
glUniform2i(uniform_tev_cfg.color_alpha_multiplier, stage.GetColorMultiplier(), stage.GetAlphaMultiplier());
|
|
||||||
glUniform4fv(uniform_tev_cfg.const_color, 1, const_color);
|
|
||||||
glUniform2i(uniform_tev_cfg.updates_combiner_buffer_color_alpha,
|
|
||||||
Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_idx),
|
|
||||||
Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_idx));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync alpha testing to hw shader
|
state.Apply();
|
||||||
if (Pica::registers.output_merger.alpha_test.enable) {
|
|
||||||
glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func);
|
|
||||||
glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref / 255.0f);
|
|
||||||
} else {
|
|
||||||
glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.Always);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::ReloadColorBuffer() {
|
void RasterizerOpenGL::ReloadColorBuffer() {
|
||||||
|
@ -26,6 +26,9 @@ public:
|
|||||||
/// Draw the current batch of triangles
|
/// Draw the current batch of triangles
|
||||||
void DrawTriangles() override;
|
void DrawTriangles() override;
|
||||||
|
|
||||||
|
/// Notify rasterizer that the specified PICA register has been changed
|
||||||
|
void NotifyPicaRegisterChanged(u32 id) override;
|
||||||
|
|
||||||
/// Notify rasterizer that the specified 3DS memory region will be read from after this notification
|
/// Notify rasterizer that the specified 3DS memory region will be read from after this notification
|
||||||
void NotifyPreRead(PAddr addr, u32 size) override;
|
void NotifyPreRead(PAddr addr, u32 size) override;
|
||||||
|
|
||||||
@ -101,7 +104,22 @@ private:
|
|||||||
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
|
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
|
||||||
void SyncFramebuffer();
|
void SyncFramebuffer();
|
||||||
|
|
||||||
/// Syncs the OpenGL drawing state to match the current PICA state
|
/// Syncs the specified TEV stage's color and alpha sources to match the PICA register
|
||||||
|
void SyncTevSources(int stage_index, const Pica::Regs::TevStageConfig& config);
|
||||||
|
|
||||||
|
/// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register
|
||||||
|
void SyncTevModifiers(int stage_index, const Pica::Regs::TevStageConfig& config);
|
||||||
|
|
||||||
|
/// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register
|
||||||
|
void SyncTevOps(int stage_index, const Pica::Regs::TevStageConfig& config);
|
||||||
|
|
||||||
|
/// Syncs the specified TEV stage's constant color to match the PICA register
|
||||||
|
void SyncTevColor(int stage_index, const Pica::Regs::TevStageConfig& config);
|
||||||
|
|
||||||
|
/// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register
|
||||||
|
void SyncTevMultipliers(int stage_index, const Pica::Regs::TevStageConfig& config);
|
||||||
|
|
||||||
|
/// Syncs the remaining OpenGL drawing state to match the current PICA state
|
||||||
void SyncDrawState();
|
void SyncDrawState();
|
||||||
|
|
||||||
/// Copies the 3ds color framebuffer into the OpenGL color framebuffer texture
|
/// Copies the 3ds color framebuffer into the OpenGL color framebuffer texture
|
||||||
@ -147,11 +165,10 @@ private:
|
|||||||
GLuint attrib_texcoords;
|
GLuint attrib_texcoords;
|
||||||
|
|
||||||
// Hardware fragment shader
|
// Hardware fragment shader
|
||||||
|
GLuint uniform_alphatest_enabled;
|
||||||
GLuint uniform_alphatest_func;
|
GLuint uniform_alphatest_func;
|
||||||
GLuint uniform_alphatest_ref;
|
GLuint uniform_alphatest_ref;
|
||||||
GLuint uniform_tex;
|
GLuint uniform_tex;
|
||||||
GLuint uniform_tev_combiner_buffer_color;
|
GLuint uniform_tev_combiner_buffer_color;
|
||||||
TEVConfigUniforms uniform_tev_cfgs[6];
|
TEVConfigUniforms uniform_tev_cfgs[6];
|
||||||
GLuint uniform_out_maps;
|
|
||||||
GLuint uniform_tex_envs;
|
|
||||||
};
|
};
|
||||||
|
@ -53,25 +53,10 @@ in vec2 vert_texcoords[3];
|
|||||||
|
|
||||||
out vec4 o[NUM_VTX_ATTR];
|
out vec4 o[NUM_VTX_ATTR];
|
||||||
|
|
||||||
uniform int out_maps[NUM_VTX_ATTR * 4];
|
|
||||||
|
|
||||||
void SetVal(int map_idx, float val) {
|
|
||||||
o[out_maps[map_idx] / 4][out_maps[map_idx] % 4] = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
SetVal(8, vert_color.x);
|
o[2] = vert_color;
|
||||||
SetVal(9, vert_color.y);
|
o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy);
|
||||||
SetVal(10, vert_color.z);
|
o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy);
|
||||||
SetVal(11, vert_color.w);
|
|
||||||
SetVal(12, vert_texcoords[0].x);
|
|
||||||
SetVal(13, vert_texcoords[0].y);
|
|
||||||
|
|
||||||
// TODO: These seem like the wrong map indices
|
|
||||||
SetVal(14, vert_texcoords[1].x);
|
|
||||||
SetVal(15, vert_texcoords[1].y);
|
|
||||||
SetVal(16, vert_texcoords[2].x);
|
|
||||||
SetVal(17, vert_texcoords[2].y);
|
|
||||||
|
|
||||||
gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
|
gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
|
||||||
}
|
}
|
||||||
@ -81,8 +66,8 @@ void main() {
|
|||||||
const char g_fragment_shader_hw[] = R"(
|
const char g_fragment_shader_hw[] = R"(
|
||||||
#version 150 core
|
#version 150 core
|
||||||
|
|
||||||
#define NUM_TEV_STAGES 6
|
|
||||||
#define NUM_VTX_ATTR 7
|
#define NUM_VTX_ATTR 7
|
||||||
|
#define NUM_TEV_STAGES 6
|
||||||
|
|
||||||
#define SOURCE_PRIMARYCOLOR 0x0
|
#define SOURCE_PRIMARYCOLOR 0x0
|
||||||
#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
|
#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
|
||||||
@ -135,6 +120,7 @@ const char g_fragment_shader_hw[] = R"(
|
|||||||
in vec4 o[NUM_VTX_ATTR];
|
in vec4 o[NUM_VTX_ATTR];
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
uniform bool alphatest_enabled;
|
||||||
uniform int alphatest_func;
|
uniform int alphatest_func;
|
||||||
uniform float alphatest_ref;
|
uniform float alphatest_ref;
|
||||||
|
|
||||||
@ -157,31 +143,23 @@ struct TEVConfig
|
|||||||
|
|
||||||
uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
|
uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
|
||||||
|
|
||||||
uniform int out_maps[NUM_VTX_ATTR * 4];
|
|
||||||
|
|
||||||
vec4 g_combiner_buffer;
|
vec4 g_combiner_buffer;
|
||||||
vec4 g_last_tex_env_out;
|
vec4 g_last_tex_env_out;
|
||||||
vec4 g_const_color;
|
vec4 g_const_color;
|
||||||
|
|
||||||
float GetVal(int map_idx) {
|
|
||||||
return o[out_maps[map_idx] / 4][out_maps[map_idx] % 4];
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 GetSource(int source) {
|
vec4 GetSource(int source) {
|
||||||
if (source == SOURCE_PRIMARYCOLOR) {
|
if (source == SOURCE_PRIMARYCOLOR) {
|
||||||
// HACK: Should use values 8/9/10/11 but hurts framerate
|
return o[2];
|
||||||
// Hack assumes 9/10/11 follow directly after 8's map
|
|
||||||
return o[out_maps[8] >> 2];
|
|
||||||
} else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
|
} else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
|
||||||
// HACK: Uses color value, but should really use fragment lighting output
|
// HACK: Uses color value, but should really use fragment lighting output
|
||||||
return o[out_maps[8] >> 2];
|
return o[2];
|
||||||
} else if (source == SOURCE_TEXTURE0) {
|
} else if (source == SOURCE_TEXTURE0) {
|
||||||
return texture(tex[0], vec2(GetVal(12), GetVal(13)));
|
return texture(tex[0], o[3].xy);
|
||||||
} else if (source == SOURCE_TEXTURE1) {
|
} else if (source == SOURCE_TEXTURE1) {
|
||||||
return texture(tex[1], vec2(GetVal(14), GetVal(15)));
|
return texture(tex[1], o[3].zw);
|
||||||
} else if (source == SOURCE_TEXTURE2) {
|
} else if (source == SOURCE_TEXTURE2) {
|
||||||
// TODO: Unverified
|
// TODO: Unverified
|
||||||
return texture(tex[2], vec2(GetVal(16), GetVal(17)));
|
return texture(tex[2], o[5].zw);
|
||||||
} else if (source == SOURCE_TEXTURE3) {
|
} else if (source == SOURCE_TEXTURE3) {
|
||||||
// TODO: no 4th texture?
|
// TODO: no 4th texture?
|
||||||
} else if (source == SOURCE_PREVIOUSBUFFER) {
|
} else if (source == SOURCE_PREVIOUSBUFFER) {
|
||||||
@ -316,33 +294,35 @@ void main(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alphatest_func == COMPAREFUNC_NEVER) {
|
if (alphatest_enabled) {
|
||||||
discard;
|
if (alphatest_func == COMPAREFUNC_NEVER) {
|
||||||
} else if (alphatest_func == COMPAREFUNC_ALWAYS) {
|
discard;
|
||||||
|
} else if (alphatest_func == COMPAREFUNC_ALWAYS) {
|
||||||
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_EQUAL) {
|
} else if (alphatest_func == COMPAREFUNC_EQUAL) {
|
||||||
if (g_last_tex_env_out.a != alphatest_ref) {
|
if (g_last_tex_env_out.a != alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
} else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
|
} else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
|
||||||
if (g_last_tex_env_out.a == alphatest_ref) {
|
if (g_last_tex_env_out.a == alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
} else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
|
} else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
|
||||||
if (g_last_tex_env_out.a >= alphatest_ref) {
|
if (g_last_tex_env_out.a >= alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
} else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
|
} else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
|
||||||
if (g_last_tex_env_out.a > alphatest_ref) {
|
if (g_last_tex_env_out.a > alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
|
} else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
|
||||||
if (g_last_tex_env_out.a <= alphatest_ref) {
|
if (g_last_tex_env_out.a <= alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
|
} else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
|
||||||
if (g_last_tex_env_out.a < alphatest_ref) {
|
if (g_last_tex_env_out.a < alphatest_ref) {
|
||||||
discard;
|
discard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ RendererOpenGL::~RendererOpenGL() {
|
|||||||
void RendererOpenGL::SwapBuffers() {
|
void RendererOpenGL::SwapBuffers() {
|
||||||
render_window->MakeCurrent();
|
render_window->MakeCurrent();
|
||||||
|
|
||||||
|
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
for(int i : {0, 1}) {
|
for(int i : {0, 1}) {
|
||||||
@ -114,6 +115,8 @@ void RendererOpenGL::SwapBuffers() {
|
|||||||
render_window->PollEvents();
|
render_window->PollEvents();
|
||||||
render_window->SwapBuffers();
|
render_window->SwapBuffers();
|
||||||
|
|
||||||
|
prev_state.Apply();
|
||||||
|
|
||||||
profiler.BeginFrame();
|
profiler.BeginFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user