From fda121c25c057d8342e1721daf82bd74130762d4 Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Thu, 9 Jan 2020 11:18:47 -0500
Subject: [PATCH] Use immutable storage when available

---
 .../renderer_opengl/gl_rasterizer_cache.cpp   | 49 +++++++++++++------
 1 file changed, 33 insertions(+), 16 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 3139c1101..25e345098 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -6,6 +6,7 @@
 #include <array>
 #include <atomic>
 #include <bitset>
+#include <cmath>
 #include <cstring>
 #include <iterator>
 #include <memory>
@@ -250,8 +251,14 @@ OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& form
     cur_state.Apply();
     glActiveTexture(GL_TEXTURE0);
 
-    glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
-                 format_tuple.format, format_tuple.type, nullptr);
+    if (GL_ARB_texture_storage) {
+        // Allocate all possible mipmap levels upfront
+        auto levels = std::log2(std::max(width, height)) + 1;
+        glTexStorage2D(GL_TEXTURE_2D, levels, format_tuple.internal_format, width, height);
+    } else {
+        glTexImage2D(GL_TEXTURE_2D, 0, format_tuple.internal_format, width, height, 0,
+                     format_tuple.format, format_tuple.type, nullptr);
+    }
 
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -273,17 +280,22 @@ static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple,
     cur_state.texture_cube_unit.texture_cube = texture;
     cur_state.Apply();
     glActiveTexture(TextureUnits::TextureCube.Enum());
-
-    for (auto faces : {
-             GL_TEXTURE_CUBE_MAP_POSITIVE_X,
-             GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
-             GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
-             GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
-             GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-             GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-         }) {
-        glTexImage2D(faces, 0, format_tuple.internal_format, width, width, 0, format_tuple.format,
-                     format_tuple.type, nullptr);
+    if (GL_ARB_texture_storage) {
+        // Allocate all possible mipmap levels in case the game uses them later
+        auto levels = std::log2(width) + 1;
+        glTexStorage2D(GL_TEXTURE_CUBE_MAP, levels, format_tuple.internal_format, width, width);
+    } else {
+        for (auto faces : {
+                 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+                 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+                 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+             }) {
+            glTexImage2D(faces, 0, format_tuple.internal_format, width, width, 0,
+                         format_tuple.format, format_tuple.type, nullptr);
+        }
     }
 
     // Restore previous texture bindings
@@ -1250,9 +1262,14 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Pica::Texture::TextureInf
                 width = surface->GetScaledWidth();
                 height = surface->GetScaledHeight();
             }
-            for (u32 level = surface->max_level + 1; level <= max_level; ++level) {
-                glTexImage2D(GL_TEXTURE_2D, level, format_tuple.internal_format, width >> level,
-                             height >> level, 0, format_tuple.format, format_tuple.type, nullptr);
+            // If we are using ARB_texture_storage then we've already allocated all of the mipmap
+            // levels
+            if (!GL_ARB_texture_storage) {
+                for (u32 level = surface->max_level + 1; level <= max_level; ++level) {
+                    glTexImage2D(GL_TEXTURE_2D, level, format_tuple.internal_format, width >> level,
+                                 height >> level, 0, format_tuple.format, format_tuple.type,
+                                 nullptr);
+                }
             }
             if (surface->is_custom || !texture_filterer->IsNull()) {
                 // TODO: proper mipmap support for custom textures