1/* 2----------------------------------------------------------------------------- 3This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5For the latest info, see http://www.ogre3d.org/ 6 7Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9Permission is hereby granted, free of charge, to any person obtaining a copy 10of this software and associated documentation files (the "Software"), to deal 11in the Software without restriction, including without limitation the rights 12to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13copies of the Software, and to permit persons to whom the Software is 14furnished to do so, subject to the following conditions: 15 16The above copyright notice and this permission notice shall be included in 17all copies or substantial portions of the Software. 18 19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25THE SOFTWARE. 26----------------------------------------------------------------------------- 27*/ 28 29#include "OgreEAGLES2Context.h" 30#include "OgreGLES2RenderSystem.h" 31#include "OgreRoot.h" 32 33namespace Ogre { 34 EAGLES2Context::EAGLES2Context(CAEAGLLayer *drawable, EAGLSharegroup *group) 35 : 36 mBackingWidth(0), 37 mBackingHeight(0), 38 mViewRenderbuffer(0), 39 mViewFramebuffer(0), 40 mDepthRenderbuffer(0), 41 mIsMultiSampleSupported(false), 42 mNumSamples(0), 43 mFSAAFramebuffer(0), 44 mFSAARenderbuffer(0) 45 { 46 47 mDrawable = [drawable retain]; 48 49#if OGRE_NO_GLES3_SUPPORT == 0 50 NSUInteger renderingAPI = kEAGLRenderingAPIOpenGLES3; 51#else 52 NSUInteger renderingAPI = kEAGLRenderingAPIOpenGLES2; 53#endif 54 // If the group argument is not NULL, then we assume that an externally created EAGLSharegroup 55 // is to be used and a context is created using that group. 56 if(group) 57 { 58 mContext = [[EAGLContext alloc] initWithAPI:renderingAPI sharegroup:group]; 59 } 60 else 61 { 62 mContext = [[EAGLContext alloc] initWithAPI:renderingAPI]; 63 } 64 65 if (!mContext || ![EAGLContext setCurrentContext:mContext]) 66 { 67 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 68 "Unable to create a suitable EAGLContext", 69 __FUNCTION__); 70 } 71 } 72 73 EAGLES2Context::~EAGLES2Context() 74 { 75 GLES2RenderSystem *rs = 76 static_cast<GLES2RenderSystem*>(Root::getSingleton().getRenderSystem()); 77 78 rs->_unregisterContext(this); 79 80 destroyFramebuffer(); 81 82 if ([EAGLContext currentContext] == mContext) 83 { 84 [EAGLContext setCurrentContext:nil]; 85 } 86 87 [mContext release]; 88 [mDrawable release]; 89 } 90 91 bool EAGLES2Context::createFramebuffer() 92 { 93 destroyFramebuffer(); 94 95 OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mViewFramebuffer)); 96 OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mViewRenderbuffer)); 97 98 OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mViewFramebuffer)); 99 OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mViewRenderbuffer)); 100 101 if(![mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(id<EAGLDrawable>) mDrawable]) 102 { 103 glGetError(); 104 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 105 "Failed to bind the drawable to a renderbuffer object", 106 __FUNCTION__); 107 return false; 108 } 109 110 OGRE_CHECK_GL_ERROR(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mBackingWidth)); 111 OGRE_CHECK_GL_ERROR(glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mBackingHeight)); 112 OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mViewRenderbuffer)); 113 114#if GL_APPLE_framebuffer_multisample 115 if(mIsMultiSampleSupported && mNumSamples > 0) 116 { 117 // Determine how many MSAS samples to use 118 GLint maxSamplesAllowed; 119 glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed); 120 int samplesToUse = (mNumSamples > maxSamplesAllowed) ? maxSamplesAllowed : mNumSamples; 121 122 // Create the FSAA framebuffer (offscreen) 123 OGRE_CHECK_GL_ERROR(glGenFramebuffers(1, &mFSAAFramebuffer)); 124 OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mFSAAFramebuffer)); 125 126 /* Create the offscreen MSAA color buffer. 127 * After rendering, the contents of this will be blitted into mFSAAFramebuffer */ 128 OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mFSAARenderbuffer)); 129 OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mFSAARenderbuffer)); 130 OGRE_CHECK_GL_ERROR(glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, samplesToUse, GL_RGBA8_OES, mBackingWidth, mBackingHeight)); 131 OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mFSAARenderbuffer)); 132 133 // Create the FSAA depth buffer 134 OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mDepthRenderbuffer)); 135 OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer)); 136 OGRE_CHECK_GL_ERROR(glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, samplesToUse, GL_DEPTH_COMPONENT24_OES, mBackingWidth, mBackingHeight)); 137 OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer)); 138 139 // Validate the FSAA framebuffer 140 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 141 { 142 glGetError(); 143 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 144 "Failed to make a complete FSAA framebuffer object", 145 __FUNCTION__); 146 return false; 147 } 148 } 149 else 150#endif 151 { 152 OGRE_CHECK_GL_ERROR(glGenRenderbuffers(1, &mDepthRenderbuffer)); 153 OGRE_CHECK_GL_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer)); 154 OGRE_CHECK_GL_ERROR(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, mBackingWidth, mBackingHeight)); 155 OGRE_CHECK_GL_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbuffer)); 156 } 157 158 OGRE_CHECK_GL_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, mViewFramebuffer)); 159 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 160 { 161 glGetError(); 162 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 163 "Failed to make a complete framebuffer object", 164 __FUNCTION__); 165 return false; 166 } 167 168 return true; 169 } 170 171 void EAGLES2Context::destroyFramebuffer() 172 { 173 OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &mViewFramebuffer)); 174 mViewFramebuffer = 0; 175 OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mViewRenderbuffer)); 176 mViewRenderbuffer = 0; 177 178 if(mFSAARenderbuffer) 179 { 180 OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mFSAARenderbuffer)); 181 mFSAARenderbuffer = 0; 182 } 183 184 if(mFSAAFramebuffer) 185 { 186 OGRE_CHECK_GL_ERROR(glDeleteFramebuffers(1, &mFSAAFramebuffer)); 187 mFSAAFramebuffer = 0; 188 } 189 190 if(mDepthRenderbuffer) 191 { 192 OGRE_CHECK_GL_ERROR(glDeleteRenderbuffers(1, &mDepthRenderbuffer)); 193 mDepthRenderbuffer = 0; 194 } 195 } 196 197 void EAGLES2Context::setCurrent() 198 { 199 BOOL ret = [EAGLContext setCurrentContext:mContext]; 200 if (!ret) 201 { 202 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 203 "Failed to make context current", 204 __FUNCTION__); 205 } 206 } 207 208 void EAGLES2Context::endCurrent() 209 { 210 // Do nothing 211 } 212 213 GLES2Context * EAGLES2Context::clone() const 214 { 215 return new EAGLES2Context(mDrawable, [mContext sharegroup]); 216 } 217 218 CAEAGLLayer * EAGLES2Context::getDrawable() const 219 { 220 return mDrawable; 221 } 222 223 EAGLContext * EAGLES2Context::getContext() const 224 { 225 return mContext; 226 } 227} 228