| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- #include "BsGLRenderTexture.h"
- #include "BsGLPixelFormat.h"
- #include "BsGLPixelBuffer.h"
- #include "BsTextureView.h"
- namespace BansheeEngine
- {
- #define PROBE_SIZE 16
- static const GLenum depthFormats[] =
- {
- GL_NONE,
- GL_DEPTH_COMPONENT16,
- GL_DEPTH_COMPONENT32,
- GL_DEPTH24_STENCIL8,
- GL_DEPTH32F_STENCIL8
- };
- static const UINT32 depthBits[] =
- {
- 0, 16, 32, 24, 32
- };
- #define DEPTHFORMAT_COUNT (sizeof(depthFormats)/sizeof(GLenum))
- GLRenderTextureCore::GLRenderTextureCore(GLRenderTexture* parent, RenderTextureProperties* properties, const RENDER_SURFACE_DESC& colorSurfaceDesc,
- const RENDER_SURFACE_DESC& depthStencilSurfaceDesc)
- :RenderTextureCore(parent, properties, colorSurfaceDesc, depthStencilSurfaceDesc), mFB(nullptr)
- {
- if (mFB != nullptr)
- bs_delete<PoolAlloc>(mFB);
- mFB = bs_new<GLFrameBufferObject, PoolAlloc>();
- GLSurfaceDesc surfaceDesc;
- surfaceDesc.numSamples = properties->getMultisampleCount();
- surfaceDesc.zoffset = 0;
- GLTexture* glTexture = static_cast<GLTexture*>(mColorSurface->getTexture().get());
- surfaceDesc.buffer = glTexture->getBuffer(mColorSurface->getFirstArraySlice(), mColorSurface->getMostDetailedMip());
- mFB->bindSurface(0, surfaceDesc);
- GLTexture* glDepthStencilTexture = static_cast<GLTexture*>(mDepthStencilSurface->getTexture().get());
- GLPixelBufferPtr depthStencilBuffer =
- glDepthStencilTexture->getBuffer(mDepthStencilSurface->getFirstArraySlice(), mDepthStencilSurface->getMostDetailedMip());
- mFB->bindDepthStencil(depthStencilBuffer);
- }
- GLRenderTextureCore::~GLRenderTextureCore()
- {
- if (mFB != nullptr)
- bs_delete<PoolAlloc>(mFB);
- }
- void GLRenderTextureCore::getCustomAttribute(const String& name, void* pData) const
- {
- if(name=="FBO")
- {
- *static_cast<GLFrameBufferObject **>(pData) = mFB;
- }
- else if (name == "GL_FBOID" || name == "GL_MULTISAMPLEFBOID")
- {
- *static_cast<GLuint*>(pData) = mFB->getGLFBOID();
- }
- }
- RenderTargetProperties* GLRenderTexture::createProperties() const
- {
- return bs_new<RenderTextureProperties>();
- }
- RenderTextureCore* GLRenderTexture::createCore(RenderTextureProperties* properties, const RENDER_SURFACE_DESC& colorSurfaceDesc,
- const RENDER_SURFACE_DESC& depthStencilSurfaceDesc)
- {
- return bs_new<GLRenderTextureCore>(this, properties, colorSurfaceDesc, depthStencilSurfaceDesc);
- }
- GLRTTManager::GLRTTManager()
- :mBlitReadFBO(0), mBlitWriteFBO(0)
- {
- detectFBOFormats();
-
- glGenFramebuffers(1, &mBlitReadFBO);
- glGenFramebuffers(1, &mBlitWriteFBO);
- }
- GLRTTManager::~GLRTTManager()
- {
- glDeleteFramebuffers(1, &mBlitReadFBO);
- glDeleteFramebuffers(1, &mBlitWriteFBO);
- }
- bool GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat)
- {
- GLuint status, depthRB = 0, stencilRB = 0;
- bool failed = false;
- if(depthFormat != GL_NONE)
- {
- // Generate depth renderbuffer
- glGenRenderbuffers(1, &depthRB);
- // Bind it to FBO
- glBindRenderbuffer(GL_RENDERBUFFER, depthRB);
-
- // Allocate storage for depth buffer
- glRenderbufferStorage(GL_RENDERBUFFER, depthFormat,
- PROBE_SIZE, PROBE_SIZE);
-
- // Attach depth
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, depthRB);
- }
- if(stencilFormat != GL_NONE)
- {
- // Generate stencil renderbuffer
- glGenRenderbuffers(1, &stencilRB);
- // Bind it to FBO
- glBindRenderbuffer(GL_RENDERBUFFER, stencilRB);
- glGetError();
- // Allocate storage for stencil buffer
- glRenderbufferStorage(GL_RENDERBUFFER, stencilFormat,
- PROBE_SIZE, PROBE_SIZE);
- if(glGetError() != GL_NO_ERROR)
- failed = true;
- // Attach stencil
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, stencilRB);
- if(glGetError() != GL_NO_ERROR)
- failed = true;
- }
-
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- // Detach and destroy
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
- if (depthRB)
- glDeleteRenderbuffers(1, &depthRB);
- if (stencilRB)
- glDeleteRenderbuffers(1, &stencilRB);
-
- return status == GL_FRAMEBUFFER_COMPLETE && !failed;
- }
-
- bool GLRTTManager::_tryPackedFormat(GLenum packedFormat)
- {
- GLuint packedRB = 0;
- bool failed = false; // flag on GL errors
- // Generate renderbuffer
- glGenRenderbuffers(1, &packedRB);
- // Bind it to FBO
- glBindRenderbuffer(GL_RENDERBUFFER, packedRB);
- // Allocate storage for buffer
- glRenderbufferStorage(GL_RENDERBUFFER, packedFormat, PROBE_SIZE, PROBE_SIZE);
- glGetError();
- // Attach depth
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, packedRB);
- if(glGetError() != GL_NO_ERROR)
- failed = true;
- // Attach stencil
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, packedRB);
- if(glGetError() != GL_NO_ERROR)
- failed = true;
- GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- // Detach and destroy
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
- glDeleteRenderbuffers(1, &packedRB);
- return status == GL_FRAMEBUFFER_COMPLETE && !failed;
- }
- void GLRTTManager::detectFBOFormats()
- {
- // Try all formats, and report which ones work as target
- GLuint fb = 0, tid = 0;
- GLint old_drawbuffer = 0, old_readbuffer = 0;
- GLenum target = GL_TEXTURE_2D;
- glGetIntegerv (GL_DRAW_BUFFER, &old_drawbuffer);
- glGetIntegerv (GL_READ_BUFFER, &old_readbuffer);
- for(size_t x=0; x<PF_COUNT; ++x)
- {
- mProps[x].valid = false;
- // Fetch GL format token
- GLenum fmt = GLPixelUtil::getGLInternalFormat((PixelFormat)x);
- if(fmt == GL_NONE && x!=0)
- continue;
- // No test for compressed formats
- if(PixelUtil::isCompressed((PixelFormat)x))
- continue;
- // Create and attach framebuffer
- glGenFramebuffers(1, &fb);
- glBindFramebuffer(GL_FRAMEBUFFER, fb);
- if (fmt!=GL_NONE && !PixelUtil::isDepth((PixelFormat)x))
- {
- // Create and attach texture
- glGenTextures(1, &tid);
- glBindTexture(target, tid);
-
- // Set some default parameters so it won't fail on NVidia cards
- if (GLEW_VERSION_1_2)
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, tid, 0);
- }
- else
- {
- // Draw to nowhere -- stencil/depth only
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
- // Check status
- GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- // Ignore status in case of fmt==GL_NONE, because no implementation will accept
- // a buffer without *any* attachment. Buffers with only stencil and depth attachment
- // might still be supported, so we must continue probing.
- if(fmt == GL_NONE || status == GL_FRAMEBUFFER_COMPLETE)
- {
- mProps[x].valid = true;
- // For each depth/stencil formats
- for (UINT32 depth = 0; depth < DEPTHFORMAT_COUNT; ++depth)
- {
- if (depthFormats[depth] != GL_DEPTH24_STENCIL8 && depthFormats[depth] != GL_DEPTH32F_STENCIL8)
- {
- if (_tryFormat(depthFormats[depth], GL_NONE))
- {
- /// Add mode to allowed modes
- FormatProperties::Mode mode;
- mode.depth = depth;
- mode.stencil = 0;
- mProps[x].modes.push_back(mode);
- }
- }
- else
- {
- // Packed depth/stencil format
- if (_tryPackedFormat(depthFormats[depth]))
- {
- /// Add mode to allowed modes
- FormatProperties::Mode mode;
- mode.depth = depth;
- mode.stencil = 0; // unuse
- mProps[x].modes.push_back(mode);
- }
- }
- }
- }
- // Delete texture and framebuffer
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glDeleteFramebuffers(1, &fb);
-
- glFinish();
-
- if (fmt != GL_NONE)
- glDeleteTextures(1, &tid);
- }
- // It seems a bug in nVidia driver: glBindFramebuffer should restore
- // draw and read buffers, but in some unclear circumstances it won't.
- glDrawBuffer(old_drawbuffer);
- glReadBuffer(old_readbuffer);
- String fmtstring = "";
- for(size_t x = 0; x < PF_COUNT; ++x)
- {
- if(mProps[x].valid)
- fmtstring += PixelUtil::getFormatName((PixelFormat)x)+" ";
- }
- }
-
- PixelFormat GLRTTManager::getSupportedAlternative(PixelFormat format)
- {
- if(checkFormat(format))
- return format;
- // Find first alternative
- PixelComponentType pct = PixelUtil::getElementType(format);
- switch(pct)
- {
- case PCT_BYTE: format = PF_A8R8G8B8; break;
- case PCT_FLOAT16: format = PF_FLOAT16_RGBA; break;
- case PCT_FLOAT32: format = PF_FLOAT32_RGBA; break;
- case PCT_COUNT: break;
- }
- if(checkFormat(format))
- return format;
- // If none at all, return to default
- return PF_A8R8G8B8;
- }
- }
|