diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 93aaf0510..27fec6843 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -76,6 +76,42 @@ LLRenderTarget::~LLRenderTarget() release(); } +void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt) +{ + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; + + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]); + LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false); + sBytesAllocated += pix_diff*4; + } + + if (mDepth) + { //resize depth attachment + if (mStencil) + { + //use render buffers where stencil buffers are in play + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + else + { + gGL.getTexUnit(0)->bindManual(mUsage, mDepth); + U32 internal_type = LLTexUnit::getInternalType(mUsage); + LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false); + } + + sBytesAllocated += pix_diff*4; + } + if(mSampleBuffer) + mSampleBuffer->resize(resx,resy); +} void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer) { @@ -241,14 +277,14 @@ bool LLRenderTarget::allocateDepth() gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); } - sBytesAllocated += mResX*mResY*4; - if (glGetError() != GL_NO_ERROR) { llwarns << "Unable to allocate depth buffer for render target." << llendl; return false; } + sBytesAllocated += mResX*mResY*4; + return true; } @@ -309,7 +345,11 @@ void LLRenderTarget::release() else { //Release before delete. - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + if(mFBO) + { + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0); + } LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true); stop_glerror(); } @@ -341,9 +381,6 @@ void LLRenderTarget::release() if (mTex.size() > 0) { - //Release before delete. - for (U32 i = 0; i < mTex.size(); ++i) - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, LLTexUnit::getInternalType(mUsage), 0, 0); sBytesAllocated -= mResX*mResY*4*mTex.size(); LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true); mTex.clear(); @@ -472,7 +509,7 @@ void LLRenderTarget::flush(bool fetch_depth) stop_glerror(); glBindFramebuffer(GL_FRAMEBUFFER, 0); stop_glerror(); - + if (mSampleBuffer) { LLGLEnable multisample(GL_MULTISAMPLE); @@ -482,7 +519,7 @@ void LLRenderTarget::flush(bool fetch_depth) check_framebuffer_status(); glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO); check_framebuffer_status(); - + stop_glerror(); if(gGLManager.mIsATI) { @@ -532,7 +569,6 @@ void LLRenderTarget::flush(bool fetch_depth) } } } - void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1, S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter) { @@ -642,7 +678,8 @@ void LLRenderTarget::getViewport(S32* viewport) // LLMultisampleBuffer implementation //================================================== LLMultisampleBuffer::LLMultisampleBuffer() : - mSamples(0) + mSamples(0), + mColorFormat(0) { } @@ -743,6 +780,7 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth mUsage = usage; mUseDepth = depth; mStencil = stencil; + mColorFormat = color_fmt; { @@ -780,6 +818,42 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth return addColorAttachment(color_fmt); } +void LLMultisampleBuffer::resize(U32 resx, U32 resy) +{ + //for accounting, get the number of pixels added/subtracted + S32 pix_diff = (resx*resy)-(mResX*mResY); + + mResX = resx; + mResY = resy; + + for (U32 i = 0; i < mTex.size(); ++i) + { //resize color attachments + glBindRenderbuffer(GL_RENDERBUFFER, mTex[i]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, mColorFormat, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + sBytesAllocated += pix_diff*4; + } + + if (mDepth) + { //resize depth attachment + if (mStencil) + { + //use render buffers where stencil buffers are in play + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + } + else + { + glBindRenderbuffer(GL_RENDERBUFFER, mDepth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + } + sBytesAllocated += pix_diff*4; + } +} + bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt) { if (color_fmt == 0) @@ -829,12 +903,13 @@ bool LLMultisampleBuffer::allocateDepth() clear_glerror(); if (mStencil) { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY); } else { - glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY); } + if (glGetError() != GL_NO_ERROR) { llwarns << "Unable to allocate depth buffer for multisample render target." << llendl; @@ -845,4 +920,3 @@ bool LLMultisampleBuffer::allocateDepth() return true; } - diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 9ed95770e..8268f1984 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -80,6 +80,12 @@ public: //multiple calls will release previously allocated resources bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE); + //resize existing attachments to use new resolution and color format + // CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined + // DO NOT use for screen space buffers or for scratch space for an image that might be uploaded + // 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, U32 color_fmt); + //provide this render target with a multisample resource. void setSampleBuffer(LLMultisampleBuffer* buffer); @@ -168,6 +174,7 @@ protected: class LLMultisampleBuffer : public LLRenderTarget { U32 mSamples; + U32 mColorFormat; public: LLMultisampleBuffer(); virtual ~LLMultisampleBuffer(); @@ -180,6 +187,7 @@ public: bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples); virtual bool addColorAttachment(U32 color_fmt); virtual bool allocateDepth(); + void resize(U32 resx, U32 resy); }; #endif //!LL_MESA_HEADLESS diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index a3f4374a4..9f4c7b1f7 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -693,9 +693,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) //allocate deferred rendering color buffers - static const LLCachedControl shadow_precision("DeferredHighPrecision",true); - const GLuint format = shadow_precision ? GL_RGBA : GL_RGBA16F_ARB; //TO-DO: Profile 16bit format later - if (!mDeferredScreen.allocate(resX, resY, format, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; + if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false; if (!addDeferredAttachments(mDeferredScreen)) return false; @@ -9409,81 +9407,86 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) stateSort(*LLViewerCamera::getInstance(), result); - const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); - LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - LLCamera camera = *viewer_camera; - - camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); - LLVector2 tdim; + U32 resY = 0; + U32 resX = 0; - - LLVector4a half_height; - half_height.setSub(ext[1], ext[0]); - half_height.mul(0.5f); - - LLVector4a left; - left.load3(camera.getLeftAxis().mV); - left.mul(left); - left.normalize3fast(); - - LLVector4a up; - up.load3(camera.getUpAxis().mV); - up.mul(up); - up.normalize3fast(); - - tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); - tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - - F32 distance = (pos-camera.getOrigin()).length(); - F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; - F32 aspect = tdim.mV[0]/tdim.mV[1]; - glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); - glh_set_current_projection(persp); - gGL.loadMatrix(persp.m); - - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - glh::matrix4f mat; - camera.getOpenGLTransform(mat.m); - - mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; - - gGL.loadMatrix(mat.m); - glh_set_current_modelview(mat); - - glClearColor(0.0f,0.0f,0.0f,0.0f); - gGL.setColorMask(true, true); - - // get the number of pixels per angle - F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); - - //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) - U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); - U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - - if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() || - resY != avatar->mImpostor.getHeight()) { - static const LLCachedControl shadow_precision("DeferredHighPrecision",true); //TO-DO: Profile 16bit format later - avatar->mImpostor.allocate(resX,resY, (!LLPipeline::sRenderDeferred || shadow_precision) ? GL_RGBA : GL_RGBA16F_ARB,TRUE,FALSE); + const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); + LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); - if (LLPipeline::sRenderDeferred) + camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis()); + + LLVector4a half_height; + half_height.setSub(ext[1], ext[0]); + half_height.mul(0.5f); + + LLVector4a left; + left.load3(camera.getLeftAxis().mV); + left.mul(left); + left.normalize3fast(); + + LLVector4a up; + up.load3(camera.getUpAxis().mV); + up.mul(up); + up.normalize3fast(); + + tdim.mV[0] = fabsf(half_height.dot3(left).getF32()); + tdim.mV[1] = fabsf(half_height.dot3(up).getF32()); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + + F32 distance = (pos-camera.getOrigin()).length(); + F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG; + F32 aspect = tdim.mV[0]/tdim.mV[1]; + glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f); + glh_set_current_projection(persp); + gGL.loadMatrix(persp.m); + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + glh::matrix4f mat; + camera.getOpenGLTransform(mat.m); + + mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat; + + gGL.loadMatrix(mat.m); + glh_set_current_modelview(mat); + + glClearColor(0.0f,0.0f,0.0f,0.0f); + gGL.setColorMask(true, true); + + // get the number of pixels per angle + F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView()); + + //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing) + resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); + resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); + + if (!avatar->mImpostor.isComplete()) { - addDeferredAttachments(avatar->mImpostor); + avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor); + } + + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else if(resX != avatar->mImpostor.getWidth() || + resY != avatar->mImpostor.getHeight()) + { + avatar->mImpostor.resize(resX,resY,GL_RGBA); } - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + avatar->mImpostor.bindTarget(); } - avatar->mImpostor.bindTarget(); - if (LLPipeline::sRenderDeferred) { avatar->mImpostor.clear();