mirror of
https://git.suyu.dev/suyu/suyu.git
synced 2024-11-26 13:26:30 -05:00
GPU: Factor out the framebuffer configuration code for both Clear and Draw commands.
This commit is contained in:
parent
c1811ed3d1
commit
78443a7f29
2 changed files with 62 additions and 95 deletions
|
@ -297,92 +297,7 @@ bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::Clear() {
|
std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers() {
|
||||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (regs.clear_buffers.Z)
|
|
||||||
clear_mask |= GL_DEPTH_BUFFER_BIT;
|
|
||||||
|
|
||||||
if (clear_mask == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Sync the depth test state before configuring the framebuffer surfaces.
|
|
||||||
SyncDepthTestState();
|
|
||||||
|
|
||||||
// TODO(bunnei): Implement these
|
|
||||||
const bool has_stencil = false;
|
|
||||||
const bool using_color_fb = true;
|
|
||||||
const bool using_depth_fb = regs.zeta.Address() != 0;
|
|
||||||
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
|
|
||||||
|
|
||||||
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.test_enabled && state.stencil.write_mask != 0);
|
|
||||||
|
|
||||||
Surface color_surface;
|
|
||||||
Surface depth_surface;
|
|
||||||
MathUtil::Rectangle<u32> surfaces_rect;
|
|
||||||
std::tie(color_surface, depth_surface, surfaces_rect) =
|
|
||||||
res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect);
|
|
||||||
|
|
||||||
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.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);
|
|
||||||
|
|
||||||
// TODO(bunnei): Sync scissorbox uniform(s) here
|
|
||||||
|
|
||||||
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
|
|
||||||
// scissor test to prevent drawing outside of the framebuffer region
|
|
||||||
state.scissor.enabled = true;
|
|
||||||
state.scissor.x = draw_rect.left;
|
|
||||||
state.scissor.y = draw_rect.bottom;
|
|
||||||
state.scissor.width = draw_rect.GetWidth();
|
|
||||||
state.scissor.height = draw_rect.GetHeight();
|
|
||||||
state.Apply();
|
|
||||||
|
|
||||||
// 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 (color_surface != nullptr && write_color_fb) {
|
|
||||||
res_cache.MarkSurfaceAsDirty(color_surface);
|
|
||||||
}
|
|
||||||
if (depth_surface != nullptr && write_depth_fb) {
|
|
||||||
res_cache.MarkSurfaceAsDirty(depth_surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::DrawArrays() {
|
|
||||||
if (accelerate_draw == AccelDraw::Disabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MICROPROFILE_SCOPE(OpenGL_Drawing);
|
|
||||||
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
const auto& regs = Core::System().GetInstance().GPU().Maxwell3D().regs;
|
||||||
|
|
||||||
// Sync the depth test state before configuring the framebuffer surfaces.
|
// Sync the depth test state before configuring the framebuffer surfaces.
|
||||||
|
@ -425,11 +340,6 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
|
BindFramebufferSurfaces(color_surface, depth_surface, has_stencil);
|
||||||
|
|
||||||
SyncViewport(surfaces_rect);
|
SyncViewport(surfaces_rect);
|
||||||
SyncBlendState();
|
|
||||||
SyncCullMode();
|
|
||||||
|
|
||||||
// TODO(bunnei): Sync framebuffer_scale uniform here
|
|
||||||
// TODO(bunnei): Sync scissorbox uniform(s) here
|
|
||||||
|
|
||||||
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
|
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect. Enable
|
||||||
// scissor test to prevent drawing outside of the framebuffer region
|
// scissor test to prevent drawing outside of the framebuffer region
|
||||||
|
@ -440,6 +350,58 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
state.scissor.height = draw_rect.GetHeight();
|
state.scissor.height = draw_rect.GetHeight();
|
||||||
state.Apply();
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (regs.clear_buffers.Z)
|
||||||
|
clear_mask |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
|
||||||
|
if (clear_mask == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto [dirty_color_surface, dirty_depth_surface] = ConfigureFramebuffers();
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
SyncBlendState();
|
||||||
|
SyncCullMode();
|
||||||
|
|
||||||
|
// TODO(bunnei): Sync framebuffer_scale uniform here
|
||||||
|
// TODO(bunnei): Sync scissorbox uniform(s) here
|
||||||
|
|
||||||
// Draw the vertex batch
|
// Draw the vertex batch
|
||||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||||
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
|
const u64 index_buffer_size{regs.index_array.count * regs.index_array.FormatSizeInBytes()};
|
||||||
|
@ -520,11 +482,11 @@ void RasterizerOpenGL::DrawArrays() {
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
// Mark framebuffer surfaces as dirty
|
// Mark framebuffer surfaces as dirty
|
||||||
if (color_surface != nullptr && write_color_fb) {
|
if (dirty_color_surface != nullptr) {
|
||||||
res_cache.MarkSurfaceAsDirty(color_surface);
|
res_cache.MarkSurfaceAsDirty(dirty_color_surface);
|
||||||
}
|
}
|
||||||
if (depth_surface != nullptr && write_depth_fb) {
|
if (dirty_depth_surface != nullptr) {
|
||||||
res_cache.MarkSurfaceAsDirty(depth_surface);
|
res_cache.MarkSurfaceAsDirty(dirty_depth_surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -82,6 +83,10 @@ private:
|
||||||
u32 border_color_a;
|
u32 border_color_a;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Configures the color and depth framebuffer states and returns the dirty <Color, Depth>
|
||||||
|
/// surfaces if writing was enabled.
|
||||||
|
std::pair<Surface, Surface> ConfigureFramebuffers();
|
||||||
|
|
||||||
/// Binds the framebuffer color and depth surface
|
/// Binds the framebuffer color and depth surface
|
||||||
void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
|
void BindFramebufferSurfaces(const Surface& color_surface, const Surface& depth_surface,
|
||||||
bool has_stencil);
|
bool has_stencil);
|
||||||
|
|
Loading…
Reference in a new issue