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 "OgreEAGLESContext.h" 30#include "OgreGLESRenderSystem.h" 31#include "OgreRoot.h" 32 33namespace Ogre { 34 EAGLESContext::EAGLESContext(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 the group argument is not NULL, then we assume that an externally created EAGLSharegroup 50 // is to be used and a context is created using that group. 51 if(group) 52 { 53 mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 sharegroup:group]; 54 } 55 else 56 { 57 mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; 58 } 59 60 if (!mContext || ![EAGLContext setCurrentContext:mContext]) 61 { 62 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 63 "Unable to create a suitable EAGLContext", 64 __FUNCTION__); 65 } 66 } 67 68 EAGLESContext::~EAGLESContext() 69 { 70 GLESRenderSystem *rs = 71 static_cast<GLESRenderSystem*>(Root::getSingleton().getRenderSystem()); 72 73 rs->_unregisterContext(this); 74 75 destroyFramebuffer(); 76 77 if ([EAGLContext currentContext] == mContext) 78 { 79 [EAGLContext setCurrentContext:nil]; 80 } 81 82 [mContext release]; 83 [mDrawable release]; 84 } 85 86 bool EAGLESContext::createFramebuffer() 87 { 88 destroyFramebuffer(); 89 90 glGenFramebuffersOES(1, &mViewFramebuffer); 91 GL_CHECK_ERROR 92 glGenRenderbuffersOES(1, &mViewRenderbuffer); 93 GL_CHECK_ERROR 94 95 glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); 96 GL_CHECK_ERROR 97 glBindRenderbufferOES(GL_RENDERBUFFER_OES, mViewRenderbuffer); 98 GL_CHECK_ERROR 99 100 if(![mContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id<EAGLDrawable>) mDrawable]) 101 { 102 GL_CHECK_ERROR 103 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 104 "Failed to bind the drawable to a renderbuffer object", 105 __FUNCTION__); 106 return false; 107 } 108 109 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &mBackingWidth); 110 GL_CHECK_ERROR 111 glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &mBackingHeight); 112 GL_CHECK_ERROR 113 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mViewRenderbuffer); 114 GL_CHECK_ERROR 115 116#if GL_APPLE_framebuffer_multisample 117 if(mIsMultiSampleSupported && mNumSamples > 0) 118 { 119 // Determine how many MSAS samples to use 120 GLint maxSamplesAllowed; 121 glGetIntegerv(GL_MAX_SAMPLES_APPLE, &maxSamplesAllowed); 122 int samplesToUse = (mNumSamples > maxSamplesAllowed) ? maxSamplesAllowed : mNumSamples; 123 124 // Create the FSAA framebuffer (offscreen) 125 glGenFramebuffersOES(1, &mFSAAFramebuffer); 126 GL_CHECK_ERROR 127 glBindFramebufferOES(GL_FRAMEBUFFER_OES, mFSAAFramebuffer); 128 GL_CHECK_ERROR 129 130 /* Create the offscreen MSAA color buffer. 131 * After rendering, the contents of this will be blitted into mFSAAFramebuffer */ 132 glGenRenderbuffersOES(1, &mFSAARenderbuffer); 133 GL_CHECK_ERROR 134 glBindRenderbufferOES(GL_RENDERBUFFER_OES, mFSAARenderbuffer); 135 GL_CHECK_ERROR 136 glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse, GL_RGBA8_OES, mBackingWidth, mBackingHeight); 137 GL_CHECK_ERROR 138 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, mFSAARenderbuffer); 139 GL_CHECK_ERROR 140 141 // Create the FSAA depth buffer 142 glGenRenderbuffersOES(1, &mDepthRenderbuffer); 143 GL_CHECK_ERROR 144 glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer); 145 GL_CHECK_ERROR 146 glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, samplesToUse, GL_DEPTH_COMPONENT24_OES, mBackingWidth, mBackingHeight); 147 GL_CHECK_ERROR 148 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer); 149 GL_CHECK_ERROR 150 151 // Validate the FSAA framebuffer 152 if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) 153 { 154 GL_CHECK_ERROR 155 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 156 "Failed to make a complete FSAA framebuffer object", 157 __FUNCTION__); 158 return false; 159 } 160 } 161 else 162#endif 163 { 164 glGenRenderbuffersOES(1, &mDepthRenderbuffer); 165 GL_CHECK_ERROR 166 glBindRenderbufferOES(GL_RENDERBUFFER_OES, mDepthRenderbuffer); 167 GL_CHECK_ERROR 168 glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, mBackingWidth, mBackingHeight); 169 GL_CHECK_ERROR 170 glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, mDepthRenderbuffer); 171 GL_CHECK_ERROR 172 } 173 174 glBindFramebufferOES(GL_FRAMEBUFFER_OES, mViewFramebuffer); 175 if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) 176 { 177 GL_CHECK_ERROR 178 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 179 "Failed to make a complete framebuffer object", 180 __FUNCTION__); 181 return false; 182 } 183 184 return true; 185 } 186 187 void EAGLESContext::destroyFramebuffer() 188 { 189 glDeleteFramebuffersOES(1, &mViewFramebuffer); 190 mViewFramebuffer = 0; 191 glDeleteRenderbuffersOES(1, &mViewRenderbuffer); 192 mViewRenderbuffer = 0; 193 194 if(mFSAARenderbuffer) 195 { 196 glDeleteRenderbuffersOES(1, &mFSAARenderbuffer); 197 mFSAARenderbuffer = 0; 198 } 199 200 if(mFSAAFramebuffer) 201 { 202 glDeleteFramebuffersOES(1, &mFSAAFramebuffer); 203 mFSAAFramebuffer = 0; 204 } 205 206 if(mDepthRenderbuffer) 207 { 208 glDeleteRenderbuffersOES(1, &mDepthRenderbuffer); 209 mDepthRenderbuffer = 0; 210 } 211 } 212 213 void EAGLESContext::setCurrent() 214 { 215 GLboolean ret = [EAGLContext setCurrentContext:mContext]; 216 if (!ret) 217 { 218 OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 219 "Failed to make context current", 220 __FUNCTION__); 221 } 222 } 223 224 void EAGLESContext::endCurrent() 225 { 226 // Do nothing 227 } 228 229 GLESContext * EAGLESContext::clone() const 230 { 231 return const_cast<EAGLESContext *>(this); 232 } 233 234 CAEAGLLayer * EAGLESContext::getDrawable() const 235 { 236 return mDrawable; 237 } 238 239 EAGLContext * EAGLESContext::getContext() const 240 { 241 return mContext; 242 } 243} 244