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