bad445d29c59c83b06e10b5bb2e0438302ba5748
[WebKit-https.git] / Source / WebCore / platform / graphics / cocoa / GraphicsContext3DCocoa.mm
1 /*
2  * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(GRAPHICS_CONTEXT_3D)
29 #import "GraphicsContext3D.h"
30
31 #if PLATFORM(IOS)
32 #import "GraphicsContext3DIOS.h"
33 #endif
34
35 #import "CanvasRenderingContext.h"
36 #import "Extensions3DOpenGL.h"
37 #import "GraphicsContext.h"
38 #import "GraphicsContext3DManager.h"
39 #import "HTMLCanvasElement.h"
40 #import "HostWindow.h"
41 #import "ImageBuffer.h"
42 #import "Logging.h"
43 #import "WebGLLayer.h"
44 #import "WebGLObject.h"
45 #import "WebGLRenderingContextBase.h"
46 #import <CoreGraphics/CGBitmapContext.h>
47 #import <sys/sysctl.h>
48 #import <sysexits.h>
49 #import <wtf/BlockObjCExceptions.h>
50 #import <wtf/text/CString.h>
51
52 #if USE(OPENGL_ES)
53 #import <OpenGLES/EAGL.h>
54 #import <OpenGLES/EAGLDrawable.h>
55 #import <OpenGLES/EAGLIOSurface.h>
56 #import <OpenGLES/ES2/glext.h>
57 #import <QuartzCore/QuartzCore.h>
58 #import <pal/spi/ios/OpenGLESSPI.h>
59 #else
60 #import <IOKit/IOKitLib.h>
61 #import <OpenGL/CGLRenderers.h>
62 #import <OpenGL/gl.h>
63 #endif
64
65 #if PLATFORM(MAC)
66 #import "ScreenProperties.h"
67 #endif
68
69 namespace WebCore {
70
71 static const unsigned statusCheckThreshold = 5;
72
73 // FIXME: This class is currently empty on Mac, but will get populated as
74 // the restructuring in https://bugs.webkit.org/show_bug.cgi?id=66903 is done
75 class GraphicsContext3DPrivate {
76 public:
77     GraphicsContext3DPrivate(GraphicsContext3D*) { }
78     
79     ~GraphicsContext3DPrivate() { }
80 };
81
82 #if USE(OPENGL)
83
84 static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest, bool antialias, bool isWebGL2, bool allowOfflineRenderers)
85 {
86     attribs.clear();
87     
88     attribs.append(kCGLPFAColorSize);
89     attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
90     attribs.append(kCGLPFADepthSize);
91     attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
92
93     // This attribute, while mentioning offline renderers, is actually
94     // allowing us to request the integrated graphics on a dual GPU
95     // system, and not force the discrete GPU.
96     // See https://developer.apple.com/library/mac/technotes/tn2229/_index.html
97     if (allowOfflineRenderers)
98         attribs.append(kCGLPFAAllowOfflineRenderers);
99
100     if (accelerated)
101         attribs.append(kCGLPFAAccelerated);
102     else {
103         attribs.append(kCGLPFARendererID);
104         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
105     }
106         
107     if (supersample && !antialias)
108         attribs.append(kCGLPFASupersample);
109
110     if (closest)
111         attribs.append(kCGLPFAClosestPolicy);
112
113     if (antialias) {
114         attribs.append(kCGLPFAMultisample);
115         attribs.append(kCGLPFASampleBuffers);
116         attribs.append(static_cast<CGLPixelFormatAttribute>(1));
117         attribs.append(kCGLPFASamples);
118         attribs.append(static_cast<CGLPixelFormatAttribute>(4));
119     }
120
121     if (isWebGL2) {
122         // FIXME: Instead of backing a WebGL2 GraphicsContext3D with a OpenGL 4 context, we should instead back it with ANGLE.
123         // Use an OpenGL 4 context for now until the ANGLE backend is ready.
124         attribs.append(kCGLPFAOpenGLProfile);
125         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_GL4_Core));
126     }
127         
128     attribs.append(static_cast<CGLPixelFormatAttribute>(0));
129 }
130
131 #endif // USE(OPENGL)
132
133 RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
134 {
135     // This implementation doesn't currently support rendering directly to the HostWindow.
136     if (renderStyle == RenderDirectlyToHostWindow)
137         return nullptr;
138
139     // Make space for the incoming context if we're full.
140     GraphicsContext3DManager::sharedManager().recycleContextIfNecessary();
141     if (GraphicsContext3DManager::sharedManager().hasTooManyContexts())
142         return nullptr;
143
144     RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle));
145
146     if (!context->m_contextObj)
147         return nullptr;
148
149     GraphicsContext3DManager::sharedManager().addContext(context.get(), hostWindow);
150
151     return context;
152 }
153
154 Ref<GraphicsContext3D> GraphicsContext3D::createShared(GraphicsContext3D& sharedContext)
155 {
156     auto hostWindow = GraphicsContext3DManager::sharedManager().hostWindowForContext(&sharedContext);
157     auto context = adoptRef(*new GraphicsContext3D(sharedContext.getContextAttributes(), hostWindow, sharedContext.m_renderStyle, &sharedContext));
158
159     GraphicsContext3DManager::sharedManager().addContext(context.ptr(), hostWindow);
160
161     return context;
162 }
163
164 #if PLATFORM(MAC)
165
166 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
167 static void setGPUByRegistryID(PlatformGraphicsContext3D contextObj, CGLPixelFormatObj pixelFormatObj, IORegistryGPUID preferredGPUID)
168 {
169     // When the WebProcess does not have access to the WindowServer, there is no way for OpenGL to tell which GPU is connected to a display.
170     // On 10.13+, find the virtual screen that corresponds to the preferred GPU by its registryID.
171     // CGLSetVirtualScreen can then be used to tell OpenGL which GPU it should be using.
172
173     if (!contextObj || !preferredGPUID)
174         return;
175
176     GLint virtualScreenCount = 0;
177     CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount, &virtualScreenCount);
178     ASSERT(error == kCGLNoError);
179
180     GLint firstAcceleratedScreen = -1;
181
182     for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen) {
183         GLint displayMask = 0;
184         error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFADisplayMask, &displayMask);
185         ASSERT(error == kCGLNoError);
186
187         auto gpuID = gpuIDForDisplayMask(displayMask);
188
189         if (gpuID == preferredGPUID) {
190             error = CGLSetVirtualScreen(contextObj, virtualScreen);
191             ASSERT(error == kCGLNoError);
192             LOG(WebGL, "Context (%p) set to GPU with ID: (%lld).", contextObj, gpuID);
193             return;
194         }
195
196         if (firstAcceleratedScreen < 0) {
197             GLint isAccelerated = 0;
198             error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFAAccelerated, &isAccelerated);
199             ASSERT(error == kCGLNoError);
200             if (isAccelerated)
201                 firstAcceleratedScreen = virtualScreen;
202         }
203     }
204
205     // No registryID match found; set to first hardware-accelerated virtual screen.
206     if (firstAcceleratedScreen >= 0) {
207         error = CGLSetVirtualScreen(contextObj, firstAcceleratedScreen);
208         ASSERT(error == kCGLNoError);
209         LOG(WebGL, "RegistryID (%lld) not matched; Context (%p) set to virtual screen (%d).", preferredGPUID, contextObj, firstAcceleratedScreen);
210     }
211 }
212 #else // __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
213 static void setGPUByDisplayMask(PlatformGraphicsContext3D contextObj, CGLPixelFormatObj pixelFormatObj, uint32_t preferredDisplayMask)
214 {
215     // A common case for multiple GPUs, external GPUs, is not supported before macOS 10.13.4.
216     // In the rarer case where there are still multiple displays plugged into multiple GPUs, this should still work.
217     // See code example at https://developer.apple.com/library/content/technotes/tn2229/_index.html#//apple_ref/doc/uid/DTS40008924-CH1-SUBSECTION7
218     // FIXME: Window server is not blocked before 10.14. There might be a more straightforward way to detect the correct GPU.
219
220     if (!contextObj || !preferredDisplayMask)
221         return;
222
223     GLint virtualScreenCount = 0;
224     CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount, &virtualScreenCount);
225     ASSERT(error == kCGLNoError);
226
227     for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen) {
228         GLint displayMask = 0;
229         error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFADisplayMask, &displayMask);
230         ASSERT(error == kCGLNoError);
231         if (error != kCGLNoError)
232             continue;
233
234         if (displayMask & preferredDisplayMask) {
235             error = CGLSetVirtualScreen(contextObj, virtualScreen);
236             ASSERT(error == kCGLNoError);
237             return;
238         }
239     }
240 }
241 #endif
242
243 #endif // !PLATFORM(MAC)
244
245 GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle, GraphicsContext3D* sharedContext)
246     : m_attrs(attrs)
247     , m_private(std::make_unique<GraphicsContext3DPrivate>(this))
248 {
249 #if PLATFORM(IOS)
250     if (m_attrs.isWebGL2)
251         m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, SH_WEBGL2_SPEC);
252     else
253         m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT);
254 #else
255     if (m_attrs.isWebGL2)
256         m_compiler = ANGLEWebKitBridge(SH_GLSL_410_CORE_OUTPUT, SH_WEBGL2_SPEC);
257 #endif
258
259 #if USE(OPENGL_ES)
260     UNUSED_PARAM(hostWindow);
261     EAGLRenderingAPI api = m_attrs.isWebGL2 ? kEAGLRenderingAPIOpenGLES3 : kEAGLRenderingAPIOpenGLES2;
262     if (!sharedContext)
263         m_contextObj = [[EAGLContext alloc] initWithAPI:api];
264     else
265         m_contextObj = [[EAGLContext alloc] initWithAPI:api sharegroup:sharedContext->m_contextObj.sharegroup];
266     makeContextCurrent();
267 #else
268     Vector<CGLPixelFormatAttribute> attribs;
269     CGLPixelFormatObj pixelFormatObj = 0;
270     GLint numPixelFormats = 0;
271     
272     // If we're configured to demand the software renderer, we'll
273     // do so. We attempt to create contexts in this order:
274     //
275     // 1) 32 bit RGBA/32 bit depth/supersampled
276     // 2) 32 bit RGBA/32 bit depth
277     // 3) 32 bit RGBA/16 bit depth
278     //
279     // If we were not forced into software mode already, our final attempt is
280     // to try that:
281     //
282     // 4) closest to 32 bit RGBA/16 bit depth/software renderer
283     //
284     // If none of that works, we simply fail and set m_contextObj to 0.
285
286     bool useMultisampling = m_attrs.antialias;
287
288 #if HAVE(APPLE_GRAPHICS_CONTROL)
289     m_powerPreferenceUsedForCreation = (hasMuxableGPU() && attrs.powerPreference == GraphicsContext3DPowerPreference::HighPerformance) ? GraphicsContext3DPowerPreference::HighPerformance : GraphicsContext3DPowerPreference::Default;
290 #else
291     m_powerPreferenceUsedForCreation = GraphicsContext3DPowerPreference::Default;
292 #endif
293
294     setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, true, false, useMultisampling, attrs.isWebGL2, allowOfflineRenderers());
295     CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
296
297     if (!numPixelFormats) {
298         setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.isWebGL2, allowOfflineRenderers());
299         CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
300
301         if (!numPixelFormats) {
302             setPixelFormat(attribs, 32, 16, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.isWebGL2, allowOfflineRenderers());
303             CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
304
305             if (!attrs.forceSoftwareRenderer && !numPixelFormats) {
306                 setPixelFormat(attribs, 32, 16, false, false, true, false, attrs.isWebGL2, allowOfflineRenderers());
307                 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
308                 useMultisampling = false;
309             }
310         }
311     }
312
313     if (!numPixelFormats)
314         return;
315
316     CGLError err = CGLCreateContext(pixelFormatObj, sharedContext ? sharedContext->m_contextObj : nullptr, &m_contextObj);
317     GLint abortOnBlacklist = 0;
318     CGLSetParameter(m_contextObj, kCGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
319     
320 #if PLATFORM(MAC)
321
322 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
323     auto gpuID = (hostWindow && hostWindow->displayID()) ? gpuIDForDisplay(hostWindow->displayID()) : primaryGPUID();
324     setGPUByRegistryID(m_contextObj, pixelFormatObj, gpuID);
325 #else
326     if (auto displayMask = primaryOpenGLDisplayMask()) {
327         if (hostWindow && hostWindow->displayID())
328             displayMask = displayMaskForDisplay(hostWindow->displayID());
329         setGPUByDisplayMask(m_contextObj, pixelFormatObj, displayMask);
330     }
331 #endif
332
333 #else
334     UNUSED_PARAM(hostWindow);
335 #endif // !PLATFORM(MAC)
336
337     CGLDestroyPixelFormat(pixelFormatObj);
338     
339     if (err != kCGLNoError || !m_contextObj) {
340         // We were unable to create the context.
341         m_contextObj = 0;
342         return;
343     }
344
345     m_isForWebGL2 = attrs.isWebGL2;
346
347     // Set the current context to the one given to us.
348     CGLSetCurrentContext(m_contextObj);
349
350 #endif // !USE(OPENGL_ES)
351     
352     validateAttributes();
353
354     // Create the WebGLLayer
355     BEGIN_BLOCK_OBJC_EXCEPTIONS
356         m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
357 #ifndef NDEBUG
358         [m_webGLLayer setName:@"WebGL Layer"];
359 #endif
360     END_BLOCK_OBJC_EXCEPTIONS
361
362 #if USE(OPENGL)
363     if (useMultisampling)
364         ::glEnable(GL_MULTISAMPLE);
365 #endif
366
367     // Create the texture that will be used for the framebuffer.
368 #if USE(OPENGL_ES)
369     ::glGenRenderbuffers(1, &m_texture);
370 #else
371     ::glGenTextures(1, &m_texture);
372     // We bind to GL_TEXTURE_RECTANGLE_EXT rather than TEXTURE_2D because
373     // that's what is required for a texture backed by IOSurface.
374     ::glBindTexture(GL_TEXTURE_RECTANGLE_EXT, m_texture);
375     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
376     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
377     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
378     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
379     ::glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
380 #endif
381
382     // Create the framebuffer object.
383     ::glGenFramebuffersEXT(1, &m_fbo);
384     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
385
386     m_state.boundFBO = m_fbo;
387     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
388         ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
389
390     // If necessary, create another framebuffer for the multisample results.
391     if (m_attrs.antialias) {
392         ::glGenFramebuffersEXT(1, &m_multisampleFBO);
393         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
394         m_state.boundFBO = m_multisampleFBO;
395         ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
396         if (m_attrs.stencil || m_attrs.depth)
397             ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
398     }
399     
400     // ANGLE initialization.
401
402     ShBuiltInResources ANGLEResources;
403     sh::InitBuiltInResources(&ANGLEResources);
404
405     getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
406     getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
407     getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
408     getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
409     getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
410     getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
411     getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
412
413     // Always set to 1 for OpenGL ES.
414     ANGLEResources.MaxDrawBuffers = 1;
415     
416     GC3Dint range[2], precision;
417     getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision);
418     ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
419
420     m_compiler.setResources(ANGLEResources);
421     
422 #if USE(OPENGL)
423     ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
424     if (!isGLES2Compliant())
425         ::glEnable(GL_POINT_SPRITE);
426 #endif
427
428     ::glClearColor(0, 0, 0, 0);
429
430     LOG(WebGL, "Created a GraphicsContext3D (%p).", this);
431 }
432
433 GraphicsContext3D::~GraphicsContext3D()
434 {
435     GraphicsContext3DManager::sharedManager().removeContext(this);
436
437     if (m_contextObj) {
438 #if USE(OPENGL_ES)
439         makeContextCurrent();
440         [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
441         ::glDeleteRenderbuffers(1, &m_texture);
442 #else
443         CGLSetCurrentContext(m_contextObj);
444         ::glDeleteTextures(1, &m_texture);
445 #endif
446         if (m_attrs.antialias) {
447             ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
448             if (m_attrs.stencil || m_attrs.depth)
449                 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
450             ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
451         } else {
452             if (m_attrs.stencil || m_attrs.depth)
453                 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
454         }
455         ::glDeleteFramebuffersEXT(1, &m_fbo);
456 #if USE(OPENGL_ES)
457         [EAGLContext setCurrentContext:0];
458         [static_cast<EAGLContext*>(m_contextObj) release];
459 #else
460         CGLSetCurrentContext(0);
461         CGLDestroyContext(m_contextObj);
462 #endif
463         [m_webGLLayer setContext:nullptr];
464     }
465
466     LOG(WebGL, "Destroyed a GraphicsContext3D (%p).", this);
467 }
468
469 #if USE(OPENGL_ES)
470 void GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height)
471 {
472     // We need to make a call to setBounds below to update the backing store size but we also
473     // do not want to clobber the bounds set during layout.
474     CGRect previousBounds = [m_webGLLayer.get() bounds];
475
476     [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)];
477     [m_webGLLayer setOpaque:!m_attrs.alpha];
478
479     [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<id<EAGLDrawable>>(m_webGLLayer.get())];
480
481     [m_webGLLayer setBounds:previousBounds];
482 }
483 #endif
484
485 bool GraphicsContext3D::makeContextCurrent()
486 {
487     if (!m_contextObj)
488         return false;
489
490 #if USE(OPENGL_ES)
491     if ([EAGLContext currentContext] != m_contextObj)
492         return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)];
493 #else
494     CGLContextObj currentContext = CGLGetCurrentContext();
495     if (currentContext != m_contextObj)
496         return CGLSetCurrentContext(m_contextObj) == kCGLNoError;
497 #endif
498     return true;
499 }
500
501 void GraphicsContext3D::checkGPUStatus()
502 {
503     if (m_failNextStatusCheck) {
504         LOG(WebGL, "Pretending the GPU has reset (%p). Lose the context.", this);
505         m_failNextStatusCheck = false;
506         forceContextLost();
507 #if USE(OPENGL)
508         CGLSetCurrentContext(0);
509 #else
510         [EAGLContext setCurrentContext:0];
511 #endif
512         return;
513     }
514
515     // Only do the check every statusCheckThreshold calls.
516     if (m_statusCheckCount)
517         return;
518
519     m_statusCheckCount = (m_statusCheckCount + 1) % statusCheckThreshold;
520
521     GLint restartStatus = 0;
522 #if USE(OPENGL)
523     CGLGetParameter(platformGraphicsContext3D(), kCGLCPGPURestartStatus, &restartStatus);
524     if (restartStatus == kCGLCPGPURestartStatusBlacklisted) {
525         LOG(WebGL, "The GPU has blacklisted us (%p). Terminating.", this);
526         exit(EX_OSERR);
527     }
528     if (restartStatus == kCGLCPGPURestartStatusCaused) {
529         LOG(WebGL, "The GPU has reset us (%p). Lose the context.", this);
530         forceContextLost();
531         CGLSetCurrentContext(0);
532     }
533 #else
534     EAGLContext* currentContext = static_cast<EAGLContext*>(PlatformGraphicsContext3D());
535     [currentContext getParameter:kEAGLCPGPURestartStatus to:&restartStatus];
536     if (restartStatus == kEAGLCPGPURestartStatusCaused || restartStatus == kEAGLCPGPURestartStatusBlacklisted) {
537         LOG(WebGL, "The GPU has either reset or blacklisted us (%p). Lose the context.", this);
538         forceContextLost();
539         [EAGLContext setCurrentContext:0];
540     }
541 #endif
542 }
543
544 #if USE(OPENGL_ES)
545 void GraphicsContext3D::presentRenderbuffer()
546 {
547     makeContextCurrent();
548     if (m_attrs.antialias)
549         resolveMultisamplingIfNecessary();
550
551     ::glFlush();
552     ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
553     [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER];
554     [EAGLContext setCurrentContext:nil];
555 }
556 #endif
557
558 bool GraphicsContext3D::texImageIOSurface2D(GC3Denum target, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, IOSurfaceRef surface, GC3Duint plane)
559 {
560 #if USE(OPENGL)
561     return kCGLNoError == CGLTexImageIOSurface2D(platformGraphicsContext3D(), target, internalFormat, width, height, format, type, surface, plane);
562 #elif USE(OPENGL_ES) && !PLATFORM(IOS_SIMULATOR)
563     return [platformGraphicsContext3D() texImageIOSurface:surface target:target internalFormat:internalFormat width:width height:height format:format type:type plane:plane];
564 #else
565     UNUSED_PARAM(target);
566     UNUSED_PARAM(internalFormat);
567     UNUSED_PARAM(width);
568     UNUSED_PARAM(height);
569     UNUSED_PARAM(format);
570     UNUSED_PARAM(type);
571     UNUSED_PARAM(surface);
572     UNUSED_PARAM(plane);
573     return false;
574 #endif
575 }
576
577 #if USE(OPENGL)
578 void GraphicsContext3D::allocateIOSurfaceBackingStore(IntSize size)
579 {
580     LOG(WebGL, "GraphicsContext3D::allocateIOSurfaceBackingStore at %d x %d. (%p)", size.width(), size.height(), this);
581     [m_webGLLayer allocateIOSurfaceBackingStoreWithSize:size usingAlpha:m_attrs.alpha];
582 }
583
584 void GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer()
585 {
586     LOG(WebGL, "GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer(). (%p)", this);
587     [m_webGLLayer bindFramebufferToNextAvailableSurface];
588 }
589
590 void GraphicsContext3D::updateCGLContext()
591 {
592     if (!m_contextObj)
593         return;
594
595     LOG(WebGL, "Detected a mux switch or display reconfiguration. Call CGLUpdateContext. (%p)", this);
596
597     makeContextCurrent();
598     CGLUpdateContext(m_contextObj);
599 }
600
601 void GraphicsContext3D::setContextVisibility(bool isVisible)
602 {
603     if (m_powerPreferenceUsedForCreation == GraphicsContext3DPowerPreference::HighPerformance) {
604         if (isVisible)
605             GraphicsContext3DManager::sharedManager().addContextRequiringHighPerformance(this);
606         else
607             GraphicsContext3DManager::sharedManager().removeContextRequiringHighPerformance(this);
608     }
609 }
610 #endif
611
612 bool GraphicsContext3D::isGLES2Compliant() const
613 {
614     return m_isForWebGL2;
615 }
616
617 void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
618 {
619 }
620
621 void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
622 {
623 }
624
625 void GraphicsContext3D::simulateContextChanged()
626 {
627     GraphicsContext3DManager::sharedManager().updateAllContexts();
628 }
629
630 bool GraphicsContext3D::allowOfflineRenderers() const
631 {
632 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
633     // When WindowServer access is blocked in the WebProcess, there is no way
634     // for OpenGL to decide which GPU is connected to a display (online/offline).
635     // OpenGL will then consider all GPUs, or renderers, as offline, which means
636     // all offline renderers need to be considered when finding a pixel format.
637     // In WebKit legacy, there will still be a WindowServer connection, and
638     // m_displayMask will not be set in this case.
639     if (primaryOpenGLDisplayMask())
640         return true;
641 #endif
642         
643 #if HAVE(APPLE_GRAPHICS_CONTROL)
644     if (hasMuxableGPU())
645         return true;
646 #endif
647     
648     return false;
649 }
650
651 #if PLATFORM(MAC)
652 void GraphicsContext3D::screenDidChange(PlatformDisplayID displayID)
653 {
654     if (!m_contextObj)
655         return;
656 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
657     setGPUByRegistryID(m_contextObj, CGLGetPixelFormat(m_contextObj), gpuIDForDisplay(displayID));
658 #else
659     setGPUByDisplayMask(m_contextObj, CGLGetPixelFormat(m_contextObj), displayMaskForDisplay(displayID));
660 #endif
661 }
662 #endif // !PLATFORM(MAC)
663
664 }
665
666 #endif // ENABLE(GRAPHICS_CONTEXT_3D)