| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /*
- -----------------------------------------------------------------------------
- This source file is part of OGRE
- (Object-oriented Graphics Rendering Engine)
- For the latest info, see http://www.ogre3d.org/
- Copyright (c) 2000-2011 Torus Knot Software Ltd
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- -----------------------------------------------------------------------------
- */
- #include "CmGLFrameBufferObject.h"
- #include "CmGLPixelFormat.h"
- #include "CmGLHardwarePixelBuffer.h"
- #include "CmGLFBORenderTexture.h"
- #include "CmRenderSystemManager.h"
- namespace CamelotEngine {
- //-----------------------------------------------------------------------------
- GLFrameBufferObject::GLFrameBufferObject(GLFBOManager *manager, UINT32 fsaa):
- mManager(manager), mNumSamples(fsaa)
- {
- /// Generate framebuffer object
- glGenFramebuffersEXT(1, &mFB);
- // check multisampling
- if (GLEW_EXT_framebuffer_blit && GLEW_EXT_framebuffer_multisample)
- {
- // check samples supported
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFB);
- GLint maxSamples;
- glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- mNumSamples = std::min(mNumSamples, (GLsizei)maxSamples);
- }
- else
- {
- mNumSamples = 0;
- }
- // will we need a second FBO to do multisampling?
- if (mNumSamples)
- {
- glGenFramebuffersEXT(1, &mMultisampleFB);
- }
- else
- {
- mMultisampleFB = 0;
- }
- /// Initialise state
- mDepth.buffer=0;
- mStencil.buffer=0;
- for(size_t x=0; x<CM_MAX_MULTIPLE_RENDER_TARGETS; ++x)
- {
- mColour[x].buffer=0;
- }
- }
- GLFrameBufferObject::~GLFrameBufferObject()
- {
- mManager->releaseRenderBuffer(mDepth);
- mManager->releaseRenderBuffer(mStencil);
- mManager->releaseRenderBuffer(mMultisampleColourBuffer);
- /// Delete framebuffer object
- glDeleteFramebuffersEXT(1, &mFB);
- if (mMultisampleFB)
- glDeleteFramebuffersEXT(1, &mMultisampleFB);
- }
- void GLFrameBufferObject::bindSurface(size_t attachment, const GLSurfaceDesc &target)
- {
- assert(attachment < CM_MAX_MULTIPLE_RENDER_TARGETS);
- mColour[attachment] = target;
- // Re-initialise
- if(mColour[0].buffer)
- initialise();
- }
- void GLFrameBufferObject::unbindSurface(size_t attachment)
- {
- assert(attachment < CM_MAX_MULTIPLE_RENDER_TARGETS);
- mColour[attachment].buffer = 0;
- // Re-initialise if buffer 0 still bound
- if(mColour[0].buffer)
- {
- initialise();
- }
- }
- void GLFrameBufferObject::initialise()
- {
- // Release depth and stencil, if they were bound
- mManager->releaseRenderBuffer(mDepth);
- mManager->releaseRenderBuffer(mStencil);
- mManager->releaseRenderBuffer(mMultisampleColourBuffer);
- /// First buffer must be bound
- if(!mColour[0].buffer)
- {
- OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
- "Attachment 0 must have surface attached",
- "GLFrameBufferObject::initialise");
- }
- // If we're doing multisampling, then we need another FBO which contains a
- // renderbuffer which is set up to multisample, and we'll blit it to the final
- // FBO afterwards to perform the multisample resolve. In that case, the
- // mMultisampleFB is bound during rendering and is the one with a depth/stencil
- /// Store basic stats
- size_t width = mColour[0].buffer->getWidth();
- size_t height = mColour[0].buffer->getHeight();
- GLuint format = mColour[0].buffer->getGLFormat();
- PixelFormat ogreFormat = mColour[0].buffer->getFormat();
- UINT16 maxSupportedMRTs = CamelotEngine::RenderSystemManager::getActive()->getCapabilities()->getNumMultiRenderTargets();
- // Bind simple buffer to add colour attachments
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFB);
- /// Bind all attachment points to frame buffer
- for(size_t x=0; x<maxSupportedMRTs; ++x)
- {
- if(mColour[x].buffer)
- {
- if(mColour[x].buffer->getWidth() != width || mColour[x].buffer->getHeight() != height)
- {
- StringStream ss;
- ss << "Attachment " << x << " has incompatible size ";
- ss << mColour[x].buffer->getWidth() << "x" << mColour[x].buffer->getHeight();
- ss << ". It must be of the same as the size of surface 0, ";
- ss << width << "x" << height;
- ss << ".";
- OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, ss.str(), "GLFrameBufferObject::initialise");
- }
- if(mColour[x].buffer->getGLFormat() != format)
- {
- StringStream ss;
- ss << "Attachment " << x << " has incompatible format.";
- OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, ss.str(), "GLFrameBufferObject::initialise");
- }
- mColour[x].buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0_EXT+x, mColour[x].zoffset);
- }
- else
- {
- // Detach
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT+x,
- GL_RENDERBUFFER_EXT, 0);
- }
- }
- // Now deal with depth / stencil
- if (mMultisampleFB)
- {
- // Bind multisample buffer
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mMultisampleFB);
- // Create AA render buffer (colour)
- // note, this can be shared too because we blit it to the final FBO
- // right after the render is finished
- mMultisampleColourBuffer = mManager->requestRenderBuffer(format, width, height, mNumSamples);
- // Attach it, because we won't be attaching below and non-multisample has
- // actually been attached to other FBO
- mMultisampleColourBuffer.buffer->bindToFramebuffer(GL_COLOR_ATTACHMENT0_EXT,
- mMultisampleColourBuffer.zoffset);
- // depth & stencil will be dealt with below
- }
- /// Find suitable depth and stencil format that is compatible with colour format
- GLenum depthFormat, stencilFormat;
- mManager->getBestDepthStencil(ogreFormat, &depthFormat, &stencilFormat);
-
- /// Request surfaces
- mDepth = mManager->requestRenderBuffer(depthFormat, width, height, mNumSamples);
- if (depthFormat == GL_DEPTH24_STENCIL8_EXT)
- {
- // bind same buffer to depth and stencil attachments
- mManager->requestRenderBuffer(mDepth);
- mStencil = mDepth;
- }
- else
- {
- // separate stencil
- mStencil = mManager->requestRenderBuffer(stencilFormat, width, height, mNumSamples);
- }
-
- /// Attach/detach surfaces
- if(mDepth.buffer)
- {
- mDepth.buffer->bindToFramebuffer(GL_DEPTH_ATTACHMENT_EXT, mDepth.zoffset);
- }
- else
- {
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT, 0);
- }
- if(mStencil.buffer)
- {
- mStencil.buffer->bindToFramebuffer(GL_STENCIL_ATTACHMENT_EXT, mStencil.zoffset);
- }
- else
- {
- glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT, 0);
- }
- /// Do glDrawBuffer calls
- GLenum bufs[CM_MAX_MULTIPLE_RENDER_TARGETS];
- GLsizei n=0;
- for(size_t x=0; x<CM_MAX_MULTIPLE_RENDER_TARGETS; ++x)
- {
- // Fill attached colour buffers
- if(mColour[x].buffer)
- {
- bufs[x] = GL_COLOR_ATTACHMENT0_EXT + x;
- // Keep highest used buffer + 1
- n = x+1;
- }
- else
- {
- bufs[x] = GL_NONE;
- }
- }
- if(glDrawBuffers)
- {
- /// Drawbuffer extension supported, use it
- glDrawBuffers(n, bufs);
- }
- else
- {
- /// In this case, the capabilities will not show more than 1 simultaneaous render target.
- glDrawBuffer(bufs[0]);
- }
- if (mMultisampleFB)
- {
- // we need a read buffer because we'll be blitting to mFB
- glReadBuffer(bufs[0]);
- }
- else
- {
- /// No read buffer, by default, if we want to read anyway we must not forget to set this.
- glReadBuffer(GL_NONE);
- }
-
- /// Check status
- GLuint status;
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-
- /// Bind main buffer
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
-
- switch(status)
- {
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- // All is good
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
- "All framebuffer formats with this texture internal format unsupported",
- "GLFrameBufferObject::initialise");
- default:
- OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
- "Framebuffer incomplete or other FBO status error",
- "GLFrameBufferObject::initialise");
- }
-
- }
- void GLFrameBufferObject::bind()
- {
- /// Bind it to FBO
- if (mMultisampleFB)
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mMultisampleFB);
- else
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFB);
- }
- void GLFrameBufferObject::swapBuffers()
- {
- if (mMultisampleFB)
- {
- // blit from multisample buffer to final buffer, triggers resolve
- size_t width = mColour[0].buffer->getWidth();
- size_t height = mColour[0].buffer->getHeight();
- glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, mMultisampleFB);
- glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, mFB);
- glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
- }
- }
- size_t GLFrameBufferObject::getWidth()
- {
- assert(mColour[0].buffer);
- return mColour[0].buffer->getWidth();
- }
- size_t GLFrameBufferObject::getHeight()
- {
- assert(mColour[0].buffer);
- return mColour[0].buffer->getHeight();
- }
- PixelFormat GLFrameBufferObject::getFormat()
- {
- assert(mColour[0].buffer);
- return mColour[0].buffer->getFormat();
- }
- //-----------------------------------------------------------------------------
- }
|