From 6ce2c850470e4d0600d69a11ae2347a643a44a65 Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow <fsahmkow27@gmail.com>
Date: Sat, 20 Jul 2019 12:54:31 -0400
Subject: [PATCH] Buffer_Cache: Implement flushing.

---
 src/video_core/buffer_cache/buffer_cache.h    | 27 ++++++++++++++++++-
 .../renderer_opengl/gl_buffer_cache.cpp       |  4 +++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 03b2882336..38ce16ed59 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -79,12 +79,16 @@ public:
     }
 
     void Map(std::size_t max_size) {
+        std::lock_guard lock{mutex};
+
         std::tie(buffer_ptr, buffer_offset_base, invalidated) = stream_buffer->Map(max_size, 4);
         buffer_offset = buffer_offset_base;
     }
 
     /// Finishes the upload stream, returns true on bindings invalidation.
     bool Unmap() {
+        std::lock_guard lock{mutex};
+
         stream_buffer->Unmap(buffer_offset - buffer_offset_base);
         return std::exchange(invalidated, false);
     }
@@ -103,7 +107,15 @@ public:
     void FlushRegion(CacheAddr addr, std::size_t size) {
         std::lock_guard lock{mutex};
 
-        // TODO
+        std::vector<MapInterval> objects = GetMapsInRange(addr, size);
+        std::sort(objects.begin(), objects.end(), [](const MapInterval& a, const MapInterval& b) {
+            return a->GetModificationTick() < b->GetModificationTick();
+        });
+        for (auto& object : objects) {
+            if (object->IsModified() && object->IsRegistered()) {
+                FlushMap(object);
+            }
+        }
     }
 
     /// Mark the specified region as being invalidated
@@ -205,11 +217,13 @@ private:
         CacheAddr new_start = cache_addr;
         CacheAddr new_end = cache_addr_end;
         bool write_inheritance = false;
+        bool modified_inheritance = false;
         // Calculate new buffer parameters
         for (auto& overlap : overlaps) {
             new_start = std::min(overlap->GetStart(), new_start);
             new_end = std::max(overlap->GetEnd(), new_end);
             write_inheritance |= overlap->IsWritten();
+            modified_inheritance |= overlap->IsModified();
         }
         GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
         for (auto& overlap : overlaps) {
@@ -217,6 +231,9 @@ private:
         }
         UpdateBlock(block, new_start, new_end, overlaps);
         MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
+        if (modified_inheritance) {
+            new_map->MarkAsModified(true, GetModifiedTicks());
+        }
         Register(new_map, write_inheritance);
         return new_map;
     }
@@ -258,6 +275,14 @@ private:
         return ++modified_ticks;
     }
 
+    void FlushMap(MapInterval map) {
+        std::size_t size = map->GetEnd() - map->GetStart();
+        TBuffer block = blocks[map->GetStart() >> block_page_bits];
+        u8* host_ptr = FromCacheAddr(map->GetStart());
+        DownloadBlockData(block, block->GetOffset(map->GetStart()), size, host_ptr);
+        map->MarkAsModified(false, 0);
+    }
+
     BufferInfo StreamBufferUpload(const void* raw_pointer, std::size_t size,
                                   std::size_t alignment) {
         AlignBuffer(alignment);
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index a45d2771ba..0781e65951 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -7,12 +7,15 @@
 #include <glad/glad.h>
 
 #include "common/assert.h"
+#include "common/microprofile.h"
 #include "video_core/renderer_opengl/gl_buffer_cache.h"
 #include "video_core/renderer_opengl/gl_rasterizer.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 
 namespace OpenGL {
 
+MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
+
 CachedBufferBlock::CachedBufferBlock(CacheAddr cache_addr, const std::size_t size)
     : VideoCommon::BufferBlock{cache_addr, size} {
     gl_buffer.Create();
@@ -53,6 +56,7 @@ void OGLBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, s
 
 void OGLBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
                                        u8* data) {
+    MICROPROFILE_SCOPE(OpenGL_Buffer_Download);
     glGetNamedBufferSubData(*buffer->GetHandle(), static_cast<GLintptr>(offset),
                             static_cast<GLsizeiptr>(size), data);
 }