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; |