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