From 694a1b55e380550ac663b79d30c5ffc5d15fd5fa Mon Sep 17 00:00:00 2001 From: Daniel Wallner Date: Fri, 11 Mar 2016 10:33:46 +0100 Subject: [PATCH] iOS SwapChain support --- src/glcontext_eagl.h | 8 +- src/glcontext_eagl.mm | 186 +++++++++++++++++++++++++++++++++++++++--- src/renderer_gl.cpp | 11 +-- 3 files changed, 182 insertions(+), 23 deletions(-) diff --git a/src/glcontext_eagl.h b/src/glcontext_eagl.h index a4786c49..33099ea1 100644 --- a/src/glcontext_eagl.h +++ b/src/glcontext_eagl.h @@ -15,7 +15,11 @@ namespace bgfx { namespace gl struct GlContext { GlContext() - : m_context(0) + : m_current(0) + , m_context(0) + , m_fbo(0) + , m_colorRbo(0) + , m_depthStencilRbo(0) { } @@ -41,7 +45,7 @@ namespace bgfx { namespace gl return 0 != m_context; } - void* m_view; + SwapChainGL* m_current; void* m_context; GLuint m_fbo; diff --git a/src/glcontext_eagl.mm b/src/glcontext_eagl.mm index 544fe037..ea086db1 100644 --- a/src/glcontext_eagl.mm +++ b/src/glcontext_eagl.mm @@ -17,6 +17,142 @@ namespace bgfx { namespace gl static void* s_opengles = NULL; + struct SwapChainGL + { + SwapChainGL(EAGLContext *_context, CAEAGLLayer *_layer) + : m_context(_context) + , m_fbo(0) + , m_colorRbo(0) + , m_depthStencilRbo(0) + { + _layer.contentsScale = [UIScreen mainScreen].scale; + + _layer.opaque = true; + + _layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys + : [NSNumber numberWithBool:false] + , kEAGLDrawablePropertyRetainedBacking + , kEAGLColorFormatRGBA8 + , kEAGLDrawablePropertyColorFormat + , nil + ]; + + + [EAGLContext setCurrentContext:_context]; + + GL_CHECK(glGenFramebuffers(1, &m_fbo) ); + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ); + + GL_CHECK(glGenRenderbuffers(1, &m_colorRbo) ); + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_colorRbo) ); + + [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_layer]; + GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorRbo) ); + + GLint width; + GLint height; + GL_CHECK(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width) ); + GL_CHECK(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height) ); + BX_TRACE("Screen size: %d x %d", width, height); + + m_width = width; + m_height = height; + m_layer = _layer; + + createFrameBuffers(m_width, m_height); + } + + ~SwapChainGL() + { + destroyFrameBuffers(); + } + + void destroyFrameBuffers() + { + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) ); + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) ); + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, 0) ); + if (0 != m_fbo) + { + GL_CHECK(glDeleteFramebuffers(1, &m_fbo) ); + m_fbo = 0; + } + + if (0 != m_colorRbo) + { + GL_CHECK(glDeleteRenderbuffers(1, &m_colorRbo) ); + m_colorRbo = 0; + } + + if (0 != m_depthStencilRbo) + { + GL_CHECK(glDeleteRenderbuffers(1, &m_depthStencilRbo) ); + m_depthStencilRbo = 0; + } + } + + void createFrameBuffers(GLint _width, GLint _height) + { + GL_CHECK(glGenRenderbuffers(1, &m_depthStencilRbo) ); + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_depthStencilRbo) ); + GL_CHECK(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, _width, _height) ); // from OES_packed_depth_stencil + GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilRbo) ); + GL_CHECK(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilRbo) ); + + BX_CHECK(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER) + , "glCheckFramebufferStatus failed 0x%08x" + , glCheckFramebufferStatus(GL_FRAMEBUFFER) + ); + + makeCurrent(); + GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) ); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) ); + swapBuffers(); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) ); + swapBuffers(); + } + + void makeCurrent() + { + [EAGLContext setCurrentContext:m_context]; + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ); + + GLint newWidth = m_layer.bounds.size.width*[UIScreen mainScreen].scale; + GLint newHeight = m_layer.bounds.size.height*[UIScreen mainScreen].scale; + resize(newWidth, newHeight); + } + + void resize(GLint _width, GLint _height) + { + if(m_width == _width && m_height == _height) + { + return; + } + + destroyFrameBuffers(); + + m_width = _width; + m_height = _height; + + createFrameBuffers(m_width, m_height); + } + + void swapBuffers() + { + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_colorRbo) ); + [m_context presentRenderbuffer:GL_RENDERBUFFER]; + } + + EAGLContext* m_context; + + CAEAGLLayer *m_layer; + GLuint m_fbo; + GLuint m_colorRbo; + GLuint m_depthStencilRbo; + GLint m_width; + GLint m_height; + }; + void GlContext::create(uint32_t _width, uint32_t _height) { s_opengles = bx::dlopen("/System/Library/Frameworks/OpenGLES.framework/OpenGLES"); @@ -65,6 +201,13 @@ namespace bgfx { namespace gl , glCheckFramebufferStatus(GL_FRAMEBUFFER) ); + makeCurrent(); + GL_CHECK(glClearColor(0.0f, 0.0f, 0.0f, 0.0f) ); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) ); + swap(NULL); + GL_CHECK(glClear(GL_COLOR_BUFFER_BIT) ); + swap(NULL); + import(); g_internalData.context = m_context; @@ -148,30 +291,51 @@ namespace bgfx { namespace gl uint64_t GlContext::getCaps() const { - return 0; + return BGFX_CAPS_SWAP_CHAIN; } - SwapChainGL* GlContext::createSwapChain(void* /*_nwh*/) + SwapChainGL* GlContext::createSwapChain(void* _nwh) { - BX_CHECK(false, "Shouldn't be called!"); - return NULL; + return BX_NEW(g_allocator, SwapChainGL)(/*m_display, m_config,*/ (EAGLContext*)m_context, (CAEAGLLayer*)_nwh); } - void GlContext::destroySwapChain(SwapChainGL* /*_swapChain*/) + void GlContext::destroySwapChain(SwapChainGL* _swapChain) { - BX_CHECK(false, "Shouldn't be called!"); + BX_DELETE(g_allocator, _swapChain); } void GlContext::swap(SwapChainGL* _swapChain) { - BX_CHECK(NULL == _swapChain, "Shouldn't be called!"); BX_UNUSED(_swapChain); - GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_colorRbo) ); - EAGLContext* context = (EAGLContext*)m_context; - [context presentRenderbuffer:GL_RENDERBUFFER]; + makeCurrent(_swapChain); + + if (NULL == _swapChain) + { + GL_CHECK(glBindRenderbuffer(GL_RENDERBUFFER, m_colorRbo) ); + EAGLContext* context = (EAGLContext*)m_context; + [context presentRenderbuffer:GL_RENDERBUFFER]; + } + else + { + _swapChain->swapBuffers(); + } } - void GlContext::makeCurrent(SwapChainGL* /*_swapChain*/) + void GlContext::makeCurrent(SwapChainGL* _swapChain) { + if (m_current != _swapChain) + { + m_current = _swapChain; + + if (NULL == _swapChain) + { + [EAGLContext setCurrentContext:(EAGLContext*)m_context]; + GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo) ); + } + else + { + _swapChain->makeCurrent(); + } + } } void GlContext::import() diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index cd750514..0f5d7ddb 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2562,16 +2562,7 @@ namespace bgfx { namespace gl { FrameBufferGL& frameBuffer = m_frameBuffers[_fbh.idx]; _height = frameBuffer.m_height; - if (UINT16_MAX != frameBuffer.m_denseIdx) - { - m_glctx.makeCurrent(frameBuffer.m_swapChain); - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) ); - } - else - { - m_glctx.makeCurrent(NULL); - GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer.m_fbo[0]) ); - } + m_glctx.makeCurrent(frameBuffer.m_swapChain); } m_fbh = _fbh;