|
|
|
@ -79,6 +79,26 @@ struct DrawParameters {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct FramebufferCacheKey {
|
|
|
|
|
bool is_single_buffer = false;
|
|
|
|
|
bool stencil_enable = false;
|
|
|
|
|
|
|
|
|
|
std::array<GLenum, Maxwell::NumRenderTargets> color_attachments{};
|
|
|
|
|
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> colors{};
|
|
|
|
|
u32 colors_count = 0;
|
|
|
|
|
|
|
|
|
|
GLuint zeta = 0;
|
|
|
|
|
|
|
|
|
|
auto Tie() const {
|
|
|
|
|
return std::tie(is_single_buffer, stencil_enable, color_attachments, colors, colors_count,
|
|
|
|
|
zeta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator<(const FramebufferCacheKey& rhs) const {
|
|
|
|
|
return Tie() < rhs.Tie();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
|
|
|
|
|
: res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info},
|
|
|
|
|
buffer_cache(*this, STREAM_BUFFER_SIZE) {
|
|
|
|
@ -103,9 +123,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
|
|
|
|
|
|
|
|
|
OpenGLState::ApplyDefaultState();
|
|
|
|
|
|
|
|
|
|
// Create render framebuffer
|
|
|
|
|
framebuffer.Create();
|
|
|
|
|
|
|
|
|
|
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
|
|
|
|
|
state.draw.shader_program = 0;
|
|
|
|
|
state.Apply();
|
|
|
|
@ -363,6 +380,44 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
|
|
|
|
|
OpenGLState& current_state) {
|
|
|
|
|
const auto [entry, is_cache_miss] = framebuffer_cache.try_emplace(fbkey);
|
|
|
|
|
auto& framebuffer = entry->second;
|
|
|
|
|
|
|
|
|
|
if (is_cache_miss)
|
|
|
|
|
framebuffer.Create();
|
|
|
|
|
|
|
|
|
|
current_state.draw.draw_framebuffer = framebuffer.handle;
|
|
|
|
|
current_state.ApplyFramebufferState();
|
|
|
|
|
|
|
|
|
|
if (!is_cache_miss)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (fbkey.is_single_buffer) {
|
|
|
|
|
if (fbkey.color_attachments[0] != GL_NONE) {
|
|
|
|
|
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, fbkey.color_attachments[0], fbkey.colors[0],
|
|
|
|
|
0);
|
|
|
|
|
}
|
|
|
|
|
glDrawBuffer(fbkey.color_attachments[0]);
|
|
|
|
|
} else {
|
|
|
|
|
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
|
|
|
|
|
if (fbkey.colors[index]) {
|
|
|
|
|
glFramebufferTexture(GL_DRAW_FRAMEBUFFER,
|
|
|
|
|
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index),
|
|
|
|
|
fbkey.colors[index], 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
glDrawBuffers(fbkey.colors_count, fbkey.color_attachments.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fbkey.zeta) {
|
|
|
|
|
GLenum zeta_attachment =
|
|
|
|
|
fbkey.stencil_enable ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT;
|
|
|
|
|
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, zeta_attachment, fbkey.zeta, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
|
|
|
|
|
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
|
|
|
|
|
|
|
|
@ -446,10 +501,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
|
|
|
|
ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
|
|
|
|
|
|
|
|
|
|
// Bind the framebuffer surfaces
|
|
|
|
|
current_state.draw.draw_framebuffer = framebuffer.handle;
|
|
|
|
|
current_state.ApplyFramebufferState();
|
|
|
|
|
current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
|
|
|
|
|
|
|
|
|
|
FramebufferCacheKey fbkey;
|
|
|
|
|
|
|
|
|
|
if (using_color_fb) {
|
|
|
|
|
if (single_color_target) {
|
|
|
|
|
// Used when just a single color attachment is enabled, e.g. for clearing a color buffer
|
|
|
|
@ -465,14 +520,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
|
|
|
|
state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
fbkey.is_single_buffer = true;
|
|
|
|
|
fbkey.color_attachments[0] =
|
|
|
|
|
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target);
|
|
|
|
|
fbkey.colors[0] = color_surface != nullptr ? color_surface->Texture().handle : 0;
|
|
|
|
|
} else {
|
|
|
|
|
// Multiple color attachments are enabled
|
|
|
|
|
std::array<GLenum, Maxwell::NumRenderTargets> buffers;
|
|
|
|
|
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
|
|
|
|
|
Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
|
|
|
|
|
|
|
|
|
@ -487,22 +540,17 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
|
|
|
|
color_surface->GetSurfaceParams().srgb_conversion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
fbkey.color_attachments[index] =
|
|
|
|
|
GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
|
|
|
|
|
fbkey.colors[index] =
|
|
|
|
|
color_surface != nullptr ? color_surface->Texture().handle : 0;
|
|
|
|
|
}
|
|
|
|
|
glDrawBuffers(regs.rt_control.count, buffers.data());
|
|
|
|
|
fbkey.is_single_buffer = false;
|
|
|
|
|
fbkey.colors_count = regs.rt_control.count;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// No color attachments are enabled - zero out all of them
|
|
|
|
|
for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
|
|
|
|
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
|
|
|
|
|
0, 0);
|
|
|
|
|
}
|
|
|
|
|
glDrawBuffer(GL_NONE);
|
|
|
|
|
// No color attachments are enabled - leave them as zero
|
|
|
|
|
fbkey.is_single_buffer = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (depth_surface) {
|
|
|
|
@ -510,22 +558,12 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
|
|
|
|
// the shader doesn't actually write to it.
|
|
|
|
|
depth_surface->MarkAsModified(true, res_cache);
|
|
|
|
|
|
|
|
|
|
if (regs.stencil_enable) {
|
|
|
|
|
// Attach both depth and stencil
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
|
|
|
|
depth_surface->Texture().handle, 0);
|
|
|
|
|
} else {
|
|
|
|
|
// Attach depth
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
|
|
|
|
|
depth_surface->Texture().handle, 0);
|
|
|
|
|
// Clear stencil attachment
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Clear both depth and stencil attachment
|
|
|
|
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
|
|
|
|
0);
|
|
|
|
|
fbkey.zeta = depth_surface->Texture().handle;
|
|
|
|
|
fbkey.stencil_enable = regs.stencil_enable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetupCachedFramebuffer(fbkey, current_state);
|
|
|
|
|
|
|
|
|
|
SyncViewport(current_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|