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 OS X platform.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuOSXPlatform.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluRenderConfig.hpp"
27 #include "tcuRenderTarget.hpp"
28 #include "glwFunctions.hpp"
29 #include "glwInitFunctions.hpp"
30 #include "deDynamicLibrary.hpp"
31 #include "glwEnums.hpp"
32 #include "gluDefs.hpp"
33 
34 #include <string>
35 
36 #include <OpenGL/OpenGL.h>
37 #include <OpenGL/CGLCurrent.h>
38 #include <OpenGL/CGLContext.h>
39 #include <OpenGL/CGLTypes.h>
40 #include <OpenGL/CGLRenderers.h>
41 
42 #define OPENGL_LIBRARY_PATH "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
43 
44 namespace tcu
45 {
46 
47 namespace
48 {
49 
50 class GLFunctionLoader : public glw::FunctionLoader
51 {
52 public:
GLFunctionLoader(const char * path)53 	GLFunctionLoader (const char* path)
54 		: m_library(path)
55 	{
56 	}
57 
get(const char * name) const58 	glw::GenericFuncType get (const char* name) const
59 	{
60 		return m_library.getFunction(name);
61 	}
62 
63 private:
64 	de::DynamicLibrary m_library;
65 };
66 
67 } // anonymous
68 
69 class CGLRenderContext : public glu::RenderContext
70 {
71 public:
72 								CGLRenderContext		(const glu::RenderConfig& config);
73 								~CGLRenderContext		(void);
74 
getType(void) const75 	glu::ContextType			getType					(void) const { return m_type;			}
getFunctions(void) const76 	const glw::Functions&		getFunctions			(void) const { return m_functions;		}
getRenderTarget(void) const77 	const tcu::RenderTarget&	getRenderTarget			(void) const { return m_renderTarget;	}
postIterate(void)78 	void						postIterate				(void) {}
79 
80 private:
81 	const glu::ContextType		m_type;
82 	CGLContextObj				m_context;
83 	glw::Functions				m_functions;
84 	RenderTarget				m_renderTarget;
85 };
86 
getCGLProfile(glu::ContextType type)87 static CGLOpenGLProfile getCGLProfile (glu::ContextType type)
88 {
89 	if (type.getAPI().getProfile() != glu::PROFILE_CORE)
90 		throw NotSupportedError("Requested OpenGL profile is not supported in CGL");
91 
92 	if (type.getAPI().getMajorVersion() == 4)
93 		return kCGLOGLPVersion_GL4_Core;
94 	else if (type.getAPI().getMajorVersion() == 3)
95 		return kCGLOGLPVersion_GL3_Core;
96 	else
97 		throw NotSupportedError("Requested OpenGL version is not supported in CGL");
98 }
99 
getVersion(const glw::Functions & gl)100 static glu::ApiType getVersion (const glw::Functions& gl)
101 {
102 	int major = 0;
103 	int minor = 0;
104 	gl.getIntegerv(GL_MAJOR_VERSION, &major);
105 	gl.getIntegerv(GL_MINOR_VERSION, &minor);
106 	GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to query exact GL version");
107 	return glu::ApiType::core(major, minor);
108 }
109 
CGLRenderContext(const glu::RenderConfig & config)110 CGLRenderContext::CGLRenderContext (const glu::RenderConfig& config)
111 	: m_type			(config.type)
112 	, m_context			(DE_NULL)
113 	, m_renderTarget	(0, 0, tcu::PixelFormat(0,0,0,0), 0, 0, 0)
114 {
115 	try
116 	{
117 		const CGLPixelFormatAttribute attribs[] =
118 		{
119 			kCGLPFAAccelerated,
120 			kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)getCGLProfile(config.type),
121 			(CGLPixelFormatAttribute)0
122 		};
123 
124 		CGLPixelFormatObj	pixelFormat;
125 		int					numVScreens;
126 
127 		if (CGLChoosePixelFormat(&attribs[0], &pixelFormat, &numVScreens) != kCGLNoError)
128 			throw NotSupportedError("No compatible pixel formats found");
129 
130 		try
131 		{
132 			if (CGLCreateContext(pixelFormat, DE_NULL, &m_context) != kCGLNoError)
133 				throw ResourceError("Failed to create CGL context");
134 
135 			if (CGLSetCurrentContext(m_context) != kCGLNoError)
136 				throw ResourceError("Failed to set current CGL context");
137 		}
138 		catch (...)
139 		{
140 			CGLReleasePixelFormat(pixelFormat);
141 			throw;
142 		}
143 
144 		CGLReleasePixelFormat(pixelFormat);
145 
146 		{
147 			GLFunctionLoader loader(OPENGL_LIBRARY_PATH);
148 			glu::initFunctions(&m_functions, &loader, config.type.getAPI());
149 		}
150 
151 		{
152 			const glu::ApiType actualApi = getVersion(m_functions);
153 			if (!contextSupports(glu::ContextType(actualApi, glu::ContextFlags(0)), config.type.getAPI()))
154 				throw tcu::NotSupportedError("OpenGL version not supported");
155 		}
156 	}
157 	catch (...)
158 	{
159 		if (m_context)
160 		{
161 			CGLSetCurrentContext(DE_NULL);
162 			CGLDestroyContext(m_context);
163 		}
164 		throw;
165 	}
166 }
167 
~CGLRenderContext(void)168 CGLRenderContext::~CGLRenderContext (void)
169 {
170 	CGLSetCurrentContext(DE_NULL);
171 	if (m_context)
172 		CGLDestroyContext(m_context);
173 }
174 
175 class CGLContextFactory : public glu::ContextFactory
176 {
177 public:
CGLContextFactory(void)178 	CGLContextFactory (void)
179 		: glu::ContextFactory("cgl", "CGL Context (surfaceless, use fbo)")
180 	{
181 	}
182 
createContext(const glu::RenderConfig & config,const tcu::CommandLine &) const183 	glu::RenderContext*	createContext (const glu::RenderConfig& config, const tcu::CommandLine&) const
184 	{
185 		return new CGLRenderContext(config);
186 	}
187 };
188 
OSXPlatform(void)189 OSXPlatform::OSXPlatform (void)
190 {
191 	m_contextFactoryRegistry.registerFactory(new CGLContextFactory());
192 }
193 
~OSXPlatform(void)194 OSXPlatform::~OSXPlatform (void)
195 {
196 }
197 
198 } // tcu
199 
createPlatform(void)200 tcu::Platform* createPlatform (void)
201 {
202 	return new tcu::OSXPlatform();
203 }
204