aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl/gl_rasterizer_cache.cpp')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp77
1 files changed, 77 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
new file mode 100644
index 00000000..6f88a8b2
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -0,0 +1,77 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/make_unique.h"
+#include "common/math_util.h"
+
+#include "core/memory.h"
+
+#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
+#include "video_core/renderer_opengl/pica_to_gl.h"
+#include "video_core/debug_utils/debug_utils.h"
+#include "video_core/math.h"
+
+RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
+ FullFlush();
+}
+
+void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) {
+ PAddr texture_addr = config.config.GetPhysicalAddress();
+
+ const auto cached_texture = texture_cache.find(texture_addr);
+
+ if (cached_texture != texture_cache.end()) {
+ state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle;
+ state.Apply();
+ } else {
+ std::unique_ptr<CachedTexture> new_texture = Common::make_unique<CachedTexture>();
+
+ new_texture->texture.Create();
+ state.texture_units[texture_unit].texture_2d = new_texture->texture.handle;
+ state.Apply();
+
+ // TODO: Need to choose filters that correspond to PICA once register is declared
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t));
+
+ const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
+
+ new_texture->width = info.width;
+ new_texture->height = info.height;
+ new_texture->size = info.width * info.height * Pica::Regs::NibblesPerPixel(info.format);
+
+ u8* texture_src_data = Memory::GetPhysicalPointer(texture_addr);
+ std::unique_ptr<Math::Vec4<u8>[]> temp_texture_buffer_rgba(new Math::Vec4<u8>[info.width * info.height]);
+
+ for (int y = 0; y < info.height; ++y) {
+ for (int x = 0; x < info.width; ++x) {
+ temp_texture_buffer_rgba[x + info.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, info.height - 1 - y, info);
+ }
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_texture_buffer_rgba.get());
+
+ texture_cache.emplace(texture_addr, std::move(new_texture));
+ }
+}
+
+void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size) {
+ // Flush any texture that falls in the flushed region
+ // TODO: Optimize by also inserting upper bound (addr + size) of each texture into the same map and also narrow using lower_bound
+ auto cache_upper_bound = texture_cache.upper_bound(addr + size);
+ for (auto it = texture_cache.begin(); it != cache_upper_bound;) {
+ if (MathUtil::IntervalsIntersect(addr, size, it->first, it->second->size)) {
+ it = texture_cache.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void RasterizerCacheOpenGL::FullFlush() {
+ texture_cache.clear();
+}