From a14b0752bedce56db7fad7983b95a4de32486432 Mon Sep 17 00:00:00 2001
From: Rye Mutt <rye@bred.dog>
Date: Mon, 17 Aug 2020 22:31:56 -0400
Subject: [PATCH] Use texture swizzle instead of memcpy shenanigans when avail
 for gl core

---
 indra/llrender/llgl.cpp      |   4 +
 indra/llrender/llgl.h        |   1 +
 indra/llrender/llimagegl.cpp | 147 +++++++++++++++++++++--------------
 3 files changed, 95 insertions(+), 57 deletions(-)

diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 6968d77d88b..9c7be7cbb32 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -192,6 +192,7 @@ LLGLManager::LLGLManager() :
 	mHasCubeMap(FALSE),
 	mHasDebugOutput(FALSE),
 
+	mHasTextureSwizzle(false),
 	mIsATI(FALSE),
 	mIsNVIDIA(FALSE),
 	mIsIntel(FALSE),
@@ -799,6 +800,8 @@ void LLGLManager::initExtensions()
 	mHasVertexShader = mGLVersion >= 2.0f || (epoxy_has_gl_extension("GL_ARB_vertex_program") && epoxy_has_gl_extension("GL_ARB_vertex_shader")
 		&& (LLRender::sGLCoreProfile || epoxy_has_gl_extension("GL_ARB_shading_language_100")));
 	mHasFragmentShader = mGLVersion >= 2.0f || (epoxy_has_gl_extension("GL_ARB_fragment_shader") && (LLRender::sGLCoreProfile || epoxy_has_gl_extension("GL_ARB_shading_language_100")));
+
+	mHasTextureSwizzle = mGLVersion >= 3.3f || epoxy_has_gl_extension("GL_ARB_texture_swizzle");
 #endif
 
 #if LL_LINUX || LL_SOLARIS
@@ -824,6 +827,7 @@ void LLGLManager::initExtensions()
 		mHasShaderObjects = FALSE;
 		mHasVertexShader = FALSE;
 		mHasFragmentShader = FALSE;
+		mHasTextureSwizzle = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL;
 	}
 	else if (getenv("LL_GL_BASICEXT"))	/* Flawfinder: ignore */
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index e0501caaaf3..f9e88f273c7 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -120,6 +120,7 @@ class LLGLManager
 	BOOL mHassRGBTexture;
 	BOOL mHassRGBFramebuffer;
     BOOL mHasTexturesRGBDecode;
+	bool mHasTextureSwizzle;
 
 	// Vendor-specific extensions
 	BOOL mIsATI;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 951109125d0..8d02ab46bbc 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1186,71 +1186,109 @@ static LLTrace::BlockTimerStatHandle FTM_SET_MANUAL_IMAGE("setManualImage");
 void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression)
 {
 	LL_RECORD_BLOCK_TIME(FTM_SET_MANUAL_IMAGE);
-	bool use_scratch = false;
-	U32* scratch = NULL;
+	std::vector<U32> scratch;
 	if (LLRender::sGLCoreProfile)
 	{
-		if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_ALPHA is deprecated, convert to RGBA
-			use_scratch = true;
-			scratch = new U32[width*height];
+#ifdef GL_ARB_texture_swizzle
+		if (gGLManager.mHasTextureSwizzle)
+		{
+			if (pixformat == GL_ALPHA)
+			{ //GL_ALPHA is deprecated, convert to RGBA
+				const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
+				glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+				pixformat = GL_RED;
+				intformat = GL_R8;
+			}
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = 0;
-				pix[3] = ((U8*) pixels)[i];
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGBA8;
+			if (pixformat == GL_LUMINANCE)
+			{ //GL_LUMINANCE is deprecated, convert to GL_RGBA
+				const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+				glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+				pixformat = GL_RED;
+				intformat = GL_R8;
+			}
+
+			if (pixformat == GL_LUMINANCE_ALPHA)
+			{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+				const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
+				glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask);
+				pixformat = GL_RG;
+				intformat = GL_RG8;
+			}
 		}
+		else
+#endif
+		{
+			if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+			{ //GL_ALPHA is deprecated, convert to RGBA
+				scratch.resize(width * height);
 
-		if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
-			use_scratch = true;
-			scratch = new U32[width*height];
+				U32 pixel_count = (U32)(width * height);
+				for (U32 i = 0; i < pixel_count; i++)
+				{
+					U8* pix = (U8*)&scratch[i];
+					pix[0] = pix[1] = pix[2] = 0;
+					pix[3] = ((U8*)pixels)[i];
+				}
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8 lum = ((U8*) pixels)[i*2+0];
-				U8 alpha = ((U8*) pixels)[i*2+1];
+				pixformat = GL_RGBA;
+				intformat = GL_RGBA8;
+			}
 
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = lum;
-				pix[3] = alpha;
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGBA8;
-		}
+			if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE)
+			{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA
+				scratch.resize(width * height);
 
-		if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) 
-		{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
-			use_scratch = true;
-			scratch = new U32[width*height];
+				U32 pixel_count = (U32)(width * height);
+				for (U32 i = 0; i < pixel_count; i++)
+				{
+					U8 lum = ((U8*)pixels)[i * 2 + 0];
+					U8 alpha = ((U8*)pixels)[i * 2 + 1];
 
-			U32 pixel_count = (U32) (width*height);
-			for (U32 i = 0; i < pixel_count; i++)
-			{
-				U8 lum = ((U8*) pixels)[i];
-				
-				U8* pix = (U8*) &scratch[i];
-				pix[0] = pix[1] = pix[2] = lum;
-				pix[3] = 255;
-			}				
-			
-			pixformat = GL_RGBA;
-			intformat = GL_RGB8;
+					U8* pix = (U8*)&scratch[i];
+					pix[0] = pix[1] = pix[2] = lum;
+					pix[3] = alpha;
+				}
+
+				pixels = &scratch[0];
+
+				pixformat = GL_RGBA;
+				intformat = GL_RGBA8;
+			}
+
+			if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE)
+			{ //GL_LUMINANCE_ALPHA is deprecated, convert to RGB
+				scratch.resize(width * height);
+
+				U32 pixel_count = (U32)(width * height);
+				for (U32 i = 0; i < pixel_count; i++)
+				{
+					U8 lum = ((U8*)pixels)[i];
+
+					U8* pix = (U8*)&scratch[i];
+					pix[0] = pix[1] = pix[2] = lum;
+					pix[3] = 255;
+				}
+
+				pixels = &scratch[0];
+
+				pixformat = GL_RGBA;
+				intformat = GL_RGB8;
+			}
 		}
 	}
-
 	if (LLImageGL::sCompressTextures && allow_compression)
 	{
 		switch (intformat)
 		{
+			case GL_RED: 
+			case GL_R8:
+				intformat = GL_COMPRESSED_RED; 
+				break;
+			case GL_RG: 
+			case GL_RG8:
+				intformat = GL_COMPRESSED_RG; 
+				break;
 			case GL_RGB: 
 			case GL_RGB8:
 				intformat = GL_COMPRESSED_RGB; 
@@ -1280,19 +1318,14 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
 				intformat = GL_COMPRESSED_ALPHA;
 				break;
 			default:
-				LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;
+				LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL;
 				break;
 		}
 	}
 
 	stop_glerror();
-	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels);
+	glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels);
 	stop_glerror();
-
-	if (use_scratch)
-	{
-		delete [] scratch;
-	}
 }
 
 //create an empty GL texture: just create a texture name
-- 
GitLab