/*-------------------------------------------------------------------------
* 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 OS X platform.
*//*--------------------------------------------------------------------*/
#include "tcuOSXPlatform.hpp"
#include "gluRenderContext.hpp"
#include "gluRenderConfig.hpp"
#include "tcuRenderTarget.hpp"
#include "glwFunctions.hpp"
#include "glwInitFunctions.hpp"
#include "deDynamicLibrary.hpp"
#include "glwEnums.hpp"
#include "gluDefs.hpp"
#include <string>
#include <OpenGL/OpenGL.h>
#include <OpenGL/CGLCurrent.h>
#include <OpenGL/CGLContext.h>
#include <OpenGL/CGLTypes.h>
#include <OpenGL/CGLRenderers.h>
#define OPENGL_LIBRARY_PATH "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
namespace tcu
{
namespace
{
class GLFunctionLoader : public glw::FunctionLoader
{
public:
GLFunctionLoader (const char* path)
: m_library(path)
{
}
glw::GenericFuncType get (const char* name) const
{
return m_library.getFunction(name);
}
private:
de::DynamicLibrary m_library;
};
} // anonymous
class CGLRenderContext : public glu::RenderContext
{
public:
CGLRenderContext (const glu::RenderConfig& config);
~CGLRenderContext (void);
glu::ContextType getType (void) const { return m_type; }
const glw::Functions& getFunctions (void) const { return m_functions; }
const tcu::RenderTarget& getRenderTarget (void) const { return m_renderTarget; }
void postIterate (void) {}
private:
const glu::ContextType m_type;
CGLContextObj m_context;
glw::Functions m_functions;
RenderTarget m_renderTarget;
};
static CGLOpenGLProfile getCGLProfile (glu::ContextType type)
{
if (type.getAPI().getProfile() != glu::PROFILE_CORE)
throw NotSupportedError("Requested OpenGL profile is not supported in CGL");
if (type.getAPI().getMajorVersion() == 4)
return kCGLOGLPVersion_GL4_Core;
else if (type.getAPI().getMajorVersion() == 3)
return kCGLOGLPVersion_GL3_Core;
else
throw NotSupportedError("Requested OpenGL version is not supported in CGL");
}
static glu::ApiType getVersion (const glw::Functions& gl)
{
int major = 0;
int minor = 0;
gl.getIntegerv(GL_MAJOR_VERSION, &major);
gl.getIntegerv(GL_MINOR_VERSION, &minor);
GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to query exact GL version");
return glu::ApiType::core(major, minor);
}
CGLRenderContext::CGLRenderContext (const glu::RenderConfig& config)
: m_type (config.type)
, m_context (DE_NULL)
, m_renderTarget (0, 0, tcu::PixelFormat(0,0,0,0), 0, 0, 0)
{
try
{
const CGLPixelFormatAttribute attribs[] =
{
kCGLPFAAccelerated,
kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)getCGLProfile(config.type),
(CGLPixelFormatAttribute)0
};
CGLPixelFormatObj pixelFormat;
int numVScreens;
if (CGLChoosePixelFormat(&attribs[0], &pixelFormat, &numVScreens) != kCGLNoError)
throw NotSupportedError("No compatible pixel formats found");
try
{
if (CGLCreateContext(pixelFormat, DE_NULL, &m_context) != kCGLNoError)
throw ResourceError("Failed to create CGL context");
if (CGLSetCurrentContext(m_context) != kCGLNoError)
throw ResourceError("Failed to set current CGL context");
}
catch (...)
{
CGLReleasePixelFormat(pixelFormat);
throw;
}
CGLReleasePixelFormat(pixelFormat);
{
GLFunctionLoader loader(OPENGL_LIBRARY_PATH);
glu::initFunctions(&m_functions, &loader, config.type.getAPI());
}
{
const glu::ApiType actualApi = getVersion(m_functions);
if (!contextSupports(glu::ContextType(actualApi, glu::ContextFlags(0)), config.type.getAPI()))
throw tcu::NotSupportedError("OpenGL version not supported");
}
}
catch (...)
{
if (m_context)
{
CGLSetCurrentContext(DE_NULL);
CGLDestroyContext(m_context);
}
throw;
}
}
CGLRenderContext::~CGLRenderContext (void)
{
CGLSetCurrentContext(DE_NULL);
if (m_context)
CGLDestroyContext(m_context);
}
class CGLContextFactory : public glu::ContextFactory
{
public:
CGLContextFactory (void)
: glu::ContextFactory("cgl", "CGL Context (surfaceless, use fbo)")
{
}
glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const
{
return new CGLRenderContext(config);
}
};
OSXPlatform::OSXPlatform (void)
{
m_contextFactoryRegistry.registerFactory(new CGLContextFactory());
}
OSXPlatform::~OSXPlatform (void)
{
}
} // tcu
tcu::Platform* createPlatform (void)
{
return new tcu::OSXPlatform();
}