diff options
| author | 2019-02-08 19:40:32 -0400 | |
|---|---|---|
| committer | 2019-02-27 21:58:39 -0400 | |
| commit | 44ea2810e422c6b53e56b26fc8aa918c48b80c8b (patch) | |
| tree | 5524e8379eed1bda7016bcff05d268991ddc4ae9 /src | |
| parent | rasterizer_cache_gl: Notify on framebuffer change (diff) | |
| download | yuzu-44ea2810e422c6b53e56b26fc8aa918c48b80c8b.tar.gz yuzu-44ea2810e422c6b53e56b26fc8aa918c48b80c8b.tar.xz yuzu-44ea2810e422c6b53e56b26fc8aa918c48b80c8b.zip | |
rasterizer_cache: mark reinterpreted surfaces and add ability to reload marked surfaces on next use.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 73 |
2 files changed, 78 insertions, 0 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 2d2bbd6ac..fe81ff227 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -1007,6 +1007,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres | |||
| 1007 | if (surface) { | 1007 | if (surface) { |
| 1008 | if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { | 1008 | if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { |
| 1009 | // Use the cached surface as-is | 1009 | // Use the cached surface as-is |
| 1010 | if (surface->MustReload()) | ||
| 1011 | LoadSurface(surface); | ||
| 1010 | return surface; | 1012 | return surface; |
| 1011 | } else if (preserve_contents) { | 1013 | } else if (preserve_contents) { |
| 1012 | // If surface parameters changed and we care about keeping the previous data, recreate | 1014 | // If surface parameters changed and we care about keeping the previous data, recreate |
| @@ -1014,6 +1016,9 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres | |||
| 1014 | Surface new_surface{RecreateSurface(surface, params)}; | 1016 | Surface new_surface{RecreateSurface(surface, params)}; |
| 1015 | Unregister(surface); | 1017 | Unregister(surface); |
| 1016 | Register(new_surface); | 1018 | Register(new_surface); |
| 1019 | if (new_surface->IsUploaded()) { | ||
| 1020 | RegisterReinterpretSurface(new_surface); | ||
| 1021 | } | ||
| 1017 | return new_surface; | 1022 | return new_surface; |
| 1018 | } else { | 1023 | } else { |
| 1019 | // Delete the old surface before creating a new one to prevent collisions. | 1024 | // Delete the old surface before creating a new one to prevent collisions. |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index cc27fefb5..0b4d720e2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -347,6 +347,10 @@ public: | |||
| 347 | return cached_size_in_bytes; | 347 | return cached_size_in_bytes; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | std::size_t GetMemorySize() const { | ||
| 351 | return memory_size; | ||
| 352 | } | ||
| 353 | |||
| 350 | void Flush() override { | 354 | void Flush() override { |
| 351 | FlushGLBuffer(); | 355 | FlushGLBuffer(); |
| 352 | } | 356 | } |
| @@ -396,6 +400,26 @@ public: | |||
| 396 | Tegra::Texture::SwizzleSource swizzle_z, | 400 | Tegra::Texture::SwizzleSource swizzle_z, |
| 397 | Tegra::Texture::SwizzleSource swizzle_w); | 401 | Tegra::Texture::SwizzleSource swizzle_w); |
| 398 | 402 | ||
| 403 | void MarkReinterpreted() { | ||
| 404 | reinterpreted = true; | ||
| 405 | } | ||
| 406 | |||
| 407 | bool IsReinterpreted() { | ||
| 408 | return reinterpreted; | ||
| 409 | } | ||
| 410 | |||
| 411 | void MarkForReload(bool reload) { | ||
| 412 | must_reload = reload; | ||
| 413 | } | ||
| 414 | |||
| 415 | bool MustReload() { | ||
| 416 | return must_reload; | ||
| 417 | } | ||
| 418 | |||
| 419 | bool IsUploaded() { | ||
| 420 | return params.identity == SurfaceParams::SurfaceClass::Uploaded; | ||
| 421 | } | ||
| 422 | |||
| 399 | private: | 423 | private: |
| 400 | void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); | 424 | void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); |
| 401 | 425 | ||
| @@ -409,6 +433,9 @@ private: | |||
| 409 | GLenum gl_internal_format{}; | 433 | GLenum gl_internal_format{}; |
| 410 | std::size_t cached_size_in_bytes{}; | 434 | std::size_t cached_size_in_bytes{}; |
| 411 | std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; | 435 | std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; |
| 436 | std::size_t memory_size; | ||
| 437 | bool reinterpreted = false; | ||
| 438 | bool must_reload = false; | ||
| 412 | }; | 439 | }; |
| 413 | 440 | ||
| 414 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { | 441 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { |
| @@ -469,6 +496,9 @@ private: | |||
| 469 | OGLFramebuffer read_framebuffer; | 496 | OGLFramebuffer read_framebuffer; |
| 470 | OGLFramebuffer draw_framebuffer; | 497 | OGLFramebuffer draw_framebuffer; |
| 471 | 498 | ||
| 499 | bool run_texception_pass = false; | ||
| 500 | bool texception = false; | ||
| 501 | |||
| 472 | /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one | 502 | /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one |
| 473 | /// using the new format. | 503 | /// using the new format. |
| 474 | OGLBuffer copy_pbo; | 504 | OGLBuffer copy_pbo; |
| @@ -476,6 +506,49 @@ private: | |||
| 476 | std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers; | 506 | std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers; |
| 477 | std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; | 507 | std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; |
| 478 | Surface last_depth_buffer; | 508 | Surface last_depth_buffer; |
| 509 | |||
| 510 | using SurfaceIntervalCache = boost::icl::interval_map<VAddr, Surface>; | ||
| 511 | using SurfaceInterval = typename IntervalCache::interval_type; | ||
| 512 | |||
| 513 | static auto GetReinterpretInterval(const Surface& object) { | ||
| 514 | return SurfaceInterval::right_open(object->GetAddr() + 1, | ||
| 515 | object->GetAddr() + object->GetMemorySize() - 1); | ||
| 516 | } | ||
| 517 | |||
| 518 | // Reinterpreted surfaces are very fragil as the game may keep rendering into them. | ||
| 519 | SurfaceIntervalCache reinterpreted_surfaces; | ||
| 520 | |||
| 521 | void RegisterReinterpretSurface(Surface r_surface) { | ||
| 522 | auto interval = GetReinterpretInterval(r_surface); | ||
| 523 | reinterpreted_surfaces.insert({interval, r_surface}); | ||
| 524 | r_surface->MarkReinterpreted(); | ||
| 525 | run_texception_pass = true; | ||
| 526 | } | ||
| 527 | |||
| 528 | Surface CollideOnReinterpretedSurface(VAddr addr) const { | ||
| 529 | const SurfaceInterval interval{addr}; | ||
| 530 | for (auto& pair : | ||
| 531 | boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) { | ||
| 532 | return pair.second; | ||
| 533 | } | ||
| 534 | return nullptr; | ||
| 535 | } | ||
| 536 | |||
| 537 | protected: | ||
| 538 | void Register(const Surface& object) { | ||
| 539 | RasterizerCache<Surface>::Register(object); | ||
| 540 | } | ||
| 541 | |||
| 542 | /// Unregisters an object from the cache | ||
| 543 | void Unregister(const Surface& object) { | ||
| 544 | const auto& params = object->GetSurfaceParams(); | ||
| 545 | if (object->IsReinterpreted()) { | ||
| 546 | auto interval = GetReinterpretInterval(object); | ||
| 547 | reinterpreted_surfaces.erase(interval); | ||
| 548 | } | ||
| 549 | RasterizerCache<Surface>::Unregister(object); | ||
| 550 | } | ||
| 551 | |||
| 479 | }; | 552 | }; |
| 480 | 553 | ||
| 481 | } // namespace OpenGL | 554 | } // namespace OpenGL |