| /*------------------------------------------------------------------------- |
| * drawElements Quality Program Tester Core |
| * ---------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief iOS Platform implementation. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "tcuIOSPlatform.hh" |
| #include "gluRenderConfig.hpp" |
| #include "gluFboRenderContext.hpp" |
| |
| #include "glwInitES20Direct.hpp" |
| #include "glwInitES30Direct.hpp" |
| |
| |
| namespace tcu |
| { |
| namespace ios |
| { |
| |
| // ScreenManager |
| |
| ScreenManager::ScreenManager (tcuEAGLView* view) |
| : m_view(view) |
| { |
| } |
| |
| ScreenManager::~ScreenManager (void) |
| { |
| } |
| |
| CAEAGLLayer* ScreenManager::acquireScreen (void) |
| { |
| if (!m_viewLock.tryLock()) |
| throw ResourceError("View is already is in use"); |
| |
| return [m_view getEAGLLayer]; |
| } |
| |
| void ScreenManager::releaseScreen (CAEAGLLayer* layer) |
| { |
| DE_UNREF(layer); |
| m_viewLock.unlock(); |
| } |
| |
| // ContextFactory |
| |
| ContextFactory::ContextFactory (ScreenManager* screenManager) |
| : glu::ContextFactory ("eagl", "iOS EAGL Context") |
| , m_screenManager (screenManager) |
| { |
| } |
| |
| ContextFactory::~ContextFactory (void) |
| { |
| } |
| |
| glu::RenderContext* ContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const |
| { |
| RawContext* rawContext = new RawContext(config.type); |
| |
| try |
| { |
| if (config.surfaceType == glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC) |
| return new glu::FboRenderContext(rawContext, config); |
| else if (config.surfaceType == glu::RenderConfig::SURFACETYPE_WINDOW) |
| return new ScreenContext(m_screenManager, config); |
| else |
| throw NotSupportedError("Unsupported surface type"); |
| } |
| catch (...) |
| { |
| delete rawContext; |
| throw; |
| } |
| } |
| |
| // Platform |
| |
| Platform::Platform (ScreenManager* screenManager) |
| { |
| m_contextFactoryRegistry.registerFactory(new ContextFactory(screenManager)); |
| } |
| |
| Platform::~Platform (void) |
| { |
| } |
| |
| // RawContext |
| |
| static EAGLRenderingAPI getEAGLApi (glu::ContextType type) |
| { |
| if (type.getAPI() == glu::ApiType::es(3,0)) |
| return kEAGLRenderingAPIOpenGLES3; |
| else if (type.getAPI() == glu::ApiType::es(2,0)) |
| return kEAGLRenderingAPIOpenGLES2; |
| else |
| throw NotSupportedError("Requested GL API is not supported on iOS"); |
| } |
| |
| RawContext::RawContext (glu::ContextType type) |
| : m_type (type) |
| , m_context (DE_NULL) |
| , m_emptyTarget (0, 0, tcu::PixelFormat(0,0,0,0), 0, 0, 0) |
| { |
| const EAGLRenderingAPI eaglApi = getEAGLApi(type); |
| |
| m_context = [[EAGLContext alloc] initWithAPI:eaglApi]; |
| if (!m_context) |
| throw ResourceError("Failed to create EAGL context"); |
| |
| try |
| { |
| if (![EAGLContext setCurrentContext:m_context]) |
| throw ResourceError("Failed to set current EAGL context"); |
| |
| if (type.getAPI() == glu::ApiType::es(3,0)) |
| glw::initES30Direct(&m_functions); |
| else if (type.getAPI() == glu::ApiType::es(2,0)) |
| glw::initES20Direct(&m_functions); |
| else |
| throw InternalError("Unsupproted API for loading functions"); |
| } |
| catch (...) |
| { |
| if ([EAGLContext currentContext] == m_context) |
| [EAGLContext setCurrentContext:nil]; |
| |
| [m_context release]; |
| throw; |
| } |
| } |
| |
| RawContext::~RawContext (void) |
| { |
| if ([EAGLContext currentContext] == m_context) |
| [EAGLContext setCurrentContext:nil]; |
| |
| [m_context release]; |
| } |
| |
| void RawContext::postIterate (void) |
| { |
| } |
| |
| NSString* chooseLayerColorFormat (const glu::RenderConfig& config) |
| { |
| const bool cr = config.redBits != glu::RenderConfig::DONT_CARE; |
| const bool cg = config.greenBits != glu::RenderConfig::DONT_CARE; |
| const bool cb = config.blueBits != glu::RenderConfig::DONT_CARE; |
| const bool ca = config.alphaBits != glu::RenderConfig::DONT_CARE; |
| |
| if ((!cr || config.redBits == 8) && |
| (!cg || config.greenBits == 8) && |
| (!cb || config.blueBits == 8) && |
| (!ca || config.alphaBits == 8)) |
| return kEAGLColorFormatRGBA8; |
| |
| if ((!cr || config.redBits == 5) && |
| (!cg || config.greenBits == 6) && |
| (!cb || config.blueBits == 5) && |
| (!ca || config.alphaBits == 0)) |
| return kEAGLColorFormatRGB565; |
| |
| return nil; |
| } |
| |
| // ScreenContext |
| |
| ScreenContext::ScreenContext (ScreenManager* screenManager, const glu::RenderConfig& config) |
| : RawContext (config.type) |
| , m_screenManager (screenManager) |
| , m_layer (DE_NULL) |
| , m_framebuffer (*this) // \note Perfectly safe to give reference to this RC as everything except postIterate() works at this point. |
| , m_colorBuffer (*this) |
| , m_depthStencilBuffer (*this) |
| { |
| m_layer = m_screenManager->acquireScreen(); |
| try |
| { |
| createFramebuffer(config); |
| } |
| catch (...) |
| { |
| m_screenManager->releaseScreen(m_layer); |
| throw; |
| } |
| } |
| |
| ScreenContext::~ScreenContext (void) |
| { |
| m_screenManager->releaseScreen(m_layer); |
| } |
| |
| void ScreenContext::createFramebuffer (const glu::RenderConfig& config) |
| { |
| const glw::Functions& gl = getFunctions(); |
| const NSString* const colorFormat = chooseLayerColorFormat(config); |
| const deUint32 depthStencilFormat = chooseDepthStencilFormat(config); |
| tcu::PixelFormat pixelFormat; |
| int width = 0; |
| int height = 0; |
| int depthBits = 0; |
| int stencilBits = 0; |
| |
| if (config.numSamples > 0) |
| throw NotSupportedError("Multisample config is not supported"); |
| |
| if (colorFormat == nil) |
| throw NotSupportedError("Unsupported color attachment format"); |
| |
| if ((config.depthBits > 0 || config.stencilBits > 0) && depthStencilFormat == 0) |
| throw NotSupportedError("Unsupported depth & stencil attachment format"); |
| |
| m_layer.opaque = TRUE; |
| m_layer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: |
| colorFormat, kEAGLDrawablePropertyColorFormat, |
| [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, |
| nil]; |
| |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *m_colorBuffer); |
| if (![getEAGLContext() renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)m_layer]) |
| throw ResourceError("Failed to allocate color renderbuffer"); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Creating color renderbuffer"); |
| |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, &pixelFormat.redBits); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_GREEN_SIZE, &pixelFormat.greenBits); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_BLUE_SIZE, &pixelFormat.blueBits); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, &pixelFormat.alphaBits); |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Querying surface size failed"); |
| |
| if (depthStencilFormat != 0) |
| { |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *m_depthStencilBuffer); |
| gl.renderbufferStorage(GL_RENDERBUFFER, depthStencilFormat, width, height); |
| |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_DEPTH_SIZE, &depthBits); |
| gl.getRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_STENCIL_SIZE, &stencilBits); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Creating depth / stencil renderbuffer"); |
| } |
| |
| gl.bindFramebuffer(GL_FRAMEBUFFER, *m_framebuffer); |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, *m_colorBuffer); |
| |
| if (depthStencilFormat != 0) |
| { |
| if (depthBits > 0) |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *m_depthStencilBuffer); |
| |
| if (stencilBits > 0) |
| gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, *m_depthStencilBuffer); |
| } |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), "Creating framebuffer"); |
| |
| if (gl.checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) |
| throw NotSupportedError("Framebuffer is not complete"); |
| |
| // Set up correct viewport for first test case. |
| gl.viewport(0, 0, width, height); |
| |
| m_renderTarget = tcu::RenderTarget(width, height, pixelFormat, depthBits, stencilBits, 0); |
| } |
| |
| void ScreenContext::postIterate (void) |
| { |
| const glw::Functions& gl = getFunctions(); |
| gl.bindRenderbuffer(GL_RENDERBUFFER, *m_colorBuffer); |
| |
| if (![getEAGLContext() presentRenderbuffer:GL_RENDERBUFFER]) |
| throw ResourceError("presentRenderbuffer() failed"); |
| } |
| |
| } // ios |
| } // tcu |