From c734602592d271204c7ac1debbc10a23c74b5b64 Mon Sep 17 00:00:00 2001
From: Cosmic Linden <cosmic@lindenlab.com>
Date: Fri, 10 Mar 2023 17:29:49 -0800
Subject: SL-19389: Fix textures not being optimally queued after the fix in
 SL-19338

In the future, some uses of glTexSubImage2D should be better vetted, ex: media prims
---
 indra/llrender/llimagegl.cpp | 80 ++++++++++++++++++++++++++------------------
 indra/llrender/llimagegl.h   |  6 ++--
 2 files changed, 51 insertions(+), 35 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index b5c36ea35e..7c1cf2ba33 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1113,6 +1113,45 @@ void LLImageGL::postAddToAtlas()
 	stop_glerror();	
 }
 
+// Equivalent to calling glSetSubImage2D(target, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, src)
+// However, instead there are multiple calls to glSetSubImage2D on smaller slices of the image
+void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
+    U32 components = LLImageGL::dataFormatComponents(pixformat);
+    U32 type_width = 0;
+
+    switch (pixtype)
+    {
+    case GL_UNSIGNED_BYTE:
+    case GL_BYTE:
+    case GL_UNSIGNED_INT_8_8_8_8_REV:
+        type_width = 1;
+        break;
+    case GL_UNSIGNED_SHORT:
+    case GL_SHORT:
+        type_width = 2;
+        break;
+    case GL_UNSIGNED_INT:
+    case GL_INT:
+    case GL_FLOAT:
+        type_width = 4;
+        break;
+    default:
+        LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL;
+    }
+
+    const U32 line_width = width * components * type_width;
+    const U32 y_offset_end = y_offset + height;
+    for (U32 y = y_offset; y < y_offset_end; ++y)
+    {
+        const S32 y_pos = y + y_offset;
+        glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src);
+        src += line_width;
+    }
+}
+
 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)
 {
     LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
@@ -1193,6 +1232,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 		if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;
 		stop_glerror();
 
+        // *TODO: glTexSubImage2D may not work on a subset of the texture if
+        // the texture is compressed. Make sure the image isn't compressed
+        // when using this function, then it's safe to replace this call with
+        // subImageLines, when it is performant to do so (see setManualImage)
 		glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap);
 		gGL.getTexUnit(0)->disable();
 		stop_glerror();
@@ -1359,7 +1402,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
         }
     }
 
-    if (LLImageGL::sCompressTextures && allow_compression)
+    const bool compress = LLImageGL::sCompressTextures && allow_compression;
+    if (compress)
     {
         switch (intformat)
         {
@@ -1412,11 +1456,11 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
         const bool use_sub_image = false;
 #else
         // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08
-        const bool use_sub_image = !allow_compression;
+        const bool use_sub_image = !compress;
 #endif
         if (!use_sub_image)
         {
-            LL_PROFILE_ZONE_NAMED("glTexImage2D alloc");
+            LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy");
             glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
         }
         else
@@ -1431,35 +1475,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
             if (src)
             {
                 LL_PROFILE_ZONE_NAMED("glTexImage2D copy");
-                U32 components = dataFormatComponents(pixformat);
-                U32 type_width = 0;
-
-                switch (pixtype)
-                {
-                case GL_UNSIGNED_BYTE:
-                case GL_BYTE:
-                case GL_UNSIGNED_INT_8_8_8_8_REV:
-                    type_width = 1;
-                    break;
-                case GL_UNSIGNED_SHORT:
-                case GL_SHORT:
-                    type_width = 2;
-                    break;
-                case GL_UNSIGNED_INT:
-                case GL_INT:
-                case GL_FLOAT:
-                    type_width = 4;
-                    break;
-                default:
-                    LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL;
-                }
-
-                U32 line_width = width * components * type_width;
-                for (U32 y = 0; y < height; ++y)
-                {
-                    glTexSubImage2D(target, miplevel, 0, y, width, 1, pixformat, pixtype, src);
-                    src += line_width;
-                }
+                subImageLines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src);
             }
         }
         alloc_tex_image(width, height, pixformat);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index a03233323b..08d8f60979 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -118,9 +118,9 @@ public:
 	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr);
 	void setImage(const LLImageRaw* imageraw);
 	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0);
-    // *NOTE: force_fast_update should only be used if the texture is not
-    // compressed (i.e. RenderCompressTextures is 0). Partial image updates
-    // (glTexSubImage2D) do not work on compressed textures.
+    // *TODO: This function may not work if the textures is compressed (i.e.
+    // RenderCompressTextures is 0). Partial image updates do not work on
+    // compressed textures.
 	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);
 	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);
 	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
-- 
cgit v1.2.3