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:
tfarley 2015-05-18 02:33:08 -07:00
parent 863edeefe0
commit 4171d6e7b1
6 changed files with 340 additions and 202 deletions

View File

@ -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));
} }

View File

@ -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;
}; };

View File

@ -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() {

View File

@ -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;
}; };

View File

@ -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,6 +294,7 @@ void main(void) {
} }
} }
if (alphatest_enabled) {
if (alphatest_func == COMPAREFUNC_NEVER) { if (alphatest_func == COMPAREFUNC_NEVER) {
discard; discard;
} else if (alphatest_func == COMPAREFUNC_ALWAYS) { } else if (alphatest_func == COMPAREFUNC_ALWAYS) {
@ -345,6 +324,7 @@ void main(void) {
discard; discard;
} }
} }
}
color = g_last_tex_env_out; color = g_last_tex_env_out;
} }

View File

@ -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();
} }