#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(mFB); mFB = bs_new(); GLSurfaceDesc surfaceDesc; surfaceDesc.numSamples = properties->getMultisampleCount(); surfaceDesc.zoffset = 0; GLTexture* glTexture = static_cast(mColorSurface->getTexture().get()); surfaceDesc.buffer = glTexture->getBuffer(mColorSurface->getFirstArraySlice(), mColorSurface->getMostDetailedMip()); mFB->bindSurface(0, surfaceDesc); GLTexture* glDepthStencilTexture = static_cast(mDepthStencilSurface->getTexture().get()); GLPixelBufferPtr depthStencilBuffer = glDepthStencilTexture->getBuffer(mDepthStencilSurface->getFirstArraySlice(), mDepthStencilSurface->getMostDetailedMip()); mFB->bindDepthStencil(depthStencilBuffer); } GLRenderTextureCore::~GLRenderTextureCore() { if (mFB != nullptr) bs_delete(mFB); } 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(); } } RenderTargetProperties* GLRenderTexture::createProperties() const { return bs_new(); } RenderTextureCore* GLRenderTexture::createCore(RenderTextureProperties* properties, const RENDER_SURFACE_DESC& colorSurfaceDesc, const RENDER_SURFACE_DESC& depthStencilSurfaceDesc) { return bs_new(this, properties, colorSurfaceDesc, depthStencilSurfaceDesc); } GLRTTManager::GLRTTManager() { detectFBOFormats(); glGenFramebuffersEXT(1, &mTempFBO); } GLRTTManager::~GLRTTManager() { glDeleteFramebuffersEXT(1, &mTempFBO); } bool GLRTTManager::_tryFormat(GLenum depthFormat, GLenum stencilFormat) { GLuint status, depthRB = 0, stencilRB = 0; bool failed = false; if(depthFormat != GL_NONE) { // Generate depth renderbuffer glGenRenderbuffersEXT(1, &depthRB); // Bind it to FBO glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRB); // Allocate storage for depth buffer glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, depthFormat, PROBE_SIZE, PROBE_SIZE); // Attach depth glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depthRB); } if(stencilFormat != GL_NONE) { // Generate stencil renderbuffer glGenRenderbuffersEXT(1, &stencilRB); // Bind it to FBO glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, stencilRB); glGetError(); // Allocate storage for stencil buffer glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, stencilFormat, PROBE_SIZE, PROBE_SIZE); if(glGetError() != GL_NO_ERROR) failed = true; // Attach stencil glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, stencilRB); if(glGetError() != GL_NO_ERROR) failed = true; } status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Detach and destroy glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); if (depthRB) glDeleteRenderbuffersEXT(1, &depthRB); if (stencilRB) glDeleteRenderbuffersEXT(1, &stencilRB); return status == GL_FRAMEBUFFER_COMPLETE_EXT && !failed; } bool GLRTTManager::_tryPackedFormat(GLenum packedFormat) { GLuint packedRB = 0; bool failed = false; // flag on GL errors // Generate renderbuffer glGenRenderbuffersEXT(1, &packedRB); // Bind it to FBO glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, packedRB); // Allocate storage for buffer glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, packedFormat, PROBE_SIZE, PROBE_SIZE); glGetError(); // Attach depth glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, packedRB); if(glGetError() != GL_NO_ERROR) failed = true; // Attach stencil glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, packedRB); if(glGetError() != GL_NO_ERROR) failed = true; GLuint status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Detach and destroy glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); glDeleteRenderbuffersEXT(1, &packedRB); return status == GL_FRAMEBUFFER_COMPLETE_EXT && !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