1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief iOS Platform implementation. 22 *//*--------------------------------------------------------------------*/ 23 24#include "tcuIOSPlatform.hh" 25#include "gluFboRenderContext.hpp" 26#include "gluRenderConfig.hpp" 27 28#include "glwInitES20Direct.hpp" 29#include "glwInitES30Direct.hpp" 30 31namespace tcu 32{ 33namespace ios 34{ 35 36// ScreenManager 37 38ScreenManager::ScreenManager(tcuEAGLView *view) : m_view(view) {} 39 40ScreenManager::~ScreenManager(void) {} 41 42CAEAGLLayer *ScreenManager::acquireScreen(void) 43{ 44 if (!m_viewLock.tryLock()) 45 throw ResourceError("View is already is in use"); 46 47 return [m_view getEAGLLayer]; 48} 49 50void ScreenManager::releaseScreen(CAEAGLLayer *layer) 51{ 52 DE_UNREF(layer); 53 m_viewLock.unlock(); 54} 55 56// ContextFactory 57 58ContextFactory::ContextFactory(ScreenManager *screenManager) 59 : glu::ContextFactory("eagl", "iOS EAGL Context"), 60 m_screenManager(screenManager) 61{ 62} 63 64ContextFactory::~ContextFactory(void) {} 65 66glu::RenderContext * 67ContextFactory::createContext(const glu::RenderConfig &config, 68 const tcu::CommandLine &) const 69{ 70 RawContext *rawContext = new RawContext(config.type); 71 72 try 73 { 74 if (config.surfaceType == 75 glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC) 76 return new glu::FboRenderContext(rawContext, config); 77 else if (config.surfaceType == glu::RenderConfig::SURFACETYPE_WINDOW) 78 return new ScreenContext(m_screenManager, config); 79 else 80 throw NotSupportedError("Unsupported surface type"); 81 } 82 catch (...) 83 { 84 delete rawContext; 85 throw; 86 } 87} 88 89// Platform 90 91Platform::Platform(ScreenManager *screenManager) 92{ 93 m_contextFactoryRegistry.registerFactory(new ContextFactory(screenManager)); 94} 95 96Platform::~Platform(void) {} 97 98// RawContext 99 100static EAGLRenderingAPI getEAGLApi(glu::ContextType type) 101{ 102 if (type.getAPI() == glu::ApiType::es(3, 0)) 103 return kEAGLRenderingAPIOpenGLES3; 104 else if (type.getAPI() == glu::ApiType::es(2, 0)) 105 return kEAGLRenderingAPIOpenGLES2; 106 else 107 throw NotSupportedError("Requested GL API is not supported on iOS"); 108} 109 110RawContext::RawContext(glu::ContextType type) 111 : m_type(type), m_context(DE_NULL), 112 m_emptyTarget(0, 0, tcu::PixelFormat(0, 0, 0, 0), 0, 0, 0) 113{ 114 const EAGLRenderingAPI eaglApi = getEAGLApi(type); 115 116 m_context = [[EAGLContext alloc] initWithAPI:eaglApi]; 117 if (!m_context) 118 throw ResourceError("Failed to create EAGL context"); 119 120 try 121 { 122 if (![EAGLContext setCurrentContext:m_context]) 123 throw ResourceError("Failed to set current EAGL context"); 124 125 if (type.getAPI() == glu::ApiType::es(3, 0)) 126 glw::initES30Direct(&m_functions); 127 else if (type.getAPI() == glu::ApiType::es(2, 0)) 128 glw::initES20Direct(&m_functions); 129 else 130 throw InternalError("Unsupproted API for loading functions"); 131 } 132 catch (...) 133 { 134 if ([EAGLContext currentContext] == m_context) 135 [EAGLContext setCurrentContext:nil]; 136 137 [m_context release]; 138 throw; 139 } 140} 141 142RawContext::~RawContext(void) 143{ 144 if ([EAGLContext currentContext] == m_context) 145 [EAGLContext setCurrentContext:nil]; 146 147 [m_context release]; 148} 149 150void RawContext::postIterate(void) {} 151 152NSString *chooseLayerColorFormat(const glu::RenderConfig &config) 153{ 154 const bool cr = config.redBits != glu::RenderConfig::DONT_CARE; 155 const bool cg = config.greenBits != glu::RenderConfig::DONT_CARE; 156 const bool cb = config.blueBits != glu::RenderConfig::DONT_CARE; 157 const bool ca = config.alphaBits != glu::RenderConfig::DONT_CARE; 158 159 if ((!cr || config.redBits == 8) && (!cg || config.greenBits == 8) && 160 (!cb || config.blueBits == 8) && (!ca || config.alphaBits == 8)) 161 return kEAGLColorFormatRGBA8; 162 163 if ((!cr || config.redBits == 5) && (!cg || config.greenBits == 6) && 164 (!cb || config.blueBits == 5) && (!ca || config.alphaBits == 0)) 165 return kEAGLColorFormatRGB565; 166 167 return nil; 168} 169 170// ScreenContext 171 172ScreenContext::ScreenContext(ScreenManager *screenManager, 173 const glu::RenderConfig &config) 174 : RawContext(config.type), m_screenManager(screenManager), m_layer(DE_NULL), 175 m_framebuffer( 176 *this) // \note Perfectly safe to give reference to this RC as 177 // everything except postIterate() works at this point. 178 , 179 m_colorBuffer(*this), m_depthStencilBuffer(*this) 180{ 181 m_layer = m_screenManager->acquireScreen(); 182 try 183 { 184 createFramebuffer(config); 185 } 186 catch (...) 187 { 188 m_screenManager->releaseScreen(m_layer); 189 throw; 190 } 191} 192 193ScreenContext::~ScreenContext(void) { m_screenManager->releaseScreen(m_layer); } 194 195void ScreenContext::createFramebuffer(const glu::RenderConfig &config) 196{ 197 const glw::Functions &gl = getFunctions(); 198 const NSString *const colorFormat = chooseLayerColorFormat(config); 199 const uint32_t depthStencilFormat = chooseDepthStencilFormat(config); 200 tcu::PixelFormat pixelFormat; 201 int width = 0; 202 int height = 0; 203 int depthBits = 0; 204 int stencilBits = 0; 205 206 if (config.numSamples > 0) 207 throw NotSupportedError("Multisample config is not supported"); 208 209 if (colorFormat == nil) 210 throw NotSupportedError("Unsupported color attachment format"); 211 212 if ((config.depthBits > 0 || config.stencilBits > 0) && 213 depthStencilFormat == 0) 214 throw NotSupportedError( 215 "Unsupported depth & stencil attachment format"); 216 217 m_layer.opaque = TRUE; 218 m_layer.drawableProperties = [NSDictionary 219 dictionaryWithObjectsAndKeys:colorFormat, 220 kEAGLDrawablePropertyColorFormat, 221 [NSNumber numberWithBool:FALSE], 222 kEAGLDrawablePropertyRetainedBacking, nil]; 223 224 gl.bindRenderbuffer(GL_RENDERBUFFER, *m_colorBuffer); 225 if (![getEAGLContext() renderbufferStorage:GL_RENDERBUFFER 226 fromDrawable:(CAEAGLLayer *)m_layer]) 227 throw ResourceError("Failed to allocate color renderbuffer"); 228 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer"); 229 230 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, 231 &width); 232 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, 233 &height); 234 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, 235 &pixelFormat.redBits); 236 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_GREEN_SIZE, 237 &pixelFormat.greenBits); 238 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_BLUE_SIZE, 239 &pixelFormat.blueBits); 240 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, 241 &pixelFormat.alphaBits); 242 GLU_EXPECT_NO_ERROR(gl.getError(), "Querying surface size failed"); 243 244 if (depthStencilFormat != 0) 245 { 246 gl.bindRenderbuffer(GL_RENDERBUFFER, *m_depthStencilBuffer); 247 gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, 248 height); 249 250 gl.getRenderbufferParameteriv(GL_RENDERBUFFER, 251 GL_RENDERBUFFER_DEPTH_SIZE, &depthBits); 252 gl.getRenderbufferParameteriv( 253 GL_RENDERBUFFER, GL_RENDERBUFFER_STENCIL_SIZE, &stencilBits); 254 255 GLU_EXPECT_NO_ERROR(gl.getError(), 256 "Creating depth / stencil renderbuffer"); 257 } 258 259 gl.bindFramebuffer(GL_FRAMEBUFFER, *m_framebuffer); 260 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 261 GL_RENDERBUFFER, *m_colorBuffer); 262 263 if (depthStencilFormat != 0) 264 { 265 if (depthBits > 0) 266 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 267 GL_RENDERBUFFER, *m_depthStencilBuffer); 268 269 if (stencilBits > 0) 270 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 271 GL_RENDERBUFFER, *m_depthStencilBuffer); 272 } 273 274 GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer"); 275 276 if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 277 throw NotSupportedError("Framebuffer is not complete"); 278 279 // Set up correct viewport for first test case. 280 gl.viewport(0, 0, width, height); 281 282 m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, 283 stencilBits, 0); 284} 285 286void ScreenContext::postIterate(void) 287{ 288 const glw::Functions &gl = getFunctions(); 289 gl.bindRenderbuffer(GL_RENDERBUFFER, *m_colorBuffer); 290 291 if (![getEAGLContext() presentRenderbuffer:GL_RENDERBUFFER]) 292 throw ResourceError("presentRenderbuffer() failed"); 293} 294 295} // namespace ios 296} // namespace tcu 297