diff options
| author | Dave Parks <davep@lindenlab.com> | 2022-03-04 17:05:05 -0600 | 
|---|---|---|
| committer | Dave Parks <davep@lindenlab.com> | 2022-03-04 17:05:05 -0600 | 
| commit | 9dc8fee0f52b5cf9d0cfc85fd285b3829b165796 (patch) | |
| tree | 07f14fdaecb4a3c29ec99a7b378e59e1eab893cc | |
| parent | 97a103255e433629f13e2156aa307ca329cdcfc6 (diff) | |
SL-16928 Fix for broken bumpmaps on Intel GPUs
| -rw-r--r-- | indra/llrender/llimagegl.cpp | 95 | ||||
| -rw-r--r-- | indra/llrender/llrendertarget.cpp | 47 | ||||
| -rw-r--r-- | indra/llrender/llrendertarget.h | 18 | ||||
| -rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl | 14 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolbump.cpp | 181 | ||||
| -rw-r--r-- | indra/newview/lldrawpoolbump.h | 1 | 
6 files changed, 215 insertions, 141 deletions
| diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index f43671dee5..9bd3a0a6b0 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -211,6 +211,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat)      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:    return 8;      case GL_LUMINANCE:						        return 8;      case GL_ALPHA:							        return 8; +    case GL_RED:                                    return 8;      case GL_COLOR_INDEX:						    return 8;      case GL_LUMINANCE_ALPHA:					    return 16;      case GL_RGB:								    return 24; @@ -260,6 +261,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat)  	  case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4;  	  case GL_LUMINANCE:						return 1;  	  case GL_ALPHA:							return 1; +      case GL_RED:                              return 1;  	  case GL_COLOR_INDEX:						return 1;  	  case GL_LUMINANCE_ALPHA:					return 2;  	  case GL_RGB:								return 3; @@ -1199,7 +1201,29 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_  void LLImageGL::generateTextures(S32 numTextures, U32 *textures)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -	glGenTextures(numTextures, textures); +    static constexpr U32 pool_size = 1024; +    static thread_local U32 name_pool[pool_size]; // pool of texture names +    static thread_local U32 name_count = 0; // number of available names in the pool + +    if (name_count == 0) +    { +        LL_PROFILE_ZONE_NAMED("iglgt - reup pool"); +        // pool is emtpy, refill it +        glGenTextures(pool_size, name_pool); +        name_count = pool_size; +    } + +    if (numTextures <= name_count) +    { +        //copy teture names off the end of the pool +        memcpy(textures, name_pool + name_count - numTextures, sizeof(U32) * numTextures); +        name_count -= numTextures; +    } +    else +    { +        LL_PROFILE_ZONE_NAMED("iglgt - pool miss"); +        glGenTextures(numTextures, textures); +    }  }  // static @@ -1221,15 +1245,18 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt      {          if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE)          { //GL_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++) +            if (pixels != nullptr)              { -                U8* pix = (U8*)&scratch[i]; -                pix[0] = pix[1] = pix[2] = 0; -                pix[3] = ((U8*)pixels)[i]; +                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]; +                }              }              pixformat = GL_RGBA; @@ -1238,18 +1265,21 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt          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++) +            if (pixels != nullptr)              { -                U8 lum = ((U8*)pixels)[i * 2 + 0]; -                U8 alpha = ((U8*)pixels)[i * 2 + 1]; +                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]; -                U8* pix = (U8*)&scratch[i]; -                pix[0] = pix[1] = pix[2] = lum; -                pix[3] = alpha; +                    U8* pix = (U8*)&scratch[i]; +                    pix[0] = pix[1] = pix[2] = lum; +                    pix[3] = alpha; +                }              }              pixformat = GL_RGBA; @@ -1258,19 +1288,21 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt          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++) +            if (pixels != nullptr)              { -                U8 lum = ((U8*)pixels)[i]; +                use_scratch = true; +                scratch = new U32[width * height]; -                U8* pix = (U8*)&scratch[i]; -                pix[0] = pix[1] = pix[2] = lum; -                pix[3] = 255; -            } +                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;          } @@ -1308,6 +1340,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt          case GL_ALPHA8:              intformat = GL_COMPRESSED_ALPHA;              break; +        case GL_RED: +        case GL_R8: +            intformat = GL_COMPRESSED_RED; +            break;          default:              LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL;              break; @@ -2010,6 +2046,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()      case GL_LUMINANCE_ALPHA:          mAlphaStride = 2;          break; +    case GL_RED:      case GL_RGB:      case GL_SRGB:          mNeedsAlphaAndPickMask = FALSE; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 401085a00b..0408010513 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -170,6 +170,53 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo  	return addColorAttachment(color_fmt);  } +void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name) +{ +    LL_PROFILE_ZONE_SCOPED; +    llassert(img != nullptr); // img must not be null +    llassert(sUseFBO); // FBO support must be enabled +    llassert(mDepth == 0); // depth buffers not supported with this mode +    llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL) + +    if (mFBO == 0) +    { +        glGenFramebuffers(1, (GLuint*)&mFBO); +    } + +    mResX = img->getWidth(); +    mResY = img->getHeight(); +    mUsage = img->getTarget(); + +    if (use_name == 0) +    { +        use_name = img->getTexName(); +    } + +    mTex.push_back(use_name); + +    glBindFramebuffer(GL_FRAMEBUFFER, mFBO); +    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, +            LLTexUnit::getInternalType(mUsage), use_name, 0); +        stop_glerror(); + +    check_framebuffer_status(); + +    glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); +} + +void LLRenderTarget::releaseColorAttachment() +{ +    LL_PROFILE_ZONE_SCOPED; +    llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets +    llassert(mFBO != 0);  // mFBO must be valid +     +    glBindFramebuffer(GL_FRAMEBUFFER, mFBO); +    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, LLTexUnit::getInternalType(mUsage), 0, 0); +    glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + +    mTex.clear(); +} +  bool LLRenderTarget::addColorAttachment(U32 color_fmt)  {  	if (color_fmt == 0) diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 6c07ac5b1c..584f224dca 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -81,6 +81,24 @@ public:  	// DO use for render targets that resize often and aren't likely to ruin someone's day if they break  	void resize(U32 resx, U32 resy); +    //point this render target at a particular LLImageGL +    //   Intended usage: +    //      LLRenderTarget target; +    //      target.addColorAttachment(image); +    //      target.bindTarget(); +    //      < issue GL calls> +    //      target.flush(); +    //      target.releaseColorAttachment(); +    //  +    // attachment -- LLImageGL to render into +    // use_name -- optional texture name to target instead of attachment->getTexName() +    // NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with +    // addColorAttachment, allocateDepth, resize, etc. +    void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0); + +    // detach from current color attachment +    void releaseColorAttachment(); +  	//add color buffer attachment  	//limit of 4 color attachments per render target  	bool addColorAttachment(U32 color_fmt); diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl index d0c06cd51f..7a941674b8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl @@ -43,18 +43,18 @@ uniform float norm_scale;  void main()  { -	float alpha = texture2D(alphaMap, vary_texcoord0).a; +	float c = texture2D(alphaMap, vary_texcoord0).r; -	vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).a-alpha)*255); -	vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).a-alpha)*255); -	vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).a-alpha)*255); -	vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).a-alpha)*255); +	vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255); +	vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255); +	vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255); +	vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255);  	vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right);  	norm = normalize(norm);  	norm *= 0.5;  	norm += 0.5;	 -	 -	frag_color = vec4(norm, alpha); + +	frag_color = vec4(norm, c);  } diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 1d5419b515..2892fc6f9f 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -56,6 +56,7 @@  LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT];   LL::WorkQueue::weak_t LLBumpImageList::sMainQueue;  LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue; +LLRenderTarget LLBumpImageList::sRenderTarget;  // static  U32 LLStandardBumpmap::sStandardBumpmapCount = 0; @@ -76,7 +77,7 @@ static S32 cube_channel = -1;  static S32 diffuse_channel = -1;  static S32 bump_channel = -1; -#define LL_BUMPLIST_MULTITHREADED 0 +#define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work  // static   void LLStandardBumpmap::init() @@ -776,6 +777,8 @@ void LLBumpImageList::clear()  	mBrightnessEntries.clear();  	mDarknessEntries.clear(); +    sRenderTarget.release(); +  	LLStandardBumpmap::clear();  } @@ -1032,6 +1035,8 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr  // static  void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code )  { +    LL_PROFILE_ZONE_SCOPED; +  	if( success )  	{          LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -1201,145 +1206,111 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI  			}  			else   			{ //convert to normal map -				 -				//disable compression on normal maps to prevent errors below -				bump->getGLTexture()->setAllowCompression(false); -                bump->getGLTexture()->setUseMipMaps(TRUE); - -                auto* bump_ptr = bump.get(); -                auto* dst_ptr = dst_image.get(); +                LL_PROFILE_ZONE_NAMED("bil - create normal map"); +                LLImageGL* img = bump->getGLTexture(); +                LLImageRaw* dst_ptr = dst_image.get(); +                LLGLTexture* bump_ptr = bump.get(); -#if LL_BUMPLIST_MULTITHREADED -                bump_ptr->ref();                  dst_ptr->ref(); -#endif - -                bump_ptr->setExplicitFormat(GL_RGBA8, GL_ALPHA); - -                auto create_texture = [=]() +                img->ref(); +                bump_ptr->ref(); +                auto create_func = [=]()                  { -#if LL_IMAGEGL_THREAD_CHECK -                    bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID(); -#endif -                    LL_PROFILE_ZONE_NAMED("bil - create texture deferred"); +                    img->setUseMipMaps(TRUE); +                    // upload dst_image to GPU (greyscale in red channel) +                    img->setExplicitFormat(GL_RED, GL_RED); +                      bump_ptr->createGLTexture(0, dst_ptr); +                    dst_ptr->unref();                  }; -                auto gen_normal_map = [=]() +                auto generate_func = [=]()                  { -#if LL_IMAGEGL_THREAD_CHECK -                    bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID(); -#endif -                    LL_PROFILE_ZONE_NAMED("bil - generate normal map"); -                    if (gNormalMapGenProgram.mProgramObject == 0) -                    { -#if LL_BUMPLIST_MULTITHREADED -                        bump_ptr->unref(); -                        dst_ptr->unref(); -#endif -                        return; -                    } -                    gPipeline.mScreen.bindTarget(); - -                    LLGLDepthTest depth(GL_FALSE); -                    LLGLDisable cull(GL_CULL_FACE); -                    LLGLDisable blend(GL_BLEND); -                    gGL.setColorMask(TRUE, TRUE); -                    gNormalMapGenProgram.bind(); - -                    static LLStaticHashedString sNormScale("norm_scale"); -                    static LLStaticHashedString sStepX("stepX"); -                    static LLStaticHashedString sStepY("stepY"); - -                    gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); -                    gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); -                    gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); +                    // Allocate an empty RGBA texture at "tex_name" the same size as bump +                    //  Note: bump will still point at GPU copy of dst_image +                    bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); +                    LLGLuint tex_name; +                    img->createGLTexture(0, nullptr, 0, 0, true, &tex_name); -                    LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(), -                        (F32)bump_ptr->getHeight() / gPipeline.mScreen.getHeight()); +                    // point render target at empty buffer +                    sRenderTarget.setColorAttachment(img, tex_name); -                    gGL.getTexUnit(0)->bind(bump_ptr); - -                    S32 width = bump_ptr->getWidth(); -                    S32 height = bump_ptr->getHeight(); - -                    S32 screen_width = gPipeline.mScreen.getWidth(); -                    S32 screen_height = gPipeline.mScreen.getHeight(); - -                    glViewport(0, 0, screen_width, screen_height); - -                    for (S32 left = 0; left < width; left += screen_width) +                    // generate normal map in empty texture                      { -                        S32 right = left + screen_width; -                        right = llmin(right, width); +                        sRenderTarget.bindTarget(); -                        F32 left_tc = (F32)left / width; -                        F32 right_tc = (F32)right / width; +                        LLGLDepthTest depth(GL_FALSE); +                        LLGLDisable cull(GL_CULL_FACE); +                        LLGLDisable blend(GL_BLEND); +                        gGL.setColorMask(TRUE, TRUE); -                        for (S32 bottom = 0; bottom < height; bottom += screen_height) -                        { -                            S32 top = bottom + screen_height; -                            top = llmin(top, height); +                        gNormalMapGenProgram.bind(); -                            F32 bottom_tc = (F32)bottom / height; -                            F32 top_tc = (F32)(bottom + screen_height) / height; -                            top_tc = llmin(top_tc, 1.f); +                        static LLStaticHashedString sNormScale("norm_scale"); +                        static LLStaticHashedString sStepX("stepX"); +                        static LLStaticHashedString sStepY("stepY"); -                            F32 screen_right = (F32)(right - left) / screen_width; -                            F32 screen_top = (F32)(top - bottom) / screen_height; +                        gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); +                        gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); +                        gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); -                            gGL.begin(LLRender::TRIANGLE_STRIP); -                            gGL.texCoord2f(left_tc, bottom_tc); -                            gGL.vertex2f(0, 0); +                        gGL.getTexUnit(0)->bind(bump_ptr); -                            gGL.texCoord2f(left_tc, top_tc); -                            gGL.vertex2f(0, screen_top); +                        gGL.begin(LLRender::TRIANGLE_STRIP); +                        gGL.texCoord2f(0, 0); +                        gGL.vertex2f(0, 0); -                            gGL.texCoord2f(right_tc, bottom_tc); -                            gGL.vertex2f(screen_right, 0); +                        gGL.texCoord2f(0, 1); +                        gGL.vertex2f(0, 1); -                            gGL.texCoord2f(right_tc, top_tc); -                            gGL.vertex2f(screen_right, screen_top); +                        gGL.texCoord2f(1, 0); +                        gGL.vertex2f(1, 0); -                            gGL.end(); +                        gGL.texCoord2f(1, 1); +                        gGL.vertex2f(1, 1); -                            gGL.flush(); +                        gGL.end(); -                            S32 w = right - left; -                            S32 h = top - bottom; +                        gGL.flush(); -                            glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h); -                        } -                    } +                        gNormalMapGenProgram.unbind(); -                    glGenerateMipmap(GL_TEXTURE_2D); +                        sRenderTarget.flush(); +                        sRenderTarget.releaseColorAttachment(); +                    } -                    gPipeline.mScreen.flush(); +                    // point bump at normal map and free gpu copy of dst_image +                    img->syncTexName(tex_name); -                    gNormalMapGenProgram.unbind(); +                    // generate mipmap +                    gGL.getTexUnit(0)->bind(img); +                    glGenerateMipmap(GL_TEXTURE_2D); +                    gGL.getTexUnit(0)->disable(); -                    //generateNormalMapFromAlpha(dst_image, nrm_image); -#if LL_BUMPLIST_MULTITHREADED                      bump_ptr->unref(); -                    dst_ptr->unref(); -#endif +                    img->unref();                  };  #if LL_BUMPLIST_MULTITHREADED -                auto main_queue = sMainQueue.lock(); - -                if (LLImageGLThread::sEnabled) -                { //dispatch creation to background thread -                    main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map); +                auto main_queue = LLImageGLThread::sEnabled ? sMainQueue.lock() : nullptr; + +                if (main_queue) +                { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread +                    main_queue->postTo( +                        sTexUpdateQueue, +                        create_func, +                        generate_func);                  }                  else  #endif -                { -                    create_texture(); -                    gen_normal_map(); +                { // immediate upload texture and generate normal map +                    create_func(); +                    generate_func();                  } + +  			} -		 +  			iter->second = bump; // derefs (and deletes) old image  			//---------------------------------------------------  		} diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 6e21859738..e8a027967b 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -163,6 +163,7 @@ private:  	bump_image_map_t mDarknessEntries;      static LL::WorkQueue::weak_t sMainQueue;      static LL::WorkQueue::weak_t sTexUpdateQueue; +    static LLRenderTarget sRenderTarget;  };  extern LLBumpImageList gBumpImageList; | 
