gl_rasterizer: Implement clear for non-zero render targets.

- Several misc. changes to ConfigureFramebuffers in support of this.
master
bunnei 2018-09-10 00:36:13 +07:00
parent ac959799e4
commit 035e6bd407
2 changed files with 66 additions and 50 deletions

@ -294,19 +294,12 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
cached_pages.add({pages_interval, delta}); cached_pages.add({pages_interval, delta});
} }
void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents) { void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
bool preserve_contents,
boost::optional<size_t> single_color_target) {
MICROPROFILE_SCOPE(OpenGL_Framebuffer); MICROPROFILE_SCOPE(OpenGL_Framebuffer);
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
const bool has_stencil = regs.stencil_enable;
const bool write_color_fb =
state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
const bool write_depth_fb =
(state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
(has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask));
Surface depth_surface; Surface depth_surface;
if (using_depth_fb) { if (using_depth_fb) {
depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); depth_surface = res_cache.GetDepthBufferSurface(preserve_contents);
@ -321,19 +314,41 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_
state.draw.draw_framebuffer = framebuffer.handle; state.draw.draw_framebuffer = framebuffer.handle;
state.Apply(); state.Apply();
if (using_color_fb) {
if (single_color_target) {
// Used when just a single color attachment is enabled, e.g. for clearing a color buffer
Surface color_surface =
res_cache.GetColorBufferSurface(*single_color_target, preserve_contents);
glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D,
color_surface != nullptr ? color_surface->Texture().handle : 0, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target));
} else {
// Multiple color attachments are enabled
std::array<GLenum, Maxwell::NumRenderTargets> buffers; std::array<GLenum, Maxwell::NumRenderTargets> buffers;
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
glFramebufferTexture2D(
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0,
0);
}
glDrawBuffers(regs.rt_control.count, buffers.data());
}
} else {
// No color attachments are enabled - zero out all of them
for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
color_surface != nullptr ? color_surface->Texture().handle : 0, 0); 0, 0);
}
glDrawBuffer(GL_NONE);
} }
glDrawBuffers(regs.rt_control.count, buffers.data());
if (depth_surface) { if (depth_surface) {
if (has_stencil) { if (regs.stencil_enable) {
// Attach both depth and stencil // Attach both depth and stencil
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
depth_surface->Texture().handle, 0); depth_surface->Texture().handle, 0);
@ -360,8 +375,9 @@ void RasterizerOpenGL::Clear() {
SCOPE_EXIT({ prev_state.Apply(); }); SCOPE_EXIT({ prev_state.Apply(); });
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
bool use_color_fb = false; bool use_color{};
bool use_depth_fb = false; bool use_depth{};
bool use_stencil{};
OpenGLState clear_state; OpenGLState clear_state;
clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer;
@ -370,22 +386,13 @@ void RasterizerOpenGL::Clear() {
clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
GLbitfield clear_mask{};
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) {
if (regs.clear_buffers.RT == 0) { use_color = true;
// We only support clearing the first color attachment for now
clear_mask |= GL_COLOR_BUFFER_BIT;
use_color_fb = true;
} else {
// TODO(subv): Add support for the other color attachments
LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT);
}
} }
if (regs.clear_buffers.Z) { if (regs.clear_buffers.Z) {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
use_depth_fb = true; use_depth = true;
clear_mask |= GL_DEPTH_BUFFER_BIT;
// Always enable the depth write when clearing the depth buffer. The depth write mask is // Always enable the depth write when clearing the depth buffer. The depth write mask is
// ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true.
@ -394,33 +401,33 @@ void RasterizerOpenGL::Clear() {
} }
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!");
use_depth_fb = true; use_stencil = true;
clear_mask |= GL_STENCIL_BUFFER_BIT;
clear_state.stencil.test_enabled = true; clear_state.stencil.test_enabled = true;
} }
if (!use_color_fb && !use_depth_fb) { if (!use_color && !use_depth && !use_stencil) {
// No color surface nor depth/stencil surface are enabled // No color surface nor depth/stencil surface are enabled
return; return;
} }
if (clear_mask == 0) {
// No clear mask is enabled
return;
}
ScopeAcquireGLContext acquire_context{emu_window}; ScopeAcquireGLContext acquire_context{emu_window};
ConfigureFramebuffers(use_depth_fb, false); ConfigureFramebuffers(use_color, use_depth || use_stencil, false,
regs.clear_buffers.RT.Value());
clear_state.Apply(); clear_state.Apply();
glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], if (use_color) {
regs.clear_color[3]); glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color);
glClearDepth(regs.clear_depth); }
glClearStencil(regs.clear_stencil);
glClear(clear_mask); if (use_depth && use_stencil) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil);
} else if (use_depth) {
glClearBufferfv(GL_DEPTH, 0, &regs.clear_depth);
} else if (use_stencil) {
glClearBufferiv(GL_STENCIL, 0, &regs.clear_stencil);
}
} }
void RasterizerOpenGL::DrawArrays() { void RasterizerOpenGL::DrawArrays() {
@ -433,7 +440,7 @@ void RasterizerOpenGL::DrawArrays() {
ScopeAcquireGLContext acquire_context{emu_window}; ScopeAcquireGLContext acquire_context{emu_window};
ConfigureFramebuffers(true, true); ConfigureFramebuffers();
SyncDepthTestState(); SyncDepthTestState();
SyncStencilTestState(); SyncStencilTestState();

@ -13,6 +13,7 @@
#include <vector> #include <vector>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <boost/optional.hpp>
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
#include <glad/glad.h> #include <glad/glad.h>
@ -97,8 +98,16 @@ private:
GLvec4 border_color; GLvec4 border_color;
}; };
/// Configures the color and depth framebuffer states /**
void ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents); * Configures the color and depth framebuffer states.
* @param use_color_fb If true, configure color framebuffers.
* @param using_depth_fb If true, configure the depth/stencil framebuffer.
* @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
* @param single_color_target Specifies if a single color buffer target should be used.
*/
void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
bool preserve_contents = true,
boost::optional<size_t> single_color_target = {});
/* /*
* Configures the current constbuffers to use for the draw command. * Configures the current constbuffers to use for the draw command.