summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2018-10-16 22:51:53 +0200
committerbunnei <bunneidev@gmail.com>2018-10-16 22:51:53 +0200
commit91602de7f27e391c8e322a2670ef9d50a64f7517 (patch)
tree82338c004e99032bf195b173f0c0ea7ed34c4f02
parentgl_rasterizer_cache: Refactor to only call GetRegionEnd on surface creation. (diff)
downloadyuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar.gz
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar.bz2
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar.lz
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar.xz
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.tar.zst
yuzu-91602de7f27e391c8e322a2670ef9d50a64f7517.zip
-rw-r--r--src/video_core/rasterizer_cache.h132
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h10
6 files changed, 116 insertions, 63 deletions
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index 76743a85b..3ec01b967 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -15,45 +15,73 @@
#include "video_core/rasterizer_interface.h"
#include "video_core/renderer_base.h"
+class RasterizerCacheObject {
+public:
+ /// Gets the address of the shader in guest memory, required for cache management
+ virtual VAddr GetAddr() const = 0;
+
+ /// Gets the size of the shader in guest memory, required for cache management
+ virtual std::size_t GetSizeInBytes() const = 0;
+
+ /// Wriets any cached resources back to memory
+ virtual void Flush() = 0;
+
+ /// Sets whether the cached object should be considered registered
+ void SetIsRegistered(bool registered) {
+ is_registered = registered;
+ }
+
+ /// Returns true if the cached object is registered
+ bool IsRegistered() const {
+ return is_registered;
+ }
+
+ /// Returns true if the cached object is dirty
+ bool IsDirty() const {
+ return is_dirty;
+ }
+
+ /// Returns ticks from when this cached object was last modified
+ u64 GetLastModifiedTicks() const {
+ return last_modified_ticks;
+ }
+
+ /// Marks an object as recently modified, used to specify whether it is clean or dirty
+ template <class T>
+ void MarkAsModified(bool dirty, T& cache) {
+ is_dirty = dirty;
+ last_modified_ticks = cache.GetModifiedTicks();
+ }
+
+private:
+ bool is_registered{}; ///< Whether the object is currently registered with the cache
+ bool is_dirty{}; ///< Whether the object is dirty (out of sync with guest memory)
+ u64 last_modified_ticks{}; ///< When the object was last modified, used for in-order flushing
+};
+
template <class T>
class RasterizerCache : NonCopyable {
+ friend class RasterizerCacheObject;
+
public:
- /// Write any cached resources overlapping the region back to memory (if dirty)
+ /// Write any cached resources overlapping the specified region back to memory
void FlushRegion(Tegra::GPUVAddr addr, size_t size) {
- if (size == 0)
- return;
-
- const ObjectInterval interval{addr, addr + size};
- for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
- for (auto& cached_object : pair.second) {
- if (!cached_object)
- continue;
-
- cached_object->Flush();
- }
+ const auto& objects{GetSortedObjectsFromRegion(addr, size)};
+ for (auto& object : objects) {
+ FlushObject(object);
}
}
/// Mark the specified region as being invalidated
void InvalidateRegion(VAddr addr, u64 size) {
- if (size == 0)
- return;
-
- const ObjectInterval interval{addr, addr + size};
- for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
- for (auto& cached_object : pair.second) {
- if (!cached_object)
- continue;
-
- remove_objects.emplace(cached_object);
+ const auto& objects{GetSortedObjectsFromRegion(addr, size)};
+ for (auto& object : objects) {
+ if (!object->IsRegistered()) {
+ // Skip duplicates
+ continue;
}
+ Unregister(object);
}
-
- for (auto& remove_object : remove_objects) {
- Unregister(remove_object);
- }
-
- remove_objects.clear();
}
/// Invalidates everything in the cache
@@ -79,6 +107,7 @@ protected:
/// Register an object into the cache
void Register(const T& object) {
+ object->SetIsRegistered(true);
object_cache.add({GetInterval(object), ObjectSet{object}});
auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
@@ -86,18 +115,57 @@ protected:
/// Unregisters an object from the cache
void Unregister(const T& object) {
+ object->SetIsRegistered(false);
auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
+ // Only flush if use_accurate_framebuffers is enabled, as it incurs a performance hit
if (Settings::values.use_accurate_framebuffers) {
- // Only flush if use_accurate_framebuffers is enabled, as it incurs a performance hit
- object->Flush();
+ FlushObject(object);
}
object_cache.subtract({GetInterval(object), ObjectSet{object}});
}
+ /// Returns a ticks counter used for tracking when cached objects were last modified
+ u64 GetModifiedTicks() {
+ return ++modified_ticks;
+ }
+
private:
+ /// Returns a list of cached objects from the specified memory region, ordered by access time
+ std::vector<T> GetSortedObjectsFromRegion(VAddr addr, u64 size) {
+ if (size == 0) {
+ return {};
+ }
+
+ std::vector<T> objects;
+ const ObjectInterval interval{addr, addr + size};
+ for (auto& pair : boost::make_iterator_range(object_cache.equal_range(interval))) {
+ for (auto& cached_object : pair.second) {
+ if (!cached_object) {
+ continue;
+ }
+ objects.push_back(cached_object);
+ }
+ }
+
+ std::sort(objects.begin(), objects.end(), [](const T& a, const T& b) -> bool {
+ return a->GetLastModifiedTicks() < b->GetLastModifiedTicks();
+ });
+
+ return objects;
+ }
+
+ /// Flushes the specified object, updating appropriate cache state as needed
+ void FlushObject(const T& object) {
+ if (!object->IsDirty()) {
+ return;
+ }
+ object->Flush();
+ object->MarkAsModified(false, *this);
+ }
+
using ObjectSet = std::set<T>;
using ObjectCache = boost::icl::interval_map<VAddr, ObjectSet>;
using ObjectInterval = typename ObjectCache::interval_type;
@@ -107,6 +175,6 @@ private:
object->GetAddr() + object->GetSizeInBytes());
}
- ObjectCache object_cache;
- ObjectSet remove_objects;
+ ObjectCache object_cache; ///< Cache of objects
+ u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
};
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index b389ca684..be29dc8be 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -15,17 +15,17 @@
namespace OpenGL {
-struct CachedBufferEntry final {
- VAddr GetAddr() const {
+struct CachedBufferEntry final : public RasterizerCacheObject {
+ VAddr GetAddr() const override {
return addr;
}
- std::size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const override {
return size;
}
// We do not have to flush this cache as things in it are never modified by us.
- void Flush() {}
+ void Flush() override {}
VAddr addr;
std::size_t size;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 0485dfb7a..6ce183c25 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -428,7 +428,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
if (color_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even if
// the shader doesn't actually write to it.
- color_surface->MarkAsDirty();
+ color_surface->MarkAsModified(true, res_cache);
}
glFramebufferTexture2D(
@@ -445,7 +445,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
if (color_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even
// if the shader doesn't actually write to it.
- color_surface->MarkAsDirty();
+ color_surface->MarkAsModified(true, res_cache);
}
buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
@@ -469,7 +469,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
if (depth_surface) {
// Assume that a surface will be written to if it is used as a framebuffer, even if
// the shader doesn't actually write to it.
- depth_surface->MarkAsDirty();
+ depth_surface->MarkAsModified(true, res_cache);
if (regs.stencil_enable) {
// Attach both depth and stencil
@@ -642,9 +642,6 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
// Only flush if use_accurate_framebuffers is enabled, as it incurs a performance hit
res_cache.FlushRegion(addr, size);
}
-
- shader_cache.FlushRegion(addr, size);
- buffer_cache.FlushRegion(addr, size);
}
void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index a1f541e75..f79b4f221 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -905,8 +905,6 @@ void CachedSurface::LoadGLBuffer() {
}
ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height);
-
- dirty = false;
}
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1111,6 +1109,7 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre
void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
surface->LoadGLBuffer();
surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
+ surface->MarkAsModified(false, *this);
}
Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool preserve_contents) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 39fd7cd75..77d925250 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -819,28 +819,20 @@ struct hash<SurfaceReserveKey> {
namespace OpenGL {
-class CachedSurface final {
+class CachedSurface final : public RasterizerCacheObject {
public:
CachedSurface(const SurfaceParams& params);
- VAddr GetAddr() const {
+ VAddr GetAddr() const override {
return params.addr;
}
- std::size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const override {
return cached_size_in_bytes;
}
- void Flush() {
- // There is no need to flush the surface if it hasn't been modified by us.
- if (!dirty)
- return;
+ void Flush() override {
FlushGLBuffer();
- dirty = false;
- }
-
- void MarkAsDirty() {
- dirty = true;
}
const OGLTexture& Texture() const {
@@ -868,7 +860,6 @@ private:
SurfaceParams params;
GLenum gl_target;
std::size_t cached_size_in_bytes;
- bool dirty = false;
};
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index d9157ec3c..a210f1731 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -19,22 +19,20 @@ class CachedShader;
using Shader = std::shared_ptr<CachedShader>;
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
-class CachedShader final {
+class CachedShader final : public RasterizerCacheObject {
public:
CachedShader(VAddr addr, Maxwell::ShaderProgram program_type);
- /// Gets the address of the shader in guest memory, required for cache management
- VAddr GetAddr() const {
+ VAddr GetAddr() const override {
return addr;
}
- /// Gets the size of the shader in guest memory, required for cache management
- std::size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const override {
return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
}
// We do not have to flush this cache as things in it are never modified by us.
- void Flush() {}
+ void Flush() override {}
/// Gets the shader entries for the shader
const GLShader::ShaderEntries& GetShaderEntries() const {