|
|
@ -105,6 +105,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind |
|
|
shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
|
|
shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
|
|
state.draw.shader_program = 0; |
|
|
state.draw.shader_program = 0; |
|
|
state.Apply(); |
|
|
state.Apply(); |
|
|
|
|
|
clear_framebuffer.Create(); |
|
|
|
|
|
|
|
|
LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here"); |
|
|
LOG_DEBUG(Render_OpenGL, "Sync fixed function OpenGL state here"); |
|
|
CheckExtensions(); |
|
|
CheckExtensions(); |
|
|
@ -124,10 +125,10 @@ GLuint RasterizerOpenGL::SetupVertexFormat() { |
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
const auto& regs = gpu.regs; |
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
|
if (!gpu.dirty_flags.vertex_attrib_format) { |
|
|
|
|
|
|
|
|
if (!gpu.dirty.vertex_attrib_format) { |
|
|
return state.draw.vertex_array; |
|
|
return state.draw.vertex_array; |
|
|
} |
|
|
} |
|
|
gpu.dirty_flags.vertex_attrib_format = false; |
|
|
|
|
|
|
|
|
gpu.dirty.vertex_attrib_format = false; |
|
|
|
|
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_VAO); |
|
|
MICROPROFILE_SCOPE(OpenGL_VAO); |
|
|
|
|
|
|
|
|
@ -181,7 +182,7 @@ GLuint RasterizerOpenGL::SetupVertexFormat() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Rebinding the VAO invalidates the vertex buffer bindings.
|
|
|
// Rebinding the VAO invalidates the vertex buffer bindings.
|
|
|
gpu.dirty_flags.vertex_array.set(); |
|
|
|
|
|
|
|
|
gpu.dirty.ResetVertexArrays(); |
|
|
|
|
|
|
|
|
state.draw.vertex_array = vao_entry.handle; |
|
|
state.draw.vertex_array = vao_entry.handle; |
|
|
return vao_entry.handle; |
|
|
return vao_entry.handle; |
|
|
@ -189,17 +190,20 @@ GLuint RasterizerOpenGL::SetupVertexFormat() { |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
|
|
|
|
if (gpu.dirty_flags.vertex_array.none()) |
|
|
|
|
|
|
|
|
if (!gpu.dirty.vertex_array_buffers) |
|
|
return; |
|
|
return; |
|
|
|
|
|
gpu.dirty.vertex_array_buffers = false; |
|
|
|
|
|
|
|
|
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
|
MICROPROFILE_SCOPE(OpenGL_VB); |
|
|
MICROPROFILE_SCOPE(OpenGL_VB); |
|
|
|
|
|
|
|
|
// Upload all guest vertex arrays sequentially to our buffer
|
|
|
// Upload all guest vertex arrays sequentially to our buffer
|
|
|
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
|
|
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
|
|
if (!gpu.dirty_flags.vertex_array[index]) |
|
|
|
|
|
|
|
|
if (!gpu.dirty.vertex_array[index]) |
|
|
continue; |
|
|
continue; |
|
|
|
|
|
gpu.dirty.vertex_array[index] = false; |
|
|
|
|
|
gpu.dirty.vertex_instance[index] = false; |
|
|
|
|
|
|
|
|
const auto& vertex_array = regs.vertex_array[index]; |
|
|
const auto& vertex_array = regs.vertex_array[index]; |
|
|
if (!vertex_array.IsEnabled()) |
|
|
if (!vertex_array.IsEnabled()) |
|
|
@ -224,8 +228,32 @@ void RasterizerOpenGL::SetupVertexBuffer(GLuint vao) { |
|
|
glVertexArrayBindingDivisor(vao, index, 0); |
|
|
glVertexArrayBindingDivisor(vao, index, 0); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SetupVertexInstances(GLuint vao) { |
|
|
|
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
|
|
|
|
|
|
|
|
|
if (!gpu.dirty.vertex_instances) |
|
|
|
|
|
return; |
|
|
|
|
|
gpu.dirty.vertex_instances = false; |
|
|
|
|
|
|
|
|
gpu.dirty_flags.vertex_array.reset(); |
|
|
|
|
|
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
// Upload all guest vertex arrays sequentially to our buffer
|
|
|
|
|
|
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
|
|
|
|
|
if (!gpu.dirty.vertex_instance[index]) |
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
gpu.dirty.vertex_instance[index] = false; |
|
|
|
|
|
|
|
|
|
|
|
if (regs.instanced_arrays.IsInstancingEnabled(index) && |
|
|
|
|
|
regs.vertex_array[index].divisor != 0) { |
|
|
|
|
|
// Enable vertex buffer instancing with the specified divisor.
|
|
|
|
|
|
glVertexArrayBindingDivisor(vao, index, regs.vertex_array[index].divisor); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Disable the vertex buffer instancing.
|
|
|
|
|
|
glVertexArrayBindingDivisor(vao, index, 0); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
GLintptr RasterizerOpenGL::SetupIndexBuffer() { |
|
|
GLintptr RasterizerOpenGL::SetupIndexBuffer() { |
|
|
@ -341,7 +369,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) { |
|
|
|
|
|
|
|
|
SyncClipEnabled(clip_distances); |
|
|
SyncClipEnabled(clip_distances); |
|
|
|
|
|
|
|
|
gpu.dirty_flags.shaders = false; |
|
|
|
|
|
|
|
|
gpu.dirty.shaders = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { |
|
|
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { |
|
|
@ -424,13 +452,13 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( |
|
|
|
|
|
|
|
|
const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents, |
|
|
const FramebufferConfigState fb_config_state{using_color_fb, using_depth_fb, preserve_contents, |
|
|
single_color_target}; |
|
|
single_color_target}; |
|
|
if (fb_config_state == current_framebuffer_config_state && |
|
|
|
|
|
gpu.dirty_flags.color_buffer.none() && !gpu.dirty_flags.zeta_buffer) { |
|
|
|
|
|
|
|
|
if (fb_config_state == current_framebuffer_config_state && !gpu.dirty.render_settings) { |
|
|
// Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or
|
|
|
// Only skip if the previous ConfigureFramebuffers call was from the same kind (multiple or
|
|
|
// single color targets). This is done because the guest registers may not change but the
|
|
|
// single color targets). This is done because the guest registers may not change but the
|
|
|
// host framebuffer may contain different attachments
|
|
|
// host framebuffer may contain different attachments
|
|
|
return current_depth_stencil_usage; |
|
|
return current_depth_stencil_usage; |
|
|
} |
|
|
} |
|
|
|
|
|
gpu.dirty.render_settings = false; |
|
|
current_framebuffer_config_state = fb_config_state; |
|
|
current_framebuffer_config_state = fb_config_state; |
|
|
|
|
|
|
|
|
texture_cache.GuardRenderTargets(true); |
|
|
texture_cache.GuardRenderTargets(true); |
|
|
@ -519,13 +547,65 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers( |
|
|
return current_depth_stencil_usage = {static_cast<bool>(depth_surface), fbkey.stencil_enable}; |
|
|
return current_depth_stencil_usage = {static_cast<bool>(depth_surface), fbkey.stencil_enable}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RasterizerOpenGL::ConfigureClearFramebuffer(OpenGLState& current_state, bool using_color_fb, |
|
|
|
|
|
bool using_depth_fb, bool using_stencil_fb) { |
|
|
|
|
|
auto& gpu = system.GPU().Maxwell3D(); |
|
|
|
|
|
const auto& regs = gpu.regs; |
|
|
|
|
|
|
|
|
|
|
|
texture_cache.GuardRenderTargets(true); |
|
|
|
|
|
View color_surface{}; |
|
|
|
|
|
if (using_color_fb) { |
|
|
|
|
|
color_surface = texture_cache.GetColorBufferSurface(regs.clear_buffers.RT, false); |
|
|
|
|
|
} |
|
|
|
|
|
View depth_surface{}; |
|
|
|
|
|
if (using_depth_fb || using_stencil_fb) { |
|
|
|
|
|
depth_surface = texture_cache.GetDepthBufferSurface(false); |
|
|
|
|
|
} |
|
|
|
|
|
texture_cache.GuardRenderTargets(false); |
|
|
|
|
|
|
|
|
|
|
|
current_state.draw.draw_framebuffer = clear_framebuffer.handle; |
|
|
|
|
|
current_state.ApplyFramebufferState(); |
|
|
|
|
|
|
|
|
|
|
|
if (color_surface) { |
|
|
|
|
|
color_surface->Attach(GL_COLOR_ATTACHMENT0, GL_DRAW_FRAMEBUFFER); |
|
|
|
|
|
} else { |
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (depth_surface) { |
|
|
|
|
|
const auto& params = depth_surface->GetSurfaceParams(); |
|
|
|
|
|
switch (params.type) { |
|
|
|
|
|
case VideoCore::Surface::SurfaceType::Depth: { |
|
|
|
|
|
depth_surface->Attach(GL_DEPTH_ATTACHMENT, GL_DRAW_FRAMEBUFFER); |
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case VideoCore::Surface::SurfaceType::DepthStencil: { |
|
|
|
|
|
depth_surface->Attach(GL_DEPTH_ATTACHMENT, GL_DRAW_FRAMEBUFFER); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
default: { UNIMPLEMENTED(); } |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, |
|
|
|
|
|
0); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::Clear() { |
|
|
void RasterizerOpenGL::Clear() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
bool use_color{}; |
|
|
bool use_color{}; |
|
|
bool use_depth{}; |
|
|
bool use_depth{}; |
|
|
bool use_stencil{}; |
|
|
bool use_stencil{}; |
|
|
|
|
|
|
|
|
OpenGLState clear_state; |
|
|
|
|
|
|
|
|
OpenGLState prev_state{OpenGLState::GetCurState()}; |
|
|
|
|
|
SCOPE_EXIT({ |
|
|
|
|
|
prev_state.AllDirty(); |
|
|
|
|
|
prev_state.Apply(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
OpenGLState clear_state{OpenGLState::GetCurState()}; |
|
|
|
|
|
clear_state.SetDefaultViewports(); |
|
|
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || |
|
|
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || |
|
|
regs.clear_buffers.A) { |
|
|
regs.clear_buffers.A) { |
|
|
use_color = true; |
|
|
use_color = true; |
|
|
@ -545,6 +625,7 @@ void RasterizerOpenGL::Clear() { |
|
|
// true.
|
|
|
// true.
|
|
|
clear_state.depth.test_enabled = true; |
|
|
clear_state.depth.test_enabled = true; |
|
|
clear_state.depth.test_func = GL_ALWAYS; |
|
|
clear_state.depth.test_func = GL_ALWAYS; |
|
|
|
|
|
clear_state.depth.write_mask = GL_TRUE; |
|
|
} |
|
|
} |
|
|
if (regs.clear_buffers.S) { |
|
|
if (regs.clear_buffers.S) { |
|
|
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |
|
|
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |
|
|
@ -581,8 +662,9 @@ void RasterizerOpenGL::Clear() { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const auto [clear_depth, clear_stencil] = ConfigureFramebuffers( |
|
|
|
|
|
clear_state, use_color, use_depth || use_stencil, false, regs.clear_buffers.RT.Value()); |
|
|
|
|
|
|
|
|
ConfigureClearFramebuffer(clear_state, use_color, use_depth, use_stencil); |
|
|
|
|
|
|
|
|
|
|
|
SyncViewport(clear_state); |
|
|
if (regs.clear_flags.scissor) { |
|
|
if (regs.clear_flags.scissor) { |
|
|
SyncScissorTest(clear_state); |
|
|
SyncScissorTest(clear_state); |
|
|
} |
|
|
} |
|
|
@ -591,21 +673,18 @@ void RasterizerOpenGL::Clear() { |
|
|
clear_state.EmulateViewportWithScissor(); |
|
|
clear_state.EmulateViewportWithScissor(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
clear_state.ApplyColorMask(); |
|
|
|
|
|
clear_state.ApplyDepth(); |
|
|
|
|
|
clear_state.ApplyStencilTest(); |
|
|
|
|
|
clear_state.ApplyViewport(); |
|
|
|
|
|
clear_state.ApplyFramebufferState(); |
|
|
|
|
|
|
|
|
clear_state.AllDirty(); |
|
|
|
|
|
clear_state.Apply(); |
|
|
|
|
|
|
|
|
if (use_color) { |
|
|
if (use_color) { |
|
|
glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); |
|
|
|
|
|
|
|
|
glClearBufferfv(GL_COLOR, 0, regs.clear_color); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (clear_depth && clear_stencil) { |
|
|
|
|
|
|
|
|
if (use_depth && use_stencil) { |
|
|
glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); |
|
|
glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); |
|
|
} else if (clear_depth) { |
|
|
|
|
|
|
|
|
} else if (use_depth) { |
|
|
glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); |
|
|
glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); |
|
|
} else if (clear_stencil) { |
|
|
|
|
|
|
|
|
} else if (use_stencil) { |
|
|
glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); |
|
|
glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -661,6 +740,7 @@ void RasterizerOpenGL::DrawArrays() { |
|
|
|
|
|
|
|
|
// Upload vertex and index data.
|
|
|
// Upload vertex and index data.
|
|
|
SetupVertexBuffer(vao); |
|
|
SetupVertexBuffer(vao); |
|
|
|
|
|
SetupVertexInstances(vao); |
|
|
const GLintptr index_buffer_offset = SetupIndexBuffer(); |
|
|
const GLintptr index_buffer_offset = SetupIndexBuffer(); |
|
|
|
|
|
|
|
|
// Setup draw parameters. It will automatically choose what glDraw* method to use.
|
|
|
// Setup draw parameters. It will automatically choose what glDraw* method to use.
|
|
|
@ -687,7 +767,7 @@ void RasterizerOpenGL::DrawArrays() { |
|
|
|
|
|
|
|
|
if (invalidate) { |
|
|
if (invalidate) { |
|
|
// As all cached buffers are invalidated, we need to recheck their state.
|
|
|
// As all cached buffers are invalidated, we need to recheck their state.
|
|
|
gpu.dirty_flags.vertex_array.set(); |
|
|
|
|
|
|
|
|
gpu.dirty.ResetVertexArrays(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
shader_program_manager->ApplyTo(state); |
|
|
shader_program_manager->ApplyTo(state); |
|
|
@ -700,6 +780,7 @@ void RasterizerOpenGL::DrawArrays() { |
|
|
params.DispatchDraw(); |
|
|
params.DispatchDraw(); |
|
|
|
|
|
|
|
|
accelerate_draw = AccelDraw::Disabled; |
|
|
accelerate_draw = AccelDraw::Disabled; |
|
|
|
|
|
gpu.dirty.memory_general = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::FlushAll() {} |
|
|
void RasterizerOpenGL::FlushAll() {} |
|
|
@ -907,10 +988,11 @@ void RasterizerOpenGL::SyncClipCoef() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncCullMode() { |
|
|
void RasterizerOpenGL::SyncCullMode() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
|
|
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D(); |
|
|
|
|
|
|
|
|
state.cull.enabled = regs.cull.enabled != 0; |
|
|
|
|
|
|
|
|
const auto& regs = maxwell3d.regs; |
|
|
|
|
|
|
|
|
|
|
|
state.cull.enabled = regs.cull.enabled != 0; |
|
|
if (state.cull.enabled) { |
|
|
if (state.cull.enabled) { |
|
|
state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); |
|
|
state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); |
|
|
state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); |
|
|
state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face); |
|
|
@ -943,16 +1025,21 @@ void RasterizerOpenGL::SyncDepthTestState() { |
|
|
state.depth.test_enabled = regs.depth_test_enable != 0; |
|
|
state.depth.test_enabled = regs.depth_test_enable != 0; |
|
|
state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; |
|
|
state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE; |
|
|
|
|
|
|
|
|
if (!state.depth.test_enabled) |
|
|
|
|
|
|
|
|
if (!state.depth.test_enabled) { |
|
|
return; |
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); |
|
|
state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncStencilTestState() { |
|
|
void RasterizerOpenGL::SyncStencilTestState() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
|
|
|
state.stencil.test_enabled = regs.stencil_enable != 0; |
|
|
|
|
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D(); |
|
|
|
|
|
if (!maxwell3d.dirty.stencil_test) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const auto& regs = maxwell3d.regs; |
|
|
|
|
|
|
|
|
|
|
|
state.stencil.test_enabled = regs.stencil_enable != 0; |
|
|
if (!regs.stencil_enable) { |
|
|
if (!regs.stencil_enable) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
@ -981,10 +1068,17 @@ void RasterizerOpenGL::SyncStencilTestState() { |
|
|
state.stencil.back.action_depth_fail = GL_KEEP; |
|
|
state.stencil.back.action_depth_fail = GL_KEEP; |
|
|
state.stencil.back.action_depth_pass = GL_KEEP; |
|
|
state.stencil.back.action_depth_pass = GL_KEEP; |
|
|
} |
|
|
} |
|
|
|
|
|
state.MarkDirtyStencilState(); |
|
|
|
|
|
maxwell3d.dirty.stencil_test = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncColorMask() { |
|
|
void RasterizerOpenGL::SyncColorMask() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
|
|
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D(); |
|
|
|
|
|
if (!maxwell3d.dirty.color_mask) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const auto& regs = maxwell3d.regs; |
|
|
|
|
|
|
|
|
const std::size_t count = |
|
|
const std::size_t count = |
|
|
regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; |
|
|
regs.independent_blend_enable ? Tegra::Engines::Maxwell3D::Regs::NumRenderTargets : 1; |
|
|
for (std::size_t i = 0; i < count; i++) { |
|
|
for (std::size_t i = 0; i < count; i++) { |
|
|
@ -995,6 +1089,9 @@ void RasterizerOpenGL::SyncColorMask() { |
|
|
dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; |
|
|
dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE; |
|
|
dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; |
|
|
dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
state.MarkDirtyColorMask(); |
|
|
|
|
|
maxwell3d.dirty.color_mask = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncMultiSampleState() { |
|
|
void RasterizerOpenGL::SyncMultiSampleState() { |
|
|
@ -1009,7 +1106,11 @@ void RasterizerOpenGL::SyncFragmentColorClampState() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncBlendState() { |
|
|
void RasterizerOpenGL::SyncBlendState() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
|
|
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D(); |
|
|
|
|
|
if (!maxwell3d.dirty.blend_state) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const auto& regs = maxwell3d.regs; |
|
|
|
|
|
|
|
|
state.blend_color.red = regs.blend_color.r; |
|
|
state.blend_color.red = regs.blend_color.r; |
|
|
state.blend_color.green = regs.blend_color.g; |
|
|
state.blend_color.green = regs.blend_color.g; |
|
|
@ -1032,6 +1133,8 @@ void RasterizerOpenGL::SyncBlendState() { |
|
|
for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |
|
|
for (std::size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |
|
|
state.blend[i].enabled = false; |
|
|
state.blend[i].enabled = false; |
|
|
} |
|
|
} |
|
|
|
|
|
maxwell3d.dirty.blend_state = false; |
|
|
|
|
|
state.MarkDirtyBlendState(); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -1048,6 +1151,9 @@ void RasterizerOpenGL::SyncBlendState() { |
|
|
blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); |
|
|
blend.src_a_func = MaxwellToGL::BlendFunc(src.factor_source_a); |
|
|
blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); |
|
|
blend.dst_a_func = MaxwellToGL::BlendFunc(src.factor_dest_a); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
state.MarkDirtyBlendState(); |
|
|
|
|
|
maxwell3d.dirty.blend_state = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncLogicOpState() { |
|
|
void RasterizerOpenGL::SyncLogicOpState() { |
|
|
@ -1099,13 +1205,21 @@ void RasterizerOpenGL::SyncPointState() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncPolygonOffset() { |
|
|
void RasterizerOpenGL::SyncPolygonOffset() { |
|
|
const auto& regs = system.GPU().Maxwell3D().regs; |
|
|
|
|
|
|
|
|
auto& maxwell3d = system.GPU().Maxwell3D(); |
|
|
|
|
|
if (!maxwell3d.dirty.polygon_offset) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const auto& regs = maxwell3d.regs; |
|
|
|
|
|
|
|
|
state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; |
|
|
state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; |
|
|
state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; |
|
|
state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; |
|
|
state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; |
|
|
state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; |
|
|
state.polygon_offset.units = regs.polygon_offset_units; |
|
|
state.polygon_offset.units = regs.polygon_offset_units; |
|
|
state.polygon_offset.factor = regs.polygon_offset_factor; |
|
|
state.polygon_offset.factor = regs.polygon_offset_factor; |
|
|
state.polygon_offset.clamp = regs.polygon_offset_clamp; |
|
|
state.polygon_offset.clamp = regs.polygon_offset_clamp; |
|
|
|
|
|
|
|
|
|
|
|
state.MarkDirtyPolygonOffset(); |
|
|
|
|
|
maxwell3d.dirty.polygon_offset = false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SyncAlphaTest() { |
|
|
void RasterizerOpenGL::SyncAlphaTest() { |
|
|
|