blob: a6625a1e72fff61bd832573da845b7ccf2fe759c [file] [log] [blame]
/*-------------------------------------------------------------------------
* 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