diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/rasterizer_cache.h | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 124 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 83 |
4 files changed, 213 insertions, 16 deletions
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index bcf0c15a4..a7bcf26fb 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h | |||
| @@ -129,6 +129,15 @@ protected: | |||
| 129 | return ++modified_ticks; | 129 | return ++modified_ticks; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | /// Flushes the specified object, updating appropriate cache state as needed | ||
| 133 | void FlushObject(const T& object) { | ||
| 134 | if (!object->IsDirty()) { | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | object->Flush(); | ||
| 138 | object->MarkAsModified(false, *this); | ||
| 139 | } | ||
| 140 | |||
| 132 | private: | 141 | private: |
| 133 | /// Returns a list of cached objects from the specified memory region, ordered by access time | 142 | /// Returns a list of cached objects from the specified memory region, ordered by access time |
| 134 | std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) { | 143 | std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) { |
| @@ -154,15 +163,6 @@ private: | |||
| 154 | return objects; | 163 | return objects; |
| 155 | } | 164 | } |
| 156 | 165 | ||
| 157 | /// Flushes the specified object, updating appropriate cache state as needed | ||
| 158 | void FlushObject(const T& object) { | ||
| 159 | if (!object->IsDirty()) { | ||
| 160 | return; | ||
| 161 | } | ||
| 162 | object->Flush(); | ||
| 163 | object->MarkAsModified(false, *this); | ||
| 164 | } | ||
| 165 | |||
| 166 | using ObjectSet = std::set<T>; | 166 | using ObjectSet = std::set<T>; |
| 167 | using ObjectCache = std::unordered_map<VAddr, T>; | 167 | using ObjectCache = std::unordered_map<VAddr, T>; |
| 168 | using IntervalCache = boost::icl::interval_map<VAddr, ObjectSet>; | 168 | using IntervalCache = boost::icl::interval_map<VAddr, ObjectSet>; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 523ed10fa..c8c1d6911 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -738,9 +738,13 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 738 | shader_program_manager->ApplyTo(state); | 738 | shader_program_manager->ApplyTo(state); |
| 739 | state.Apply(); | 739 | state.Apply(); |
| 740 | 740 | ||
| 741 | res_cache.SignalPreDrawCall(); | ||
| 742 | |||
| 741 | // Execute draw call | 743 | // Execute draw call |
| 742 | params.DispatchDraw(); | 744 | params.DispatchDraw(); |
| 743 | 745 | ||
| 746 | res_cache.SignalPostDrawCall(); | ||
| 747 | |||
| 744 | // Disable scissor test | 748 | // Disable scissor test |
| 745 | state.viewports[0].scissor.enabled = false; | 749 | state.viewports[0].scissor.enabled = false; |
| 746 | 750 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 81b6099f9..5fdf1164d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <optional> | ||
| 6 | #include <glad/glad.h> | 7 | #include <glad/glad.h> |
| 7 | 8 | ||
| 8 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| @@ -549,6 +550,8 @@ CachedSurface::CachedSurface(const SurfaceParams& params) | |||
| 549 | // alternatives. This signals a bug on those functions. | 550 | // alternatives. This signals a bug on those functions. |
| 550 | const auto width = static_cast<GLsizei>(params.MipWidth(0)); | 551 | const auto width = static_cast<GLsizei>(params.MipWidth(0)); |
| 551 | const auto height = static_cast<GLsizei>(params.MipHeight(0)); | 552 | const auto height = static_cast<GLsizei>(params.MipHeight(0)); |
| 553 | memory_size = params.MemorySize(); | ||
| 554 | reinterpreted = false; | ||
| 552 | 555 | ||
| 553 | const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); | 556 | const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type); |
| 554 | gl_internal_format = format_tuple.internal_format; | 557 | gl_internal_format = format_tuple.internal_format; |
| @@ -970,22 +973,23 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre | |||
| 970 | ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); | 973 | ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); |
| 971 | 974 | ||
| 972 | if (index >= regs.rt_control.count) { | 975 | if (index >= regs.rt_control.count) { |
| 973 | return last_color_buffers[index] = {}; | 976 | return current_color_buffers[index] = {}; |
| 974 | } | 977 | } |
| 975 | 978 | ||
| 976 | if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { | 979 | if (regs.rt[index].Address() == 0 || regs.rt[index].format == Tegra::RenderTargetFormat::NONE) { |
| 977 | return last_color_buffers[index] = {}; | 980 | return current_color_buffers[index] = {}; |
| 978 | } | 981 | } |
| 979 | 982 | ||
| 980 | const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)}; | 983 | const SurfaceParams color_params{SurfaceParams::CreateForFramebuffer(index)}; |
| 981 | 984 | ||
| 982 | return last_color_buffers[index] = GetSurface(color_params, preserve_contents); | 985 | return current_color_buffers[index] = GetSurface(color_params, preserve_contents); |
| 983 | } | 986 | } |
| 984 | 987 | ||
| 985 | void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { | 988 | void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { |
| 986 | surface->LoadGLBuffer(); | 989 | surface->LoadGLBuffer(); |
| 987 | surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); | 990 | surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle); |
| 988 | surface->MarkAsModified(false, *this); | 991 | surface->MarkAsModified(false, *this); |
| 992 | surface->MarkForReload(false); | ||
| 989 | } | 993 | } |
| 990 | 994 | ||
| 991 | Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) { | 995 | Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) { |
| @@ -997,18 +1001,23 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres | |||
| 997 | Surface surface{TryGet(params.addr)}; | 1001 | Surface surface{TryGet(params.addr)}; |
| 998 | if (surface) { | 1002 | if (surface) { |
| 999 | if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { | 1003 | if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { |
| 1000 | // Use the cached surface as-is | 1004 | // Use the cached surface as-is unless it's not synced with memory |
| 1005 | if (surface->MustReload()) | ||
| 1006 | LoadSurface(surface); | ||
| 1001 | return surface; | 1007 | return surface; |
| 1002 | } else if (preserve_contents) { | 1008 | } else if (preserve_contents) { |
| 1003 | // If surface parameters changed and we care about keeping the previous data, recreate | 1009 | // If surface parameters changed and we care about keeping the previous data, recreate |
| 1004 | // the surface from the old one | 1010 | // the surface from the old one |
| 1005 | Surface new_surface{RecreateSurface(surface, params)}; | 1011 | Surface new_surface{RecreateSurface(surface, params)}; |
| 1006 | Unregister(surface); | 1012 | UnregisterSurface(surface); |
| 1007 | Register(new_surface); | 1013 | Register(new_surface); |
| 1014 | if (new_surface->IsUploaded()) { | ||
| 1015 | RegisterReinterpretSurface(new_surface); | ||
| 1016 | } | ||
| 1008 | return new_surface; | 1017 | return new_surface; |
| 1009 | } else { | 1018 | } else { |
| 1010 | // Delete the old surface before creating a new one to prevent collisions. | 1019 | // Delete the old surface before creating a new one to prevent collisions. |
| 1011 | Unregister(surface); | 1020 | UnregisterSurface(surface); |
| 1012 | } | 1021 | } |
| 1013 | } | 1022 | } |
| 1014 | 1023 | ||
| @@ -1290,4 +1299,107 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params | |||
| 1290 | return {}; | 1299 | return {}; |
| 1291 | } | 1300 | } |
| 1292 | 1301 | ||
| 1302 | static std::optional<u32> TryFindBestMipMap(std::size_t memory, const SurfaceParams params, | ||
| 1303 | u32 height) { | ||
| 1304 | for (u32 i = 0; i < params.max_mip_level; i++) { | ||
| 1305 | if (memory == params.GetMipmapSingleSize(i) && params.MipHeight(i) == height) { | ||
| 1306 | return {i}; | ||
| 1307 | } | ||
| 1308 | } | ||
| 1309 | return {}; | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | static std::optional<u32> TryFindBestLayer(VAddr addr, const SurfaceParams params, u32 mipmap) { | ||
| 1313 | const std::size_t size = params.LayerMemorySize(); | ||
| 1314 | VAddr start = params.addr + params.GetMipmapLevelOffset(mipmap); | ||
| 1315 | for (u32 i = 0; i < params.depth; i++) { | ||
| 1316 | if (start == addr) { | ||
| 1317 | return {i}; | ||
| 1318 | } | ||
| 1319 | start += size; | ||
| 1320 | } | ||
| 1321 | return {}; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | static bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface render_surface, | ||
| 1325 | const Surface blitted_surface) { | ||
| 1326 | const auto& dst_params = blitted_surface->GetSurfaceParams(); | ||
| 1327 | const auto& src_params = render_surface->GetSurfaceParams(); | ||
| 1328 | const std::size_t src_memory_size = src_params.size_in_bytes; | ||
| 1329 | const std::optional<u32> level = | ||
| 1330 | TryFindBestMipMap(src_memory_size, dst_params, src_params.height); | ||
| 1331 | if (level.has_value()) { | ||
| 1332 | if (src_params.width == dst_params.MipWidthGobAligned(*level) && | ||
| 1333 | src_params.height == dst_params.MipHeight(*level) && | ||
| 1334 | src_params.block_height >= dst_params.MipBlockHeight(*level)) { | ||
| 1335 | const std::optional<u32> slot = | ||
| 1336 | TryFindBestLayer(render_surface->GetAddr(), dst_params, *level); | ||
| 1337 | if (slot.has_value()) { | ||
| 1338 | glCopyImageSubData(render_surface->Texture().handle, | ||
| 1339 | SurfaceTargetToGL(src_params.target), 0, 0, 0, 0, | ||
| 1340 | blitted_surface->Texture().handle, | ||
| 1341 | SurfaceTargetToGL(dst_params.target), *level, 0, 0, *slot, | ||
| 1342 | dst_params.MipWidth(*level), dst_params.MipHeight(*level), 1); | ||
| 1343 | blitted_surface->MarkAsModified(true, cache); | ||
| 1344 | return true; | ||
| 1345 | } | ||
| 1346 | } | ||
| 1347 | } | ||
| 1348 | return false; | ||
| 1349 | } | ||
| 1350 | |||
| 1351 | static bool IsReinterpretInvalid(const Surface render_surface, const Surface blitted_surface) { | ||
| 1352 | const VAddr bound1 = blitted_surface->GetAddr() + blitted_surface->GetMemorySize(); | ||
| 1353 | const VAddr bound2 = render_surface->GetAddr() + render_surface->GetMemorySize(); | ||
| 1354 | if (bound2 > bound1) | ||
| 1355 | return true; | ||
| 1356 | const auto& dst_params = blitted_surface->GetSurfaceParams(); | ||
| 1357 | const auto& src_params = render_surface->GetSurfaceParams(); | ||
| 1358 | return (dst_params.component_type != src_params.component_type); | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | static bool IsReinterpretInvalidSecond(const Surface render_surface, | ||
| 1362 | const Surface blitted_surface) { | ||
| 1363 | const auto& dst_params = blitted_surface->GetSurfaceParams(); | ||
| 1364 | const auto& src_params = render_surface->GetSurfaceParams(); | ||
| 1365 | return (dst_params.height > src_params.height && dst_params.width > src_params.width); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface, | ||
| 1369 | Surface intersect) { | ||
| 1370 | if (IsReinterpretInvalid(triggering_surface, intersect)) { | ||
| 1371 | UnregisterSurface(intersect); | ||
| 1372 | return false; | ||
| 1373 | } | ||
| 1374 | if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) { | ||
| 1375 | if (IsReinterpretInvalidSecond(triggering_surface, intersect)) { | ||
| 1376 | UnregisterSurface(intersect); | ||
| 1377 | return false; | ||
| 1378 | } | ||
| 1379 | FlushObject(intersect); | ||
| 1380 | FlushObject(triggering_surface); | ||
| 1381 | intersect->MarkForReload(true); | ||
| 1382 | } | ||
| 1383 | return true; | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | void RasterizerCacheOpenGL::SignalPreDrawCall() { | ||
| 1387 | if (texception && GLAD_GL_ARB_texture_barrier) { | ||
| 1388 | glTextureBarrier(); | ||
| 1389 | } | ||
| 1390 | texception = false; | ||
| 1391 | } | ||
| 1392 | |||
| 1393 | void RasterizerCacheOpenGL::SignalPostDrawCall() { | ||
| 1394 | for (u32 i = 0; i < Maxwell::NumRenderTargets; i++) { | ||
| 1395 | if (current_color_buffers[i] != nullptr) { | ||
| 1396 | Surface intersect = CollideOnReinterpretedSurface(current_color_buffers[i]->GetAddr()); | ||
| 1397 | if (intersect != nullptr) { | ||
| 1398 | PartialReinterpretSurface(current_color_buffers[i], intersect); | ||
| 1399 | texception = true; | ||
| 1400 | } | ||
| 1401 | } | ||
| 1402 | } | ||
| 1403 | } | ||
| 1404 | |||
| 1293 | } // namespace OpenGL | 1405 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 838554c35..797bbdc9c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -34,6 +34,7 @@ using SurfaceTarget = VideoCore::Surface::SurfaceTarget; | |||
| 34 | using SurfaceType = VideoCore::Surface::SurfaceType; | 34 | using SurfaceType = VideoCore::Surface::SurfaceType; |
| 35 | using PixelFormat = VideoCore::Surface::PixelFormat; | 35 | using PixelFormat = VideoCore::Surface::PixelFormat; |
| 36 | using ComponentType = VideoCore::Surface::ComponentType; | 36 | using ComponentType = VideoCore::Surface::ComponentType; |
| 37 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||
| 37 | 38 | ||
| 38 | struct SurfaceParams { | 39 | struct SurfaceParams { |
| 39 | enum class SurfaceClass { | 40 | enum class SurfaceClass { |
| @@ -140,10 +141,18 @@ struct SurfaceParams { | |||
| 140 | return offset; | 141 | return offset; |
| 141 | } | 142 | } |
| 142 | 143 | ||
| 144 | std::size_t GetMipmapSingleSize(u32 mip_level) const { | ||
| 145 | return InnerMipmapMemorySize(mip_level, false, is_layered); | ||
| 146 | } | ||
| 147 | |||
| 143 | u32 MipWidth(u32 mip_level) const { | 148 | u32 MipWidth(u32 mip_level) const { |
| 144 | return std::max(1U, width >> mip_level); | 149 | return std::max(1U, width >> mip_level); |
| 145 | } | 150 | } |
| 146 | 151 | ||
| 152 | u32 MipWidthGobAligned(u32 mip_level) const { | ||
| 153 | return Common::AlignUp(std::max(1U, width >> mip_level), 64U * 8U / GetFormatBpp()); | ||
| 154 | } | ||
| 155 | |||
| 147 | u32 MipHeight(u32 mip_level) const { | 156 | u32 MipHeight(u32 mip_level) const { |
| 148 | return std::max(1U, height >> mip_level); | 157 | return std::max(1U, height >> mip_level); |
| 149 | } | 158 | } |
| @@ -346,6 +355,10 @@ public: | |||
| 346 | return cached_size_in_bytes; | 355 | return cached_size_in_bytes; |
| 347 | } | 356 | } |
| 348 | 357 | ||
| 358 | std::size_t GetMemorySize() const { | ||
| 359 | return memory_size; | ||
| 360 | } | ||
| 361 | |||
| 349 | void Flush() override { | 362 | void Flush() override { |
| 350 | FlushGLBuffer(); | 363 | FlushGLBuffer(); |
| 351 | } | 364 | } |
| @@ -395,6 +408,26 @@ public: | |||
| 395 | Tegra::Texture::SwizzleSource swizzle_z, | 408 | Tegra::Texture::SwizzleSource swizzle_z, |
| 396 | Tegra::Texture::SwizzleSource swizzle_w); | 409 | Tegra::Texture::SwizzleSource swizzle_w); |
| 397 | 410 | ||
| 411 | void MarkReinterpreted() { | ||
| 412 | reinterpreted = true; | ||
| 413 | } | ||
| 414 | |||
| 415 | bool IsReinterpreted() const { | ||
| 416 | return reinterpreted; | ||
| 417 | } | ||
| 418 | |||
| 419 | void MarkForReload(bool reload) { | ||
| 420 | must_reload = reload; | ||
| 421 | } | ||
| 422 | |||
| 423 | bool MustReload() const { | ||
| 424 | return must_reload; | ||
| 425 | } | ||
| 426 | |||
| 427 | bool IsUploaded() const { | ||
| 428 | return params.identity == SurfaceParams::SurfaceClass::Uploaded; | ||
| 429 | } | ||
| 430 | |||
| 398 | private: | 431 | private: |
| 399 | void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); | 432 | void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); |
| 400 | 433 | ||
| @@ -408,6 +441,9 @@ private: | |||
| 408 | GLenum gl_internal_format{}; | 441 | GLenum gl_internal_format{}; |
| 409 | std::size_t cached_size_in_bytes{}; | 442 | std::size_t cached_size_in_bytes{}; |
| 410 | std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; | 443 | std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; |
| 444 | std::size_t memory_size; | ||
| 445 | bool reinterpreted = false; | ||
| 446 | bool must_reload = false; | ||
| 411 | }; | 447 | }; |
| 412 | 448 | ||
| 413 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { | 449 | class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { |
| @@ -433,6 +469,9 @@ public: | |||
| 433 | const Common::Rectangle<u32>& src_rect, | 469 | const Common::Rectangle<u32>& src_rect, |
| 434 | const Common::Rectangle<u32>& dst_rect); | 470 | const Common::Rectangle<u32>& dst_rect); |
| 435 | 471 | ||
| 472 | void SignalPreDrawCall(); | ||
| 473 | void SignalPostDrawCall(); | ||
| 474 | |||
| 436 | private: | 475 | private: |
| 437 | void LoadSurface(const Surface& surface); | 476 | void LoadSurface(const Surface& surface); |
| 438 | Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); | 477 | Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); |
| @@ -449,6 +488,10 @@ private: | |||
| 449 | /// Tries to get a reserved surface for the specified parameters | 488 | /// Tries to get a reserved surface for the specified parameters |
| 450 | Surface TryGetReservedSurface(const SurfaceParams& params); | 489 | Surface TryGetReservedSurface(const SurfaceParams& params); |
| 451 | 490 | ||
| 491 | // Partialy reinterpret a surface based on a triggering_surface that collides with it. | ||
| 492 | // returns true if the reinterpret was successful, false in case it was not. | ||
| 493 | bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect); | ||
| 494 | |||
| 452 | /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data | 495 | /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data |
| 453 | void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); | 496 | void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); |
| 454 | void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); | 497 | void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); |
| @@ -465,12 +508,50 @@ private: | |||
| 465 | OGLFramebuffer read_framebuffer; | 508 | OGLFramebuffer read_framebuffer; |
| 466 | OGLFramebuffer draw_framebuffer; | 509 | OGLFramebuffer draw_framebuffer; |
| 467 | 510 | ||
| 511 | bool texception = false; | ||
| 512 | |||
| 468 | /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one | 513 | /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one |
| 469 | /// using the new format. | 514 | /// using the new format. |
| 470 | OGLBuffer copy_pbo; | 515 | OGLBuffer copy_pbo; |
| 471 | 516 | ||
| 472 | std::array<Surface, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> last_color_buffers; | 517 | std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers; |
| 518 | std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; | ||
| 473 | Surface last_depth_buffer; | 519 | Surface last_depth_buffer; |
| 520 | |||
| 521 | using SurfaceIntervalCache = boost::icl::interval_map<VAddr, Surface>; | ||
| 522 | using SurfaceInterval = typename SurfaceIntervalCache::interval_type; | ||
| 523 | |||
| 524 | static auto GetReinterpretInterval(const Surface& object) { | ||
| 525 | return SurfaceInterval::right_open(object->GetAddr() + 1, | ||
| 526 | object->GetAddr() + object->GetMemorySize() - 1); | ||
| 527 | } | ||
| 528 | |||
| 529 | // Reinterpreted surfaces are very fragil as the game may keep rendering into them. | ||
| 530 | SurfaceIntervalCache reinterpreted_surfaces; | ||
| 531 | |||
| 532 | void RegisterReinterpretSurface(Surface reinterpret_surface) { | ||
| 533 | auto interval = GetReinterpretInterval(reinterpret_surface); | ||
| 534 | reinterpreted_surfaces.insert({interval, reinterpret_surface}); | ||
| 535 | reinterpret_surface->MarkReinterpreted(); | ||
| 536 | } | ||
| 537 | |||
| 538 | Surface CollideOnReinterpretedSurface(VAddr addr) const { | ||
| 539 | const SurfaceInterval interval{addr}; | ||
| 540 | for (auto& pair : | ||
| 541 | boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) { | ||
| 542 | return pair.second; | ||
| 543 | } | ||
| 544 | return nullptr; | ||
| 545 | } | ||
| 546 | |||
| 547 | /// Unregisters an object from the cache | ||
| 548 | void UnregisterSurface(const Surface& object) { | ||
| 549 | if (object->IsReinterpreted()) { | ||
| 550 | auto interval = GetReinterpretInterval(object); | ||
| 551 | reinterpreted_surfaces.erase(interval); | ||
| 552 | } | ||
| 553 | Unregister(object); | ||
| 554 | } | ||
| 474 | }; | 555 | }; |
| 475 | 556 | ||
| 476 | } // namespace OpenGL | 557 | } // namespace OpenGL |