summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-02-27 21:17:55 -0500
committerGravatar GitHub2019-02-27 21:17:55 -0500
commit1f5d6a8fed1714d999adfd27f97263404e53469e (patch)
tree6773c27510ded54f50c5852b81918b008b2b9945 /src
parentMerge pull request #2172 from lioncash/reorder (diff)
parentDevirtualize Register/Unregister and use a wrapper instead. (diff)
downloadyuzu-1f5d6a8fed1714d999adfd27f97263404e53469e.tar.gz
yuzu-1f5d6a8fed1714d999adfd27f97263404e53469e.tar.xz
yuzu-1f5d6a8fed1714d999adfd27f97263404e53469e.zip
Merge pull request #2121 from FernandoS27/texception2
Improve the Accuracy of the Rasterizer Cache through a Texception Pass
Diffstat (limited to '')
-rw-r--r--src/video_core/rasterizer_cache.h18
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp124
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h83
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
132private: 141private:
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
985void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) { 988void 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
991Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) { 995Surface 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
1302static 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
1312static 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
1324static 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
1351static 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
1361static 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
1368bool 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
1386void RasterizerCacheOpenGL::SignalPreDrawCall() {
1387 if (texception && GLAD_GL_ARB_texture_barrier) {
1388 glTextureBarrier();
1389 }
1390 texception = false;
1391}
1392
1393void 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;
34using SurfaceType = VideoCore::Surface::SurfaceType; 34using SurfaceType = VideoCore::Surface::SurfaceType;
35using PixelFormat = VideoCore::Surface::PixelFormat; 35using PixelFormat = VideoCore::Surface::PixelFormat;
36using ComponentType = VideoCore::Surface::ComponentType; 36using ComponentType = VideoCore::Surface::ComponentType;
37using Maxwell = Tegra::Engines::Maxwell3D::Regs;
37 38
38struct SurfaceParams { 39struct 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
398private: 431private:
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
413class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { 449class 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
436private: 475private:
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