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