summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp85
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h3
2 files changed, 86 insertions, 2 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index bb53a2821..28f0bc379 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -254,6 +254,60 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup
254 cur_state.Apply(); 254 cur_state.Apply();
255} 255}
256 256
257static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
258 const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
259 GLuint read_fb_handle, GLuint draw_fb_handle) {
260 OpenGLState prev_state{OpenGLState::GetCurState()};
261 SCOPE_EXIT({ prev_state.Apply(); });
262
263 OpenGLState state;
264 state.draw.read_framebuffer = read_fb_handle;
265 state.draw.draw_framebuffer = draw_fb_handle;
266 state.Apply();
267
268 u32 buffers{};
269
270 if (type == SurfaceType::ColorTexture) {
271 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
272 0);
273 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
274 0);
275
276 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex,
277 0);
278 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
279 0);
280
281 buffers = GL_COLOR_BUFFER_BIT;
282 } else if (type == SurfaceType::Depth) {
283 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
284 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0);
285 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
286
287 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
288 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0);
289 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
290
291 buffers = GL_DEPTH_BUFFER_BIT;
292 } else if (type == SurfaceType::DepthStencil) {
293 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
294 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
295 src_tex, 0);
296
297 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
298 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
299 dst_tex, 0);
300
301 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
302 }
303
304 glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, dst_rect.left,
305 dst_rect.bottom, dst_rect.right, dst_rect.top, buffers,
306 buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
307
308 return true;
309}
310
257CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) { 311CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) {
258 texture.Create(); 312 texture.Create();
259 const auto& rect{params.GetRect()}; 313 const auto& rect{params.GetRect()};
@@ -580,19 +634,25 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
580 if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none) 634 if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none)
581 return {}; 635 return {};
582 636
583 // Check for an exact match in existing surfaces 637 // Look up surface in the cache based on address
584 const auto& search{surface_cache.find(params.addr)}; 638 const auto& search{surface_cache.find(params.addr)};
585 Surface surface; 639 Surface surface;
586 if (search != surface_cache.end()) { 640 if (search != surface_cache.end()) {
587 surface = search->second; 641 surface = search->second;
588 if (surface->GetSurfaceParams() != params || Settings::values.use_accurate_framebuffers) { 642 if (Settings::values.use_accurate_framebuffers) {
643 // If use_accurate_framebuffers is enabled, always load from memory
589 FlushSurface(surface); 644 FlushSurface(surface);
590 UnregisterSurface(surface); 645 UnregisterSurface(surface);
646 } else if (surface->GetSurfaceParams() != params) {
647 // If surface parameters changed, recreate the surface from the old one
648 return RecreateSurface(surface, params);
591 } else { 649 } else {
650 // Use the cached surface as-is
592 return surface; 651 return surface;
593 } 652 }
594 } 653 }
595 654
655 // No surface found - create a new one
596 surface = std::make_shared<CachedSurface>(params); 656 surface = std::make_shared<CachedSurface>(params);
597 RegisterSurface(surface); 657 RegisterSurface(surface);
598 LoadSurface(surface); 658 LoadSurface(surface);
@@ -600,6 +660,27 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
600 return surface; 660 return surface;
601} 661}
602 662
663Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
664 const SurfaceParams& new_params) {
665 // Verify surface is compatible for blitting
666 const auto& params{surface->GetSurfaceParams()};
667 ASSERT(params.type == new_params.type);
668 ASSERT(params.pixel_format == new_params.pixel_format);
669 ASSERT(params.component_type == new_params.component_type);
670
671 // Create a new surface with the new parameters, and blit the previous surface to it
672 Surface new_surface{std::make_shared<CachedSurface>(new_params)};
673 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
674 new_surface->GetSurfaceParams().GetRect(), params.type, read_framebuffer.handle,
675 draw_framebuffer.handle);
676
677 // Update cache accordingly
678 UnregisterSurface(surface);
679 RegisterSurface(new_surface);
680
681 return new_surface;
682}
683
603Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const { 684Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const {
604 // Tries to find the GPU address of a framebuffer based on the CPU address. This is because 685 // Tries to find the GPU address of a framebuffer based on the CPU address. This is because
605 // final output framebuffers are specified by CPU address, but internally our GPU cache uses 686 // final output framebuffers are specified by CPU address, but internally our GPU cache uses
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 5124199b2..b084c4db4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -454,6 +454,9 @@ private:
454 void LoadSurface(const Surface& surface); 454 void LoadSurface(const Surface& surface);
455 Surface GetSurface(const SurfaceParams& params); 455 Surface GetSurface(const SurfaceParams& params);
456 456
457 /// Recreates a surface with new parameters
458 Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params);
459
457 /// Register surface into the cache 460 /// Register surface into the cache
458 void RegisterSurface(const Surface& surface); 461 void RegisterSurface(const Surface& surface);
459 462