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;
|
||||
}
|
||||
|
||||
VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
|
||||
|
||||
if (g_debug_context)
|
||||
g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
|
||||
}
|
||||
|
@ -23,9 +23,12 @@ public:
|
||||
/// Draw the current batch of triangles
|
||||
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
|
||||
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
|
||||
virtual void NotifyFlush(u32 addr, u32 size) = 0;
|
||||
virtual void NotifyFlush(PAddr addr, u32 size) = 0;
|
||||
};
|
||||
|
@ -17,6 +17,17 @@
|
||||
|
||||
#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) {
|
||||
|
||||
}
|
||||
@ -32,6 +43,7 @@ void RasterizerOpenGL::InitObjects() {
|
||||
attrib_color = glGetAttribLocation(shader.GetHandle(), "vert_color");
|
||||
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_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_out_maps = glGetUniformLocation(shader.GetHandle(), "out_maps");
|
||||
|
||||
// Generate VBO and VAO
|
||||
vertex_buffer.Create();
|
||||
vertex_array.Create();
|
||||
@ -132,8 +142,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0,
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::DrawTriangles() {
|
||||
state.Apply();
|
||||
|
||||
SyncFramebuffer();
|
||||
SyncDrawState();
|
||||
|
||||
@ -143,11 +151,224 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||
vertex_batch.clear();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
|
||||
void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||
if (!Settings::values.use_hw_renderer)
|
||||
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();
|
||||
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)
|
||||
return;
|
||||
|
||||
state.Apply();
|
||||
|
||||
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
|
||||
u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
|
||||
* 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() {
|
||||
// Sync the viewport
|
||||
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,
|
||||
viewport_width, viewport_height);
|
||||
|
||||
// Sync the 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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// Sync bound texture(s), upload if not cached
|
||||
const auto pica_textures = Pica::registers.GetTextures();
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
@ -443,84 +647,13 @@ void RasterizerOpenGL::SyncDrawState() {
|
||||
}
|
||||
}
|
||||
|
||||
state.Apply();
|
||||
|
||||
// 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
|
||||
// Skip processing TEV stages that simply pass the previous stage results through
|
||||
const auto tev_stages = Pica::registers.GetTevStages();
|
||||
for (unsigned tev_stage_idx = 0; tev_stage_idx < tev_stages.size(); ++tev_stage_idx) {
|
||||
const auto& stage = 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));
|
||||
}
|
||||
glUniform1i(uniform_tev_cfgs[tev_stage_idx].enabled, IsNotPassThroughTevStage(tev_stages[tev_stage_idx]));
|
||||
}
|
||||
|
||||
// Sync alpha testing to hw shader
|
||||
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);
|
||||
}
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::ReloadColorBuffer() {
|
||||
|
@ -26,6 +26,9 @@ public:
|
||||
/// Draw the current batch of triangles
|
||||
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
|
||||
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
|
||||
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();
|
||||
|
||||
/// Copies the 3ds color framebuffer into the OpenGL color framebuffer texture
|
||||
@ -147,11 +165,10 @@ private:
|
||||
GLuint attrib_texcoords;
|
||||
|
||||
// Hardware fragment shader
|
||||
GLuint uniform_alphatest_enabled;
|
||||
GLuint uniform_alphatest_func;
|
||||
GLuint uniform_alphatest_ref;
|
||||
GLuint uniform_tex;
|
||||
GLuint uniform_tev_combiner_buffer_color;
|
||||
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];
|
||||
|
||||
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() {
|
||||
SetVal(8, vert_color.x);
|
||||
SetVal(9, vert_color.y);
|
||||
SetVal(10, vert_color.z);
|
||||
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);
|
||||
o[2] = vert_color;
|
||||
o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy);
|
||||
o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy);
|
||||
|
||||
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"(
|
||||
#version 150 core
|
||||
|
||||
#define NUM_TEV_STAGES 6
|
||||
#define NUM_VTX_ATTR 7
|
||||
#define NUM_TEV_STAGES 6
|
||||
|
||||
#define SOURCE_PRIMARYCOLOR 0x0
|
||||
#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
|
||||
@ -135,6 +120,7 @@ const char g_fragment_shader_hw[] = R"(
|
||||
in vec4 o[NUM_VTX_ATTR];
|
||||
out vec4 color;
|
||||
|
||||
uniform bool alphatest_enabled;
|
||||
uniform int alphatest_func;
|
||||
uniform float alphatest_ref;
|
||||
|
||||
@ -157,31 +143,23 @@ struct TEVConfig
|
||||
|
||||
uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
|
||||
|
||||
uniform int out_maps[NUM_VTX_ATTR * 4];
|
||||
|
||||
vec4 g_combiner_buffer;
|
||||
vec4 g_last_tex_env_out;
|
||||
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) {
|
||||
if (source == SOURCE_PRIMARYCOLOR) {
|
||||
// HACK: Should use values 8/9/10/11 but hurts framerate
|
||||
// Hack assumes 9/10/11 follow directly after 8's map
|
||||
return o[out_maps[8] >> 2];
|
||||
return o[2];
|
||||
} else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
|
||||
// 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) {
|
||||
return texture(tex[0], vec2(GetVal(12), GetVal(13)));
|
||||
return texture(tex[0], o[3].xy);
|
||||
} 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) {
|
||||
// TODO: Unverified
|
||||
return texture(tex[2], vec2(GetVal(16), GetVal(17)));
|
||||
return texture(tex[2], o[5].zw);
|
||||
} else if (source == SOURCE_TEXTURE3) {
|
||||
// TODO: no 4th texture?
|
||||
} else if (source == SOURCE_PREVIOUSBUFFER) {
|
||||
@ -316,33 +294,35 @@ void main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
if (alphatest_func == COMPAREFUNC_NEVER) {
|
||||
discard;
|
||||
} else if (alphatest_func == COMPAREFUNC_ALWAYS) {
|
||||
if (alphatest_enabled) {
|
||||
if (alphatest_func == COMPAREFUNC_NEVER) {
|
||||
discard;
|
||||
} else if (alphatest_func == COMPAREFUNC_ALWAYS) {
|
||||
|
||||
} else if (alphatest_func == COMPAREFUNC_EQUAL) {
|
||||
if (g_last_tex_env_out.a != alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
|
||||
if (g_last_tex_env_out.a == alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
|
||||
if (g_last_tex_env_out.a >= alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
|
||||
if (g_last_tex_env_out.a > alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
|
||||
if (g_last_tex_env_out.a <= alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
|
||||
if (g_last_tex_env_out.a < alphatest_ref) {
|
||||
discard;
|
||||
} else if (alphatest_func == COMPAREFUNC_EQUAL) {
|
||||
if (g_last_tex_env_out.a != alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
|
||||
if (g_last_tex_env_out.a == alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
|
||||
if (g_last_tex_env_out.a >= alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
|
||||
if (g_last_tex_env_out.a > alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
|
||||
if (g_last_tex_env_out.a <= alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
|
||||
if (g_last_tex_env_out.a < alphatest_ref) {
|
||||
discard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ RendererOpenGL::~RendererOpenGL() {
|
||||
void RendererOpenGL::SwapBuffers() {
|
||||
render_window->MakeCurrent();
|
||||
|
||||
OpenGLState prev_state = OpenGLState::GetCurState();
|
||||
state.Apply();
|
||||
|
||||
for(int i : {0, 1}) {
|
||||
@ -114,6 +115,8 @@ void RendererOpenGL::SwapBuffers() {
|
||||
render_window->PollEvents();
|
||||
render_window->SwapBuffers();
|
||||
|
||||
prev_state.Apply();
|
||||
|
||||
profiler.BeginFrame();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user