summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl/gl_rasterizer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl/gl_rasterizer.cpp')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp308
1 files changed, 190 insertions, 118 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 6f05f24a0..ea138d402 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -112,7 +112,7 @@ RasterizerOpenGL::RasterizerOpenGL() {
glEnable(GL_BLEND);
- NGLOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
+ LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
}
RasterizerOpenGL::~RasterizerOpenGL() {
@@ -146,7 +146,6 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
u64 size = end - start + 1;
// Copy vertex array data
- res_cache.FlushRegion(start, size, nullptr);
Memory::ReadBlock(*memory_manager->GpuToCpuAddress(start), array_ptr, size);
// Bind the vertex array to the buffer at the current offset.
@@ -166,9 +165,9 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
// assume every shader uses them all.
for (unsigned index = 0; index < 16; ++index) {
auto& attrib = regs.vertex_attrib_format[index];
- NGLOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
- index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
- attrib.offset.Value(), attrib.IsNormalized());
+ LOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
+ index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
+ attrib.offset.Value(), attrib.IsNormalized());
auto& buffer = regs.vertex_array[attrib.buffer];
ASSERT(buffer.IsEnabled());
@@ -197,8 +196,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!");
// Next available bindpoints to use when uploading the const buffers and textures to the GLSL
- // shaders.
- u32 current_constbuffer_bindpoint = 0;
+ // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
+ u32 current_constbuffer_bindpoint = uniform_buffers.size();
u32 current_texture_bindpoint = 0;
for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) {
@@ -252,8 +251,8 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
break;
}
default:
- NGLOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}",
- index, shader_config.enable.Value(), shader_config.offset);
+ LOG_CRITICAL(HW_GPU, "Unimplemented shader index={}, enable={}, offset=0x{:08X}", index,
+ shader_config.enable.Value(), shader_config.offset);
UNREACHABLE();
}
@@ -298,17 +297,16 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
return true;
}
-void RasterizerOpenGL::DrawArrays() {
- if (accelerate_draw == AccelDraw::Disabled)
- return;
-
- MICROPROFILE_SCOPE(OpenGL_Drawing);
+std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb,
+ bool using_depth_fb) {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
- // TODO(bunnei): Implement these
+ // Sync the depth test state before configuring the framebuffer surfaces.
+ SyncDepthTestState();
+
+ // TODO(bunnei): Implement this
const bool has_stencil = false;
- const bool using_color_fb = true;
- const bool using_depth_fb = false;
+
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
const bool write_color_fb =
@@ -325,35 +323,21 @@ void RasterizerOpenGL::DrawArrays() {
std::tie(color_surface, depth_surface, surfaces_rect) =
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
- const u16 res_scale = color_surface != nullptr
- ? color_surface->res_scale
- : (depth_surface == nullptr ? 1u : depth_surface->res_scale);
-
MathUtil::Rectangle<u32> draw_rect{
+ static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left,
+ surfaces_rect.left, surfaces_rect.right)), // Left
+ static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top,
+ surfaces_rect.bottom, surfaces_rect.top)), // Top
+ static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right,
+ surfaces_rect.left, surfaces_rect.right)), // Right
static_cast<u32>(
- std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left * res_scale,
- surfaces_rect.left, surfaces_rect.right)), // Left
- static_cast<u32>(
- std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top * res_scale,
- surfaces_rect.bottom, surfaces_rect.top)), // Top
- static_cast<u32>(
- std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.right * res_scale,
- surfaces_rect.left, surfaces_rect.right)), // Right
- static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) +
- viewport_rect.bottom * res_scale,
- surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
+ std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.bottom,
+ surfaces_rect.bottom, surfaces_rect.top))}; // Bottom
// Bind the framebuffer surfaces
BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
- // Sync the viewport
- SyncViewport(surfaces_rect, res_scale);
-
- // Sync the blend state registers
- SyncBlendState();
-
- // TODO(bunnei): Sync framebuffer_scale uniform here
- // TODO(bunnei): Sync scissorbox uniform(s) here
+ SyncViewport(surfaces_rect);
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
// scissor test to prevent drawing outside of the framebuffer region
@@ -364,6 +348,66 @@ void RasterizerOpenGL::DrawArrays() {
state.scissor.height = draw_rect.GetHeight();
state.Apply();
+ // Only return the surface to be marked as dirty if writing to it is enabled.
+ return std::make_pair(write_color_fb ? color_surface : nullptr,
+ write_depth_fb ? depth_surface : nullptr);
+}
+
+void RasterizerOpenGL::Clear() {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ bool use_color_fb = false;
+ bool use_depth_fb = false;
+
+ GLbitfield clear_mask = 0;
+ if (regs.clear_buffers.R && regs.clear_buffers.G && regs.clear_buffers.B &&
+ regs.clear_buffers.A) {
+ clear_mask |= GL_COLOR_BUFFER_BIT;
+ use_color_fb = true;
+ }
+ if (regs.clear_buffers.Z) {
+ clear_mask |= GL_DEPTH_BUFFER_BIT;
+ use_depth_fb = true;
+ }
+
+ if (clear_mask == 0)
+ return;
+
+ auto [dirty_color_surface, dirty_depth_surface] =
+ ConfigureFramebuffers(use_color_fb, use_depth_fb);
+
+ // TODO(Subv): Support clearing only partial colors.
+ glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2],
+ regs.clear_color[3]);
+ glClearDepth(regs.clear_depth);
+
+ glClear(clear_mask);
+
+ // Mark framebuffer surfaces as dirty
+ if (dirty_color_surface != nullptr) {
+ res_cache.MarkSurfaceAsDirty(dirty_color_surface);
+ }
+ if (dirty_depth_surface != nullptr) {
+ res_cache.MarkSurfaceAsDirty(dirty_depth_surface);
+ }
+}
+
+void RasterizerOpenGL::DrawArrays() {
+ if (accelerate_draw == AccelDraw::Disabled)
+ return;
+
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ auto [dirty_color_surface, dirty_depth_surface] =
+ ConfigureFramebuffers(true, regs.zeta.Address() != 0);
+
+ SyncBlendState();
+ SyncCullMode();
+
+ // TODO(bunnei): Sync framebuffer_scale uniform here
+ // TODO(bunnei): Sync scissorbox uniform(s) here
+
// Draw the vertex batch
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
@@ -420,14 +464,16 @@ void RasterizerOpenGL::DrawArrays() {
const GLenum primitive_mode{MaxwellToGL::PrimitiveTopology(regs.draw.topology)};
if (is_indexed) {
- const GLint index_min{static_cast<GLint>(regs.index_array.first)};
- const GLint index_max{static_cast<GLint>(regs.index_array.first + regs.index_array.count)};
- glDrawRangeElementsBaseVertex(primitive_mode, index_min, index_max, regs.index_array.count,
- MaxwellToGL::IndexFormat(regs.index_array.format),
- reinterpret_cast<const void*>(index_buffer_offset),
- -index_min);
+ const GLint base_vertex{static_cast<GLint>(regs.vb_element_base)};
+
+ // Adjust the index buffer offset so it points to the first desired index.
+ index_buffer_offset += regs.index_array.first * regs.index_array.FormatSizeInBytes();
+
+ glDrawElementsBaseVertex(primitive_mode, regs.index_array.count,
+ MaxwellToGL::IndexFormat(regs.index_array.format),
+ reinterpret_cast<const void*>(index_buffer_offset), base_vertex);
} else {
- glDrawArrays(primitive_mode, 0, regs.vertex_buffer.count);
+ glDrawArrays(primitive_mode, regs.vertex_buffer.first, regs.vertex_buffer.count);
}
// Disable scissor test
@@ -437,24 +483,16 @@ void RasterizerOpenGL::DrawArrays() {
// Unbind textures for potential future use as framebuffer attachments
for (auto& texture_unit : state.texture_units) {
- texture_unit.texture_2d = 0;
+ texture_unit.Unbind();
}
state.Apply();
// Mark framebuffer surfaces as dirty
- MathUtil::Rectangle<u32> draw_rect_unscaled{
- draw_rect.left / res_scale, draw_rect.top / res_scale, draw_rect.right / res_scale,
- draw_rect.bottom / res_scale};
-
- if (color_surface != nullptr && write_color_fb) {
- auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
- res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
- color_surface);
+ if (dirty_color_surface != nullptr) {
+ res_cache.MarkSurfaceAsDirty(dirty_color_surface);
}
- if (depth_surface != nullptr && write_depth_fb) {
- auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled);
- res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
- depth_surface);
+ if (dirty_depth_surface != nullptr) {
+ res_cache.MarkSurfaceAsDirty(dirty_depth_surface);
}
}
@@ -462,7 +500,7 @@ void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {}
void RasterizerOpenGL::FlushAll() {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
- res_cache.FlushAll();
+ res_cache.FlushRegion(0, Kernel::VMManager::MAX_ADDRESS);
}
void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) {
@@ -472,13 +510,13 @@ void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) {
void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
- res_cache.InvalidateRegion(addr, size, nullptr);
+ res_cache.InvalidateRegion(addr, size);
}
void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size);
- res_cache.InvalidateRegion(addr, size, nullptr);
+ res_cache.InvalidateRegion(addr, size);
}
bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
@@ -497,45 +535,28 @@ bool RasterizerOpenGL::AccelerateFill(const void* config) {
return true;
}
-bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& framebuffer,
+bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
VAddr framebuffer_addr, u32 pixel_stride,
ScreenInfo& screen_info) {
- if (framebuffer_addr == 0) {
- return false;
+ if (!framebuffer_addr) {
+ return {};
}
+
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
- SurfaceParams src_params;
- src_params.cpu_addr = framebuffer_addr;
- src_params.addr = res_cache.TryFindFramebufferGpuAddress(framebuffer_addr).get_value_or(0);
- src_params.width = std::min(framebuffer.width, pixel_stride);
- src_params.height = framebuffer.height;
- src_params.stride = pixel_stride;
- src_params.is_tiled = true;
- src_params.block_height = Tegra::Texture::TICEntry::DefaultBlockHeight;
- src_params.pixel_format =
- SurfaceParams::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format);
- src_params.component_type =
- SurfaceParams::ComponentTypeFromGPUPixelFormat(framebuffer.pixel_format);
- src_params.UpdateParams();
-
- MathUtil::Rectangle<u32> src_rect;
- Surface src_surface;
- std::tie(src_surface, src_rect) =
- res_cache.GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true);
-
- if (src_surface == nullptr) {
- return false;
+ const auto& surface{res_cache.TryFindFramebufferSurface(framebuffer_addr)};
+ if (!surface) {
+ return {};
}
- u32 scaled_width = src_surface->GetScaledWidth();
- u32 scaled_height = src_surface->GetScaledHeight();
+ // Verify that the cached surface is the same size and format as the requested framebuffer
+ const auto& params{surface->GetSurfaceParams()};
+ const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)};
+ ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
+ ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
+ ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
- screen_info.display_texcoords = MathUtil::Rectangle<float>(
- (float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
- (float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
-
- screen_info.display_texture = src_surface->texture.handle;
+ screen_info.display_texture = surface->Texture().handle;
return true;
}
@@ -608,32 +629,44 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
boost::optional<VAddr> addr = gpu.memory_manager->GpuToCpuAddress(buffer.address);
- std::vector<u8> data;
+ size_t size = 0;
+
if (used_buffer.IsIndirect()) {
// Buffer is accessed indirectly, so upload the entire thing
- data.resize(buffer.size * sizeof(float));
+ size = buffer.size * sizeof(float);
+
+ if (size > MaxConstbufferSize) {
+ LOG_ERROR(HW_GPU, "indirect constbuffer size {} exceeds maximum {}", size,
+ MaxConstbufferSize);
+ size = MaxConstbufferSize;
+ }
} else {
// Buffer is accessed directly, upload just what we use
- data.resize(used_buffer.GetSize() * sizeof(float));
+ size = used_buffer.GetSize() * sizeof(float);
}
+ // Align the actual size so it ends up being a multiple of vec4 to meet the OpenGL std140
+ // UBO alignment requirements.
+ size = Common::AlignUp(size, sizeof(GLvec4));
+ ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
+
+ std::vector<u8> data(size);
Memory::ReadBlock(*addr, data.data(), data.size());
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer_draw_state.ssbo);
- glBufferData(GL_SHADER_STORAGE_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
- glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ glBindBuffer(GL_UNIFORM_BUFFER, buffer_draw_state.ssbo);
+ glBufferData(GL_UNIFORM_BUFFER, data.size(), data.data(), GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
// Now configure the bindpoint of the buffer inside the shader
std::string buffer_name = used_buffer.GetName();
- GLuint index =
- glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, buffer_name.c_str());
+ GLuint index = glGetProgramResourceIndex(program, GL_UNIFORM_BLOCK, buffer_name.c_str());
if (index != -1)
- glShaderStorageBlockBinding(program, index, buffer_draw_state.bindpoint);
+ glUniformBlockBinding(program, index, buffer_draw_state.bindpoint);
}
state.Apply();
- return current_bindpoint + entries.size();
+ return current_bindpoint + static_cast<u32>(entries.size());
}
u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program, u32 current_unit,
@@ -653,16 +686,23 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,
// Bind the uniform to the sampler.
GLint uniform = glGetUniformLocation(program, entry.GetName().c_str());
- ASSERT(uniform != -1);
+ if (uniform == -1) {
+ continue;
+ }
+
glProgramUniform1i(program, uniform, current_bindpoint);
const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
- ASSERT(texture.enabled);
+
+ if (!texture.enabled) {
+ state.texture_units[current_bindpoint].texture_2d = 0;
+ continue;
+ }
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
Surface surface = res_cache.GetTextureSurface(texture);
if (surface != nullptr) {
- state.texture_units[current_bindpoint].texture_2d = surface->texture.handle;
+ state.texture_units[current_bindpoint].texture_2d = surface->Texture().handle;
state.texture_units[current_bindpoint].swizzle.r =
MaxwellToGL::SwizzleSource(texture.tic.x_source);
state.texture_units[current_bindpoint].swizzle.g =
@@ -679,7 +719,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,
state.Apply();
- return current_unit + entries.size();
+ return current_unit + static_cast<u32>(entries.size());
}
void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
@@ -688,16 +728,16 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
state.Apply();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- color_surface != nullptr ? color_surface->texture.handle : 0, 0);
+ color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
if (depth_surface != nullptr) {
if (has_stencil) {
// attach both depth and stencil
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- depth_surface->texture.handle, 0);
+ depth_surface->Texture().handle, 0);
} else {
// attach depth
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
- depth_surface->texture.handle, 0);
+ depth_surface->Texture().handle, 0);
// clear stencil attachment
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
}
@@ -708,14 +748,14 @@ void RasterizerOpenGL::BindFramebufferSurfaces(const Surface& color_surface,
}
}
-void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect, u16 res_scale) {
+void RasterizerOpenGL::SyncViewport(const MathUtil::Rectangle<u32>& surfaces_rect) {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
- state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left * res_scale;
- state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom * res_scale;
- state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth() * res_scale);
- state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight() * res_scale);
+ state.viewport.x = static_cast<GLint>(surfaces_rect.left) + viewport_rect.left;
+ state.viewport.y = static_cast<GLint>(surfaces_rect.bottom) + viewport_rect.bottom;
+ state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
+ state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
}
void RasterizerOpenGL::SyncClipEnabled() {
@@ -727,7 +767,27 @@ void RasterizerOpenGL::SyncClipCoef() {
}
void RasterizerOpenGL::SyncCullMode() {
- UNREACHABLE();
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ state.cull.enabled = regs.cull.enabled != 0;
+
+ if (state.cull.enabled) {
+ state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face);
+ state.cull.mode = MaxwellToGL::CullFace(regs.cull.cull_face);
+
+ const bool flip_triangles{regs.screen_y_control.triangle_rast_flip == 0 ||
+ regs.viewport_transform[0].scale_y < 0.0f};
+
+ // If the GPU is configured to flip the rasterized triangles, then we need to flip the
+ // notion of front and back. Note: We flip the triangles when the value of the register is 0
+ // because OpenGL already does it for us.
+ if (flip_triangles) {
+ if (state.cull.front_face == GL_CCW)
+ state.cull.front_face = GL_CW;
+ else if (state.cull.front_face == GL_CW)
+ state.cull.front_face = GL_CCW;
+ }
+ }
}
void RasterizerOpenGL::SyncDepthScale() {
@@ -738,9 +798,20 @@ void RasterizerOpenGL::SyncDepthOffset() {
UNREACHABLE();
}
+void RasterizerOpenGL::SyncDepthTestState() {
+ const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
+
+ state.depth.test_enabled = regs.depth_test_enable != 0;
+ state.depth.write_mask = regs.depth_write_enabled ? GL_TRUE : GL_FALSE;
+
+ if (!state.depth.test_enabled)
+ return;
+
+ state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
+}
+
void RasterizerOpenGL::SyncBlendState() {
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
- ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented");
// TODO(Subv): Support more than just render target 0.
state.blend.enabled = regs.blend.enable[0] != 0;
@@ -748,6 +819,7 @@ void RasterizerOpenGL::SyncBlendState() {
if (!state.blend.enabled)
return;
+ ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented");
ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented");
state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb);
state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb);