diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 103 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 13 |
2 files changed, 66 insertions, 50 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c7e2c877c..d37863a00 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -294,19 +294,12 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | |||
| 294 | cached_pages.add({pages_interval, delta}); | 294 | cached_pages.add({pages_interval, delta}); |
| 295 | } | 295 | } |
| 296 | 296 | ||
| 297 | void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents) { | 297 | void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, |
| 298 | bool preserve_contents, | ||
| 299 | boost::optional<size_t> single_color_target) { | ||
| 298 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); | 300 | MICROPROFILE_SCOPE(OpenGL_Framebuffer); |
| 299 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 301 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 300 | 302 | ||
| 301 | const bool has_stencil = regs.stencil_enable; | ||
| 302 | const bool write_color_fb = | ||
| 303 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || | ||
| 304 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; | ||
| 305 | |||
| 306 | const bool write_depth_fb = | ||
| 307 | (state.depth.test_enabled && state.depth.write_mask == GL_TRUE) || | ||
| 308 | (has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask)); | ||
| 309 | |||
| 310 | Surface depth_surface; | 303 | Surface depth_surface; |
| 311 | if (using_depth_fb) { | 304 | if (using_depth_fb) { |
| 312 | depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); | 305 | depth_surface = res_cache.GetDepthBufferSurface(preserve_contents); |
| @@ -321,19 +314,41 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_depth_fb, bool preserve_ | |||
| 321 | state.draw.draw_framebuffer = framebuffer.handle; | 314 | state.draw.draw_framebuffer = framebuffer.handle; |
| 322 | state.Apply(); | 315 | state.Apply(); |
| 323 | 316 | ||
| 324 | std::array<GLenum, Maxwell::NumRenderTargets> buffers; | 317 | if (using_color_fb) { |
| 325 | for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | 318 | if (single_color_target) { |
| 326 | Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | 319 | // Used when just a single color attachment is enabled, e.g. for clearing a color buffer |
| 327 | buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | 320 | Surface color_surface = |
| 328 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, | 321 | res_cache.GetColorBufferSurface(*single_color_target, preserve_contents); |
| 329 | GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, | 322 | glFramebufferTexture2D( |
| 330 | color_surface != nullptr ? color_surface->Texture().handle : 0, 0); | 323 | GL_DRAW_FRAMEBUFFER, |
| 324 | GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target), GL_TEXTURE_2D, | ||
| 325 | color_surface != nullptr ? color_surface->Texture().handle : 0, 0); | ||
| 326 | glDrawBuffer(GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(*single_color_target)); | ||
| 327 | } else { | ||
| 328 | // Multiple color attachments are enabled | ||
| 329 | std::array<GLenum, Maxwell::NumRenderTargets> buffers; | ||
| 330 | for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||
| 331 | Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents); | ||
| 332 | buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | ||
| 333 | glFramebufferTexture2D( | ||
| 334 | GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), | ||
| 335 | GL_TEXTURE_2D, color_surface != nullptr ? color_surface->Texture().handle : 0, | ||
| 336 | 0); | ||
| 337 | } | ||
| 338 | glDrawBuffers(regs.rt_control.count, buffers.data()); | ||
| 339 | } | ||
| 340 | } else { | ||
| 341 | // No color attachments are enabled - zero out all of them | ||
| 342 | for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { | ||
| 343 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, | ||
| 344 | GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D, | ||
| 345 | 0, 0); | ||
| 346 | } | ||
| 347 | glDrawBuffer(GL_NONE); | ||
| 331 | } | 348 | } |
| 332 | 349 | ||
| 333 | glDrawBuffers(regs.rt_control.count, buffers.data()); | ||
| 334 | |||
| 335 | if (depth_surface) { | 350 | if (depth_surface) { |
| 336 | if (has_stencil) { | 351 | if (regs.stencil_enable) { |
| 337 | // Attach both depth and stencil | 352 | // Attach both depth and stencil |
| 338 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, | 353 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, |
| 339 | depth_surface->Texture().handle, 0); | 354 | depth_surface->Texture().handle, 0); |
| @@ -360,8 +375,9 @@ void RasterizerOpenGL::Clear() { | |||
| 360 | SCOPE_EXIT({ prev_state.Apply(); }); | 375 | SCOPE_EXIT({ prev_state.Apply(); }); |
| 361 | 376 | ||
| 362 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 377 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 363 | bool use_color_fb = false; | 378 | bool use_color{}; |
| 364 | bool use_depth_fb = false; | 379 | bool use_depth{}; |
| 380 | bool use_stencil{}; | ||
| 365 | 381 | ||
| 366 | OpenGLState clear_state; | 382 | OpenGLState clear_state; |
| 367 | clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; | 383 | clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer; |
| @@ -370,22 +386,13 @@ void RasterizerOpenGL::Clear() { | |||
| 370 | clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; | 386 | clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; |
| 371 | clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; | 387 | clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; |
| 372 | 388 | ||
| 373 | GLbitfield clear_mask{}; | ||
| 374 | if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || | 389 | if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || |
| 375 | regs.clear_buffers.A) { | 390 | regs.clear_buffers.A) { |
| 376 | if (regs.clear_buffers.RT == 0) { | 391 | use_color = true; |
| 377 | // We only support clearing the first color attachment for now | ||
| 378 | clear_mask |= GL_COLOR_BUFFER_BIT; | ||
| 379 | use_color_fb = true; | ||
| 380 | } else { | ||
| 381 | // TODO(subv): Add support for the other color attachments | ||
| 382 | LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT); | ||
| 383 | } | ||
| 384 | } | 392 | } |
| 385 | if (regs.clear_buffers.Z) { | 393 | if (regs.clear_buffers.Z) { |
| 386 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); | 394 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!"); |
| 387 | use_depth_fb = true; | 395 | use_depth = true; |
| 388 | clear_mask |= GL_DEPTH_BUFFER_BIT; | ||
| 389 | 396 | ||
| 390 | // Always enable the depth write when clearing the depth buffer. The depth write mask is | 397 | // Always enable the depth write when clearing the depth buffer. The depth write mask is |
| 391 | // ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true. | 398 | // 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() { | |||
| 394 | } | 401 | } |
| 395 | if (regs.clear_buffers.S) { | 402 | if (regs.clear_buffers.S) { |
| 396 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); | 403 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |
| 397 | use_depth_fb = true; | 404 | use_stencil = true; |
| 398 | clear_mask |= GL_STENCIL_BUFFER_BIT; | ||
| 399 | clear_state.stencil.test_enabled = true; | 405 | clear_state.stencil.test_enabled = true; |
| 400 | } | 406 | } |
| 401 | 407 | ||
| 402 | if (!use_color_fb && !use_depth_fb) { | 408 | if (!use_color && !use_depth && !use_stencil) { |
| 403 | // No color surface nor depth/stencil surface are enabled | 409 | // No color surface nor depth/stencil surface are enabled |
| 404 | return; | 410 | return; |
| 405 | } | 411 | } |
| 406 | 412 | ||
| 407 | if (clear_mask == 0) { | ||
| 408 | // No clear mask is enabled | ||
| 409 | return; | ||
| 410 | } | ||
| 411 | |||
| 412 | ScopeAcquireGLContext acquire_context{emu_window}; | 413 | ScopeAcquireGLContext acquire_context{emu_window}; |
| 413 | 414 | ||
| 414 | ConfigureFramebuffers(use_depth_fb, false); | 415 | ConfigureFramebuffers(use_color, use_depth || use_stencil, false, |
| 416 | regs.clear_buffers.RT.Value()); | ||
| 415 | 417 | ||
| 416 | clear_state.Apply(); | 418 | clear_state.Apply(); |
| 417 | 419 | ||
| 418 | glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2], | 420 | if (use_color) { |
| 419 | regs.clear_color[3]); | 421 | glClearBufferfv(GL_COLOR, regs.clear_buffers.RT, regs.clear_color); |
| 420 | glClearDepth(regs.clear_depth); | 422 | } |
| 421 | glClearStencil(regs.clear_stencil); | ||
| 422 | 423 | ||
| 423 | glClear(clear_mask); | 424 | if (use_depth && use_stencil) { |
| 425 | glClearBufferfi(GL_DEPTH_STENCIL, 0, regs.clear_depth, regs.clear_stencil); | ||
| 426 | } else if (use_depth) { | ||
| 427 | glClearBufferfv(GL_DEPTH, 0, ®s.clear_depth); | ||
| 428 | } else if (use_stencil) { | ||
| 429 | glClearBufferiv(GL_STENCIL, 0, ®s.clear_stencil); | ||
| 430 | } | ||
| 424 | } | 431 | } |
| 425 | 432 | ||
| 426 | void RasterizerOpenGL::DrawArrays() { | 433 | void RasterizerOpenGL::DrawArrays() { |
| @@ -433,7 +440,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 433 | 440 | ||
| 434 | ScopeAcquireGLContext acquire_context{emu_window}; | 441 | ScopeAcquireGLContext acquire_context{emu_window}; |
| 435 | 442 | ||
| 436 | ConfigureFramebuffers(true, true); | 443 | ConfigureFramebuffers(); |
| 437 | 444 | ||
| 438 | SyncDepthTestState(); | 445 | SyncDepthTestState(); |
| 439 | SyncStencilTestState(); | 446 | SyncStencilTestState(); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 3d62cc196..a39f9cdf6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | 14 | ||
| 15 | #include <boost/icl/interval_map.hpp> | 15 | #include <boost/icl/interval_map.hpp> |
| 16 | #include <boost/optional.hpp> | ||
| 16 | #include <boost/range/iterator_range.hpp> | 17 | #include <boost/range/iterator_range.hpp> |
| 17 | #include <glad/glad.h> | 18 | #include <glad/glad.h> |
| 18 | 19 | ||
| @@ -97,8 +98,16 @@ private: | |||
| 97 | GLvec4 border_color; | 98 | GLvec4 border_color; |
| 98 | }; | 99 | }; |
| 99 | 100 | ||
| 100 | /// Configures the color and depth framebuffer states | 101 | /** |
| 101 | void ConfigureFramebuffers(bool using_depth_fb, bool preserve_contents); | 102 | * Configures the color and depth framebuffer states. |
| 103 | * @param use_color_fb If true, configure color framebuffers. | ||
| 104 | * @param using_depth_fb If true, configure the depth/stencil framebuffer. | ||
| 105 | * @param preserve_contents If true, tries to preserve data from a previously used framebuffer. | ||
| 106 | * @param single_color_target Specifies if a single color buffer target should be used. | ||
| 107 | */ | ||
| 108 | void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, | ||
| 109 | bool preserve_contents = true, | ||
| 110 | boost::optional<size_t> single_color_target = {}); | ||
| 102 | 111 | ||
| 103 | /* | 112 | /* |
| 104 | * Configures the current constbuffers to use for the draw command. | 113 | * Configures the current constbuffers to use for the draw command. |