#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(const RENDER_TEXTURE_DESC& desc) :RenderTextureCore(desc), mProperties(desc, true), mFB(nullptr) { } GLRenderTextureCore::~GLRenderTextureCore() { if (mFB != nullptr) bs_delete(mFB); } void GLRenderTextureCore::initialize() { RenderTextureCore::initialize(); if (mFB != nullptr) bs_delete(mFB); mFB = bs_new(); GLTextureCore* glTexture = static_cast(mColorSurface->getTexture().get()); GLSurfaceDesc surfaceDesc; surfaceDesc.numSamples = getProperties().getMultisampleCount(); if (glTexture->getProperties().getTextureType() != TEX_TYPE_3D) { surfaceDesc.zoffset = 0; surfaceDesc.buffer = glTexture->getBuffer(mColorSurface->getFirstArraySlice(), mColorSurface->getMostDetailedMip()); } else { surfaceDesc.zoffset = mColorSurface->getFirstArraySlice(); surfaceDesc.buffer = glTexture->getBuffer(0, mColorSurface->getMostDetailedMip()); } mFB->bindSurface(0, surfaceDesc); GLTextureCore* glDepthStencilTexture = static_cast(mDepthStencilSurface->getTexture().get()); GLPixelBufferPtr depthStencilBuffer = nullptr; if (glDepthStencilTexture->getProperties().getTextureType() != TEX_TYPE_3D) { depthStencilBuffer = glDepthStencilTexture->getBuffer(mDepthStencilSurface->getFirstArraySlice(), mDepthStencilSurface->getMostDetailedMip()); } mFB->bindDepthStencil(depthStencilBuffer); } void GLRenderTextureCore::getCustomAttribute(const String& name, void* pData) const { if(name=="FBO") { *static_cast(pData) = mFB; } else if (name == "GL_FBOID" || name == "GL_MULTISAMPLEFBOID") { *static_cast(pData) = mFB->getGLFBOID(); } } 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