123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901 |
- /**
- * @file llrendertarget.cpp
- * @brief LLRenderTarget implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "linden_common.h"
- #include <utility>
- #include "llrendertarget.h"
- #include "llgl.h"
- #include "llimagegl.h"
- #include "llrender.h"
- // statics
- U32 LLRenderTarget::sBytesAllocated = 0;
- bool LLRenderTarget::sUseFBO = false;
- U32 LLRenderTarget::sCurFBO = 0;
- U32 LLRenderTarget::sCurResX = 0;
- U32 LLRenderTarget::sCurResY = 0;
- static LLRenderTarget* sBoundTarget = NULL;
- void check_framebuffer_status()
- {
- if (gDebugGL)
- {
- GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
- if (status != GL_FRAMEBUFFER_COMPLETE)
- {
- llwarns << "Frame buffer failed check with status: " << std::hex
- << status << std::dec << llendl;
- }
- stop_glerror();
- }
- }
- LLRenderTarget::LLRenderTarget()
- : mPreviousRT(NULL),
- mResX(0),
- mResY(0),
- mFBO(0),
- mPreviousFBO(0),
- mPreviousResX(0),
- mPreviousResY(0),
- mDepth(0),
- mUsage(LLTexUnit::TT_TEXTURE),
- mGenerateMipMaps(LLTexUnit::TMG_NONE),
- mMipLevels(0),
- mUseDepth(false),
- mStencil(false)
- {
- }
- LLRenderTarget::~LLRenderTarget()
- {
- release();
- }
- //static
- void LLRenderTarget::reset()
- {
- sCurFBO = 0;
- sCurResX = sCurResY = 0;
- sBoundTarget = NULL;
- }
- void LLRenderTarget::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;
- llassert(mInternalFormat.size() == mTex.size());
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- LLTexUnit* unit0 = gGL.getTexUnit(0);
- for (U32 i = 0, size = mTex.size(); i < size; ++i)
- {
- // Resize color attachments
- unit0->bindManual(mUsage, mTex[i]);
- LLImageGL::setManualImage(internal_type, 0, mInternalFormat[i],
- 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
- {
- unit0->bindManual(mUsage, mDepth);
- LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24,
- mResX, mResY, GL_DEPTH_COMPONENT,
- GL_UNSIGNED_INT, NULL, false);
- }
- sBytesAllocated += pix_diff * 4;
- }
- }
- // Legacy EE renderer version
- bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth,
- bool stencil, LLTexUnit::eTextureType usage)
- {
- resx = llmin(resx, gGLManager.mGLMaxTextureSize);
- resy = llmin(resy, gGLManager.mGLMaxTextureSize);
- release();
- stop_glerror();
- mResX = resx;
- mResY = resy;
- mStencil = stencil;
- mUsage = usage;
- mUseDepth = depth;
- if (sUseFBO)
- {
- if (depth)
- {
- if (!allocateDepth())
- {
- llwarns << "Failed to allocate depth buffer for render target."
- << llendl;
- return false;
- }
- }
- glGenFramebuffers(1, (GLuint*)&mFBO);
- if (mDepth)
- {
- stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- if (mStencil)
- {
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, mDepth);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER,
- GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, mDepth);
- }
- else
- {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage),
- mDepth, 0);
- }
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- }
- }
- return addColorAttachment(color_fmt);
- }
- // New PBR renderer version
- bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth,
- LLTexUnit::eTextureType usage,
- LLTexUnit::eMipGeneration mips_generation)
- {
- resx = llmin(resx, gGLManager.mGLMaxTextureSize);
- resy = llmin(resy, gGLManager.mGLMaxTextureSize);
- release();
- stop_glerror();
- mResX = resx;
- mResY = resy;
- mUsage = usage;
- mStencil = false;
- mUseDepth = depth;
- mGenerateMipMaps = mips_generation;
- if (mips_generation != LLTexUnit::TMG_NONE)
- {
- mMipLevels = 1 + log2f(F32(llmax(resx, resy)));
- }
- if (depth && !allocateDepth())
- {
- llwarns << "Failed to allocate depth buffer for render target."
- << llendl;
- return false;
- }
- glGenFramebuffers(1, (GLuint*)&mFBO);
- if (mDepth)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage), mDepth, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- }
- return addColorAttachment(color_fmt);
- }
- void LLRenderTarget::setColorAttachment(LLImageGL* imgp, U32 use_name)
- {
- // This method only works when img is not NULL, FBO support is enabled,
- // depth buffers are not in use, mTex is empty (binding target should be
- // done via LLImageGL).
- llassert(imgp && sUseFBO && mDepth == 0 && mTex.empty());
- if (!mFBO)
- {
- glGenFramebuffers(1, (GLuint*)&mFBO);
- }
- mResX = imgp->getWidth();
- mResY = imgp->getHeight();
- mUsage = imgp->getTarget();
- if (!use_name)
- {
- use_name = imgp->getTexName();
- }
- mTex.push_back(use_name);
- stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- LLTexUnit::getInternalType(mUsage), use_name, 0);
- check_framebuffer_status();
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- }
- void LLRenderTarget::releaseColorAttachment()
- {
- // Cannot use releaseColorAttachment with LLRenderTarget managed color
- // targets
- llassert(mFBO && mTex.size() == 1);
- 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)
- {
- return true;
- }
- U32 offset = mTex.size();
- if (offset >= 4)
- {
- llwarns << "Too many color attachments !" << llendl;
- return false;
- }
- if (offset > 0 && !mFBO)
- {
- llwarns << "FBO not in use, aborting." << llendl;
- return false;
- }
- U32 tex;
- LLImageGL::generateTextures(1, &tex);
- LLTexUnit* unit0 = gGL.getTexUnit(0);
- unit0->bindManual(mUsage, tex);
- clear_glerror();
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- LLImageGL::setManualImage(internal_type, 0, color_fmt, mResX, mResY,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
- if (glGetError() != GL_NO_ERROR)
- {
- llwarns << "Could not allocate color buffer for render target."
- << llendl;
- return false;
- }
- sBytesAllocated += mResX * mResY * 4;
- if (offset == 0)
- {
- // Use bilinear filtering on single texture render targets that are not
- // multisampled
- unit0->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
- else
- {
- // Do not filter data attachments
- unit0->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
- if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
- {
- unit0->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
- }
- else
- {
- // ATI does not support mirrored repeat for rectangular textures.
- unit0->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- }
- stop_glerror();
- if (mFBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + offset,
- internal_type, tex, 0);
- check_framebuffer_status();
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- }
- mTex.push_back(tex);
- mInternalFormat.push_back(color_fmt);
- if (gDebugGL)
- {
- // Bind and unbind to validate target
- bindTarget();
- flush();
- }
- return true;
- }
- bool LLRenderTarget::allocateDepth()
- {
- if (mStencil)
- {
- // Use render buffers where stencil buffers are in play
- glGenRenderbuffers(1, (GLuint*)&mDepth);
- glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
- clear_glerror();
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
- mResX, mResY);
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- }
- else
- {
- LLImageGL::generateTextures(1, &mDepth);
- LLTexUnit* unit0 = gGL.getTexUnit(0);
- unit0->bindManual(mUsage, mDepth);
- clear_glerror();
- LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0,
- GL_DEPTH_COMPONENT24, mResX, mResY,
- GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL,
- false);
- unit0->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
- if (glGetError() != GL_NO_ERROR)
- {
- llwarns << "Unable to allocate depth buffer for render target."
- << llendl;
- return false;
- }
- sBytesAllocated += mResX * mResY * 4;
- return true;
- }
- void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
- {
- if (!mFBO || !target.mFBO)
- {
- llerrs << "Cannot share depth buffer between non FBO render targets."
- << llendl;
- }
- if (target.mDepth)
- {
- llerrs << "Attempting to override existing depth buffer. Detach existing buffer first."
- << llendl;
- }
- if (target.mUseDepth)
- {
- llerrs << "Attempting to override existing shared depth buffer. Detach existing buffer first."
- << llendl;
- }
- if (mDepth)
- {
- stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
- if (mStencil)
- {
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, mDepth);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, mDepth);
- target.mStencil = true;
- }
- else
- {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage),
- mDepth, 0);
- }
- check_framebuffer_status();
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- target.mUseDepth = true;
- }
- }
- void LLRenderTarget::release()
- {
- // New PBR renderer version
- if (gUsePBRShaders)
- {
- if (mDepth)
- {
- LLImageGL::deleteTextures(1, &mDepth);
- mDepth = 0;
- sBytesAllocated -= mResX * mResY * 4;
- }
- else if (mFBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- if (mUseDepth)
- {
- // Detach shared depth buffer
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage),
- 0, 0);
- mUseDepth = false;
- }
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
- size_t tsize = mTex.size();
- // Detach any extra color buffers (e.g. SRGB spec buffers)
- if (tsize > 1 && mFBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- for (size_t z = tsize - 1; z > 0 ; --z)
- {
- glFramebufferTexture2D(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0 + z,
- internal_type, 0, 0);
- }
- LLImageGL::deleteTextures(tsize - 1, &mTex[1]);
- sBytesAllocated -= mResX * mResY * 4 * (tsize - 1);
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
- if (mFBO)
- {
- if (mFBO == sCurFBO)
- {
- sCurFBO = 0;
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- glDeleteFramebuffers(1, (GLuint*)&mFBO);
- mFBO = 0;
- }
- if (tsize)
- {
- LLImageGL::deleteTextures(1, &mTex[0]);
- sBytesAllocated -= mResX * mResY * 4;
- }
- mTex.clear();
- mInternalFormat.clear();
- mResX = mResY = 0;
- return;
- }
- // Legacy EE renderer version
- if (mDepth)
- {
- if (mStencil)
- {
- glDeleteRenderbuffers(1, (GLuint*)&mDepth);
- }
- else
- {
- if (mFBO)
- {
- // Release before delete.
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage),
- 0, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- }
- LLImageGL::deleteTextures(1, &mDepth);
- }
- mDepth = 0;
- sBytesAllocated -= mResX * mResY * 4;
- }
- else if (mUseDepth && mFBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- // Detach shared depth buffer
- if (mStencil)
- {
- // Attached as a renderbuffer
- glFramebufferRenderbuffer(GL_FRAMEBUFFER,
- GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, 0);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, 0);
- mStencil = false;
- }
- else
- {
- // Attached as a texture
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- LLTexUnit::getInternalType(mUsage), 0, 0);
- }
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- mUseDepth = false;
- }
- if (mFBO)
- {
- glDeleteFramebuffers(1, (GLuint*)&mFBO);
- mFBO = 0;
- }
- stop_glerror();
- size_t tsize = mTex.size();
- if (tsize > 0)
- {
- sBytesAllocated -= mResX * mResY * 4 * tsize;
- LLImageGL::deleteTextures(tsize, &mTex[0]);
- mTex.clear();
- mInternalFormat.clear();
- }
- mResX = mResY = 0;
- }
- void LLRenderTarget::bindTarget()
- {
- static const GLenum drawbuffers[] =
- {
- GL_COLOR_ATTACHMENT0,
- GL_COLOR_ATTACHMENT1,
- GL_COLOR_ATTACHMENT2,
- GL_COLOR_ATTACHMENT3
- };
- // New PBR renderer version
- if (gUsePBRShaders)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- sCurFBO = mFBO;
- if (mTex.empty())
- {
- // No color buffer to draw to
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
- else
- {
- // Setup multiple render targets
- glDrawBuffers(mTex.size(), drawbuffers);
- }
- check_framebuffer_status();
- glViewport(0, 0, mResX, mResY);
- sCurResX = mResX;
- sCurResY = mResY;
- mPreviousRT = sBoundTarget;
- sBoundTarget = this;
- return;
- }
- // Legacy EE renderer version
- if (mFBO)
- {
- mPreviousFBO = sCurFBO;
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- sCurFBO = mFBO;
- if (mTex.empty())
- {
- // No color buffer to draw to
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
- else
- {
- // Setup multiple render targets
- glDrawBuffers(mTex.size(), drawbuffers);
- }
- check_framebuffer_status();
- }
- mPreviousResX = sCurResX;
- mPreviousResY = sCurResY;
- glViewport(0, 0, sCurResX = mResX, sCurResY = mResY);
- }
- void LLRenderTarget::clear(U32 mask_in)
- {
- U32 mask = GL_COLOR_BUFFER_BIT;
- if (mUseDepth)
- {
- if (gUsePBRShaders)
- {
- mask |= GL_DEPTH_BUFFER_BIT;
- }
- else
- {
- mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- }
- }
- if (mFBO)
- {
- check_framebuffer_status();
- glClear(mask & mask_in);
- }
- else
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, mResX, mResY);
- glClear(mask & mask_in);
- }
- stop_glerror();
- }
- U32 LLRenderTarget::getTexture(U32 attachment) const
- {
- if (attachment > mTex.size() - 1)
- {
- llerrs << "Invalid attachment index." << llendl;
- }
- return mTex.empty() ? 0 : mTex[attachment];
- }
- void LLRenderTarget::bindTexture(U32 index, S32 channel,
- LLTexUnit::eTextureFilterOptions filter_opt)
- {
- LLTexUnit* unitp = gGL.getTexUnit(channel);
- bool has_mips = gUsePBRShaders &&
- (filter_opt == LLTexUnit::TFO_TRILINEAR ||
- filter_opt == LLTexUnit::TFO_ANISOTROPIC);
- unitp->bindManual(mUsage, getTexture(index), has_mips);
- unitp->setTextureFilteringOption(filter_opt);
- if (index < mInternalFormat.size())
- {
- U32 format = mInternalFormat[index];
- LLTexUnit::eTextureColorSpace space;
- if (format == GL_SRGB || format == GL_SRGB8 ||
- format == GL_SRGB_ALPHA || format == GL_SRGB8_ALPHA8)
- {
- space = LLTexUnit::TCS_SRGB;
- }
- else
- {
- space = LLTexUnit::TCS_LINEAR;
- }
- unitp->setTextureColorSpace(space);
- }
- else
- {
- llwarns << "Out of range 'index': " << index << " (max is "
- << mInternalFormat.size() - 1 << ")" << llendl;
- llassert_always(!gDebugGL);
- unitp->setTextureColorSpace(LLTexUnit::TCS_LINEAR);
- }
- }
- void LLRenderTarget::flush(bool fetch_depth)
- {
- gGL.flush();
- // New PBR renderer version
- if (gUsePBRShaders)
- {
- if (mGenerateMipMaps == LLTexUnit::TMG_AUTO)
- {
- bindTexture(0, 0, LLTexUnit::TFO_TRILINEAR);
- glGenerateMipmap(GL_TEXTURE_2D);
- }
- if (mPreviousRT)
- {
- // *HACK: pop the RT stack back two frames and push the previous
- // frame back on to play nice with the GL state machine.
- sBoundTarget = mPreviousRT->mPreviousRT;
- mPreviousRT->bindTarget();
- }
- else
- {
- sBoundTarget = NULL;
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- sCurFBO = 0;
- sCurResX = gGLViewport[2];
- sCurResY = gGLViewport[3];
- glViewport(gGLViewport[0], gGLViewport[1], sCurResX, sCurResY);
- glReadBuffer(GL_BACK);
- glDrawBuffer(GL_BACK);
- }
- return;
- }
- // Legacy EE renderer version
- if (!mFBO)
- {
- LLTexUnit* unit0 = gGL.getTexUnit(0);
- unit0->bind(this);
- U32 internal_type = LLTexUnit::getInternalType(mUsage);
- glCopyTexSubImage2D(internal_type, 0, 0, 0, 0, 0, mResX, mResY);
- if (fetch_depth)
- {
- if (!mDepth)
- {
- allocateDepth();
- }
- unit0->bind(this, true);
- glCopyTexSubImage2D(internal_type, 0, 0, 0, 0, 0, mResX, mResY);
- }
- unit0->disable();
- }
- else
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO);
- sCurFBO = mPreviousFBO;
- if (mPreviousFBO)
- {
- glViewport(0, 0, sCurResX = mPreviousResX, sCurResY = mPreviousResY);
- mPreviousFBO = 0;
- }
- else
- {
- glViewport(gGLViewport[0], gGLViewport[1],
- sCurResX = gGLViewport[2], sCurResY = gGLViewport[3]);
- }
- }
- stop_glerror();
- }
- void LLRenderTarget::copyContents(LLRenderTarget& source,
- S32 src_x0, S32 src_y0,
- S32 src_x1, S32 src_y1,
- S32 dst_x0, S32 dst_y0,
- S32 dst_x1, S32 dst_y1,
- U32 mask, U32 filter)
- {
- GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? GL_TRUE : GL_FALSE;
- LLGLDepthTest depth(write_depth, write_depth);
- gGL.flush();
- if (!source.mFBO || !mFBO)
- {
- llwarns << "Cannot copy framebuffer contents for non FBO render targets."
- << llendl;
- return;
- }
- stop_glerror();
- if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, source.mFBO);
- check_framebuffer_status();
- gGL.getTexUnit(0)->bind(this, true);
- glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0,
- src_x0, src_y0, dst_x0, dst_y0, dst_x1, dst_y1);
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
- else
- {
- glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFBO);
- check_framebuffer_status();
- glBlitFramebuffer(src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0,
- dst_x1, dst_y1, mask, filter);
- glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
- stop_glerror();
- }
- //static
- void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source,
- S32 src_x0, S32 src_y0,
- S32 src_x1, S32 src_y1,
- S32 dst_x0, S32 dst_y0,
- S32 dst_x1, S32 dst_y1,
- U32 mask, U32 filter)
- {
- if (!source.mFBO)
- {
- llwarns << "Cannot copy framebuffer contents for non FBO render targets."
- << llendl;
- return;
- }
- GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
- LLGLDepthTest depth(write_depth, write_depth);
- stop_glerror();
- glBindFramebuffer(GL_READ_FRAMEBUFFER, source.mFBO);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
- check_framebuffer_status();
- glBlitFramebuffer(src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1,
- dst_y1, mask, filter);
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- stop_glerror();
- }
- bool LLRenderTarget::isComplete() const
- {
- return !mTex.empty() || mDepth;
- }
- void LLRenderTarget::getViewport(S32* viewport)
- {
- viewport[0] = viewport[1] = 0;
- viewport[2] = mResX;
- viewport[3] = mResY;
- }
- void LLRenderTarget::swapFBORefs(LLRenderTarget& other)
- {
- if (mResX != other.mResX || mResY != other.mResY)
- {
- llwarns_sparse << "FBOs sizes do not match." << llendl;
- llassert(false);
- return;
- }
- if (mUsage != other.mUsage || mUseDepth != other.mUseDepth ||
- mDepth != other.mDepth || mMipLevels != other.mMipLevels ||
- mGenerateMipMaps != other.mGenerateMipMaps ||
- mTex.size() != other.mTex.size() ||
- mInternalFormat.size() != other.mInternalFormat.size())
- {
- llwarns_sparse << "FBOs parameters do not match." << llendl;
- llassert(false);
- return;
- }
- std::swap(mFBO, other.mFBO);
- std::swap(mTex, other.mTex);
- }
|