7f61ef6f23cd7b4fd63e84ea050343a43770c037
[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_FAMILY) && !USE(ANGLE)
32 #import "GraphicsContext3DIOS.h"
33 #endif
34
35 #import "CanvasRenderingContext.h"
36 #import "GraphicsContext.h"
37 #import "GraphicsContext3DManager.h"
38 #import "HTMLCanvasElement.h"
39 #import "HostWindow.h"
40 #import "ImageBuffer.h"
41 #import "Logging.h"
42 #import "WebGLLayer.h"
43 #import "WebGLObject.h"
44 #import "WebGLRenderingContextBase.h"
45 #import <CoreGraphics/CGBitmapContext.h>
46 #import <sys/sysctl.h>
47 #import <sysexits.h>
48 #import <wtf/BlockObjCExceptions.h>
49 #import <wtf/text/CString.h>
50
51 #if USE(OPENGL_ES)
52 #import <OpenGLES/EAGL.h>
53 #import <OpenGLES/EAGLDrawable.h>
54 #import <OpenGLES/EAGLIOSurface.h>
55 #import <OpenGLES/ES2/glext.h>
56 #import <QuartzCore/QuartzCore.h>
57 #import <pal/spi/ios/OpenGLESSPI.h>
58 #elif USE(OPENGL)
59 #import <IOKit/IOKitLib.h>
60 #import <OpenGL/CGLRenderers.h>
61 #import <OpenGL/gl.h>
62 #elif USE(ANGLE)
63 #define EGL_EGL_PROTOTYPES 0
64 // Skip the inclusion of ANGLE's explicit context entry points for now.
65 #define GL_ANGLE_explicit_context
66 #define GL_ANGLE_explicit_context_gles1
67 typedef void* GLeglContext;
68 #include <ANGLE/egl.h>
69 #include <ANGLE/eglext.h>
70 #include <ANGLE/eglext_angle.h>
71 #include <ANGLE/entry_points_egl.h>
72 #include <ANGLE/entry_points_gles_2_0_autogen.h>
73 #include <ANGLE/entry_points_gles_ext_autogen.h>
74 #include <ANGLE/gl2ext.h>
75 #include <ANGLE/gl2ext_angle.h>
76 #endif
77
78 #if USE(OPENGL_ES) || USE(OPENGL)
79 #include "Extensions3DOpenGL.h"
80 #elif USE(ANGLE)
81 #include "Extensions3DANGLE.h"
82 #endif
83
84 #if PLATFORM(MAC)
85 #import "ScreenProperties.h"
86 #endif
87
88 namespace WebCore {
89
90 static const unsigned statusCheckThreshold = 5;
91
92 // FIXME: This class is currently empty on Mac, but will get populated as
93 // the restructuring in https://bugs.webkit.org/show_bug.cgi?id=66903 is done
94 class GraphicsContext3DPrivate {
95     WTF_MAKE_FAST_ALLOCATED;
96 public:
97     GraphicsContext3DPrivate(GraphicsContext3D*) { }
98     
99     ~GraphicsContext3DPrivate() { }
100 };
101
102 RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
103 {
104     // This implementation doesn't currently support rendering directly to the HostWindow.
105     if (renderStyle == RenderDirectlyToHostWindow)
106         return nullptr;
107
108     // Make space for the incoming context if we're full.
109     GraphicsContext3DManager::sharedManager().recycleContextIfNecessary();
110     if (GraphicsContext3DManager::sharedManager().hasTooManyContexts())
111         return nullptr;
112
113     RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle));
114
115     if (!context->m_contextObj)
116         return nullptr;
117
118     GraphicsContext3DManager::sharedManager().addContext(context.get(), hostWindow);
119
120     return context;
121 }
122
123 Ref<GraphicsContext3D> GraphicsContext3D::createShared(GraphicsContext3D& sharedContext)
124 {
125     auto hostWindow = GraphicsContext3DManager::sharedManager().hostWindowForContext(&sharedContext);
126     auto context = adoptRef(*new GraphicsContext3D(sharedContext.getContextAttributes(), hostWindow, sharedContext.m_renderStyle, &sharedContext));
127
128     GraphicsContext3DManager::sharedManager().addContext(context.ptr(), hostWindow);
129
130     return context;
131 }
132
133 #if PLATFORM(MAC) && USE(OPENGL) // FIXME: This probably should be just USE(OPENGL) - see <rdar://53062794>.
134
135 static void setGPUByRegistryID(PlatformGraphicsContext3D contextObj, CGLPixelFormatObj pixelFormatObj, IORegistryGPUID preferredGPUID)
136 {
137     // 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.
138     // On 10.13+, find the virtual screen that corresponds to the preferred GPU by its registryID.
139     // CGLSetVirtualScreen can then be used to tell OpenGL which GPU it should be using.
140
141     if (!contextObj || !preferredGPUID)
142         return;
143
144     GLint virtualScreenCount = 0;
145     CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount, &virtualScreenCount);
146     ASSERT(error == kCGLNoError);
147
148     GLint firstAcceleratedScreen = -1;
149
150     for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen) {
151         GLint displayMask = 0;
152         error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFADisplayMask, &displayMask);
153         ASSERT(error == kCGLNoError);
154
155         auto gpuID = gpuIDForDisplayMask(displayMask);
156
157         if (gpuID == preferredGPUID) {
158             error = CGLSetVirtualScreen(contextObj, virtualScreen);
159             ASSERT(error == kCGLNoError);
160             LOG(WebGL, "Context (%p) set to GPU with ID: (%lld).", contextObj, gpuID);
161             return;
162         }
163
164         if (firstAcceleratedScreen < 0) {
165             GLint isAccelerated = 0;
166             error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFAAccelerated, &isAccelerated);
167             ASSERT(error == kCGLNoError);
168             if (isAccelerated)
169                 firstAcceleratedScreen = virtualScreen;
170         }
171     }
172
173     // No registryID match found; set to first hardware-accelerated virtual screen.
174     if (firstAcceleratedScreen >= 0) {
175         error = CGLSetVirtualScreen(contextObj, firstAcceleratedScreen);
176         ASSERT(error == kCGLNoError);
177         LOG(WebGL, "RegistryID (%lld) not matched; Context (%p) set to virtual screen (%d).", preferredGPUID, contextObj, firstAcceleratedScreen);
178     }
179 }
180
181 #endif // PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
182
183 GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle, GraphicsContext3D* sharedContext)
184     : m_attrs(attrs)
185     , m_private(makeUnique<GraphicsContext3DPrivate>(this))
186 {
187
188 #if HAVE(APPLE_GRAPHICS_CONTROL)
189     m_powerPreferenceUsedForCreation = (hasLowAndHighPowerGPUs() && attrs.powerPreference == GraphicsContext3DPowerPreference::HighPerformance) ? GraphicsContext3DPowerPreference::HighPerformance : GraphicsContext3DPowerPreference::Default;
190 #else
191     m_powerPreferenceUsedForCreation = GraphicsContext3DPowerPreference::Default;
192 #endif
193
194 #if !USE(ANGLE)
195 #if USE(OPENGL_ES)
196     if (m_attrs.isWebGL2)
197         m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, SH_WEBGL2_SPEC);
198     else
199         m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT);
200 #else
201     if (m_attrs.isWebGL2)
202         m_compiler = ANGLEWebKitBridge(SH_GLSL_410_CORE_OUTPUT, SH_WEBGL2_SPEC);
203 #endif // USE(OPENGL_ES)
204 #endif // !USE(ANGLE)
205
206 #if USE(OPENGL_ES)
207     UNUSED_PARAM(hostWindow);
208     EAGLRenderingAPI api = m_attrs.isWebGL2 ? kEAGLRenderingAPIOpenGLES3 : kEAGLRenderingAPIOpenGLES2;
209     if (!sharedContext)
210         m_contextObj = [[EAGLContext alloc] initWithAPI:api];
211     else
212         m_contextObj = [[EAGLContext alloc] initWithAPI:api sharegroup:sharedContext->m_contextObj.sharegroup];
213     makeContextCurrent();
214
215     if (m_attrs.isWebGL2)
216         ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART_FIXED_INDEX);
217 #elif USE(OPENGL)
218
219     bool useMultisampling = m_attrs.antialias;
220
221     Vector<CGLPixelFormatAttribute> attribs;
222     CGLPixelFormatObj pixelFormatObj = 0;
223     GLint numPixelFormats = 0;
224
225     attribs.append(kCGLPFAAccelerated);
226     attribs.append(kCGLPFAColorSize);
227     attribs.append(static_cast<CGLPixelFormatAttribute>(32));
228     attribs.append(kCGLPFADepthSize);
229     attribs.append(static_cast<CGLPixelFormatAttribute>(32));
230
231     // This attribute, while mentioning offline renderers, is actually
232     // allowing us to request the integrated graphics on a dual GPU
233     // system, and not force the discrete GPU.
234     // See https://developer.apple.com/library/mac/technotes/tn2229/_index.html
235     if (allowOfflineRenderers())
236         attribs.append(kCGLPFAAllowOfflineRenderers);
237
238     if (useMultisampling) {
239         attribs.append(kCGLPFAMultisample);
240         attribs.append(kCGLPFASampleBuffers);
241         attribs.append(static_cast<CGLPixelFormatAttribute>(1));
242         attribs.append(kCGLPFASamples);
243         attribs.append(static_cast<CGLPixelFormatAttribute>(4));
244     }
245
246     if (attrs.isWebGL2) {
247         // FIXME: Instead of backing a WebGL2 GraphicsContext3D with a OpenGL 4 context, we should instead back it with ANGLE.
248         // Use an OpenGL 4 context for now until the ANGLE backend is ready.
249         attribs.append(kCGLPFAOpenGLProfile);
250         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_GL4_Core));
251     }
252
253     attribs.append(static_cast<CGLPixelFormatAttribute>(0));
254
255     CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
256
257     if (!numPixelFormats)
258         return;
259
260     CGLError err = CGLCreateContext(pixelFormatObj, sharedContext ? sharedContext->m_contextObj : nullptr, &m_contextObj);
261     GLint abortOnBlacklist = 0;
262     CGLSetParameter(m_contextObj, kCGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
263     
264 #if PLATFORM(MAC) // FIXME: This probably should be USE(OPENGL) - see <rdar://53062794>.
265
266     auto gpuID = (hostWindow && hostWindow->displayID()) ? gpuIDForDisplay(hostWindow->displayID()) : primaryGPUID();
267     setGPUByRegistryID(m_contextObj, pixelFormatObj, gpuID);
268
269 #else
270     UNUSED_PARAM(hostWindow);
271 #endif
272
273     CGLDestroyPixelFormat(pixelFormatObj);
274     
275     if (err != kCGLNoError || !m_contextObj) {
276         // We were unable to create the context.
277         m_contextObj = 0;
278         return;
279     }
280
281     m_isForWebGL2 = attrs.isWebGL2;
282
283     CGLSetCurrentContext(m_contextObj);
284
285     // WebGL 2 expects ES 3-only PRIMITIVE_RESTART_FIXED_INDEX to be enabled; we must emulate this on non-ES 3 systems.
286     if (m_isForWebGL2)
287         ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART);
288
289 #elif USE(ANGLE)
290     UNUSED_PARAM(hostWindow);
291     UNUSED_PARAM(sharedContext);
292
293     m_displayObj = EGL_GetDisplay(EGL_DEFAULT_DISPLAY);
294     if (m_displayObj == EGL_NO_DISPLAY)
295         return;
296     EGLint majorVersion, minorVersion;
297     if (EGL_Initialize(m_displayObj, &majorVersion, &minorVersion) == EGL_FALSE) {
298         LOG(WebGL, "EGLDisplay Initialization failed.");
299         return;
300     }
301     LOG(WebGL, "ANGLE initialised Major: %d Minor: %d", majorVersion, minorVersion);
302     const char *displayExtensions = EGL_QueryString(m_displayObj, EGL_EXTENSIONS);
303     LOG(WebGL, "Extensions: %s", displayExtensions);
304
305     EGLConfig config;
306     EGLint configAttributes[] = {
307         EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
308         EGL_RED_SIZE, 8,
309         EGL_GREEN_SIZE, 8,
310         EGL_BLUE_SIZE, 8,
311         EGL_ALPHA_SIZE, 8,
312         EGL_NONE
313     };
314     EGLint numberConfigsReturned = 0;
315     EGL_ChooseConfig(m_displayObj, configAttributes, &config, 1, &numberConfigsReturned);
316     if (numberConfigsReturned != 1) {
317         LOG(WebGL, "EGLConfig Initialization failed.");
318         return;
319     }
320     LOG(WebGL, "Got EGLConfig");
321
322     EGL_BindAPI(EGL_OPENGL_ES_API);
323     if (EGL_GetError() != EGL_SUCCESS) {
324         LOG(WebGL, "Unable to bind to OPENGL_ES_API");
325         return;
326     }
327
328     std::vector<EGLint> contextAttributes;
329     if (attrs.isWebGL2) {
330         contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
331         contextAttributes.push_back(3);
332     } else {
333         contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
334         contextAttributes.push_back(2);
335         // ANGLE will upgrade the context to ES3 automatically unless this is specified.
336         contextAttributes.push_back(EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE);
337         contextAttributes.push_back(EGL_FALSE);
338     }
339     contextAttributes.push_back(EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE);
340     contextAttributes.push_back(EGL_TRUE);
341     if (strstr(displayExtensions, "EGL_ANGLE_power_preference")) {
342         contextAttributes.push_back(EGL_POWER_PREFERENCE_ANGLE);
343         // EGL_LOW_POWER_ANGLE is the default. Change to
344         // EGL_HIGH_POWER_ANGLE if desired.
345         contextAttributes.push_back(EGL_LOW_POWER_ANGLE);
346     }
347     contextAttributes.push_back(EGL_NONE);
348
349     m_contextObj = EGL_CreateContext(m_displayObj, config, EGL_NO_CONTEXT, contextAttributes.data());
350     if (m_contextObj == EGL_NO_CONTEXT) {
351         LOG(WebGL, "EGLContext Initialization failed.");
352         return;
353     }
354     LOG(WebGL, "Got EGLContext");
355
356     EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
357
358     static constexpr const char* requiredExtensions[] = {
359         "GL_ANGLE_texture_rectangle", // For IOSurface-backed textures
360         "GL_EXT_texture_format_BGRA8888", // For creating the EGL surface from an IOSurface
361     };
362
363     static constexpr const char* optionalExtensions[] = {
364         "GL_EXT_debug_marker",
365     };
366
367     Extensions3D& extensions = getExtensions();
368
369     for (size_t i = 0; i < WTF_ARRAY_LENGTH(requiredExtensions); ++i) {
370         if (!extensions.supports(requiredExtensions[i])) {
371             LOG(WebGL, "Missing required extension.");
372             return;
373         }
374
375         extensions.ensureEnabled(requiredExtensions[i]);
376     }
377
378     for (size_t i = 0; i < WTF_ARRAY_LENGTH(optionalExtensions); ++i) {
379         if (extensions.supports(optionalExtensions[i]))
380             extensions.ensureEnabled(optionalExtensions[i]);
381     }
382
383 #endif // #elif USE(ANGLE)
384
385     validateAttributes();
386
387     // Create the WebGLLayer
388     BEGIN_BLOCK_OBJC_EXCEPTIONS
389         m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
390 #ifndef NDEBUG
391         [m_webGLLayer setName:@"WebGL Layer"];
392 #endif
393 #if USE(ANGLE)
394         [m_webGLLayer setEGLDisplay:m_displayObj andConfig:config];
395 #endif
396     END_BLOCK_OBJC_EXCEPTIONS
397
398 #if USE(OPENGL)
399     if (useMultisampling)
400         ::glEnable(GL_MULTISAMPLE);
401 #endif
402
403     // Create the texture that will be used for the framebuffer.
404 #if USE(OPENGL_ES)
405     ::glGenRenderbuffers(1, &m_texture);
406 #elif USE(OPENGL)
407     ::glGenTextures(1, &m_texture);
408     // We bind to GL_TEXTURE_RECTANGLE_EXT rather than TEXTURE_2D because
409     // that's what is required for a texture backed by IOSurface.
410     ::glBindTexture(GL_TEXTURE_RECTANGLE_EXT, m_texture);
411     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
412     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
413     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
414     ::glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
415     ::glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 0);
416 #elif USE(ANGLE)
417     gl::GenTextures(1, &m_texture);
418     gl::BindTexture(GL_TEXTURE_RECTANGLE_ANGLE, m_texture);
419     gl::TexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
420     gl::TexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
421     gl::TexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
422     gl::TexParameteri(GL_TEXTURE_RECTANGLE_ANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
423     gl::BindTexture(GL_TEXTURE_RECTANGLE_ANGLE, 0);
424 #else
425 #error Unsupported configuration
426 #endif
427
428 #if USE(OPENGL) || USE(OPENGL_ES)
429     // Create the framebuffer object.
430     ::glGenFramebuffersEXT(1, &m_fbo);
431     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
432
433     m_state.boundFBO = m_fbo;
434     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
435         ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
436
437     // If necessary, create another framebuffer for the multisample results.
438     if (m_attrs.antialias) {
439         ::glGenFramebuffersEXT(1, &m_multisampleFBO);
440         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
441         m_state.boundFBO = m_multisampleFBO;
442         ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
443         if (m_attrs.stencil || m_attrs.depth)
444             ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
445     }
446 #elif USE(ANGLE)
447     gl::GenFramebuffers(1, &m_fbo);
448     gl::BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
449     m_state.boundFBO = m_fbo;
450
451     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
452         gl::GenRenderbuffers(1, &m_depthStencilBuffer);
453
454     // If necessary, create another framebuffer for the multisample results.
455     if (m_attrs.antialias) {
456         gl::GenFramebuffers(1, &m_multisampleFBO);
457         gl::BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
458         m_state.boundFBO = m_multisampleFBO;
459         gl::GenRenderbuffers(1, &m_multisampleColorBuffer);
460         if (m_attrs.stencil || m_attrs.depth)
461             gl::GenRenderbuffers(1, &m_multisampleDepthStencilBuffer);
462     }
463
464 #endif // USE(ANGLE)
465
466 #if !USE(ANGLE)
467     // ANGLE shader compiler initialization.
468
469     ShBuiltInResources ANGLEResources;
470     sh::InitBuiltInResources(&ANGLEResources);
471
472     getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
473     getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
474     getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
475     getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
476     getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
477     getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
478     getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
479
480     // Always set to 1 for OpenGL ES.
481     ANGLEResources.MaxDrawBuffers = 1;
482     
483     GC3Dint range[2], precision;
484     getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision);
485     ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
486
487     m_compiler.setResources(ANGLEResources);
488 #endif // !USE(ANGLE)
489     
490 #if USE(OPENGL)
491     ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
492     if (!isGLES2Compliant())
493         ::glEnable(GL_POINT_SPRITE);
494 #endif
495
496 #if USE(OPENGL) || USE(OPENGL_ES)
497     ::glClearColor(0, 0, 0, 0);
498 #elif USE(ANGLE)
499     gl::ClearColor(0, 0, 0, 0);
500 #endif
501
502     LOG(WebGL, "Created a GraphicsContext3D (%p).", this);
503 }
504
505 GraphicsContext3D::~GraphicsContext3D()
506 {
507     GraphicsContext3DManager::sharedManager().removeContext(this);
508
509     if (m_contextObj) {
510 #if USE(OPENGL_ES)
511         makeContextCurrent();
512         [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
513         ::glDeleteRenderbuffers(1, &m_texture);
514 #elif USE(OPENGL)
515         CGLSetCurrentContext(m_contextObj);
516         ::glDeleteTextures(1, &m_texture);
517 #elif USE(ANGLE)
518         EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
519         gl::DeleteTextures(1, &m_texture);
520 #endif
521
522 #if USE(OPENGL) || USE(OPENGL_ES)
523         if (m_attrs.antialias) {
524             ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
525             if (m_attrs.stencil || m_attrs.depth)
526                 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
527             ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
528         } else {
529             if (m_attrs.stencil || m_attrs.depth)
530                 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
531         }
532         ::glDeleteFramebuffersEXT(1, &m_fbo);
533 #elif USE(ANGLE)
534         if (m_attrs.antialias) {
535             gl::DeleteRenderbuffers(1, &m_multisampleColorBuffer);
536             if (m_attrs.stencil || m_attrs.depth)
537                 gl::DeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer);
538             gl::DeleteFramebuffers(1, &m_multisampleFBO);
539         } else {
540             if (m_attrs.stencil || m_attrs.depth)
541                 gl::DeleteRenderbuffers(1, &m_depthStencilBuffer);
542         }
543         gl::DeleteFramebuffers(1, &m_fbo);
544 #endif
545
546 #if USE(OPENGL_ES)
547         [EAGLContext setCurrentContext:0];
548         [static_cast<EAGLContext*>(m_contextObj) release];
549 #elif USE(OPENGL)
550         CGLSetCurrentContext(0);
551         CGLDestroyContext(m_contextObj);
552 #elif USE(ANGLE)
553         EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
554         EGL_DestroyContext(m_displayObj, m_contextObj);
555 #endif
556         [m_webGLLayer setContext:nullptr];
557     }
558
559     LOG(WebGL, "Destroyed a GraphicsContext3D (%p).", this);
560 }
561
562 #if USE(OPENGL_ES)
563 void GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height)
564 {
565     // We need to make a call to setBounds below to update the backing store size but we also
566     // do not want to clobber the bounds set during layout.
567     CGRect previousBounds = [m_webGLLayer.get() bounds];
568
569     [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)];
570     [m_webGLLayer setOpaque:!m_attrs.alpha];
571
572     [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<id<EAGLDrawable>>(m_webGLLayer.get())];
573
574     [m_webGLLayer setBounds:previousBounds];
575 }
576 #endif
577
578 bool GraphicsContext3D::makeContextCurrent()
579 {
580     if (!m_contextObj)
581         return false;
582
583 #if USE(OPENGL_ES)
584     if ([EAGLContext currentContext] != m_contextObj)
585         return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)];
586 #elif USE(OPENGL)
587     CGLContextObj currentContext = CGLGetCurrentContext();
588     if (currentContext != m_contextObj)
589         return CGLSetCurrentContext(m_contextObj) == kCGLNoError;
590 #elif USE(ANGLE)
591     if (EGL_GetCurrentContext() != m_contextObj)
592         return EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
593 #endif
594     return true;
595 }
596
597 void GraphicsContext3D::checkGPUStatus()
598 {
599     if (m_failNextStatusCheck) {
600         LOG(WebGL, "Pretending the GPU has reset (%p). Lose the context.", this);
601         m_failNextStatusCheck = false;
602         forceContextLost();
603 #if USE(OPENGL)
604         CGLSetCurrentContext(0);
605 #elif USE(OPENGL_ES)
606         [EAGLContext setCurrentContext:0];
607 #elif USE(ANGLE)
608         EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
609 #endif
610         return;
611     }
612
613     // Only do the check every statusCheckThreshold calls.
614     if (m_statusCheckCount)
615         return;
616
617     m_statusCheckCount = (m_statusCheckCount + 1) % statusCheckThreshold;
618
619     GLint restartStatus = 0;
620 #if USE(OPENGL)
621     CGLGetParameter(platformGraphicsContext3D(), kCGLCPGPURestartStatus, &restartStatus);
622     if (restartStatus == kCGLCPGPURestartStatusBlacklisted) {
623         LOG(WebGL, "The GPU has blacklisted us (%p). Terminating.", this);
624         exit(EX_OSERR);
625     }
626     if (restartStatus == kCGLCPGPURestartStatusCaused) {
627         LOG(WebGL, "The GPU has reset us (%p). Lose the context.", this);
628         forceContextLost();
629         CGLSetCurrentContext(0);
630     }
631 #elif USE(OPENGL_ES)
632     EAGLContext* currentContext = static_cast<EAGLContext*>(PlatformGraphicsContext3D());
633     [currentContext getParameter:kEAGLCPGPURestartStatus to:&restartStatus];
634     if (restartStatus == kEAGLCPGPURestartStatusCaused || restartStatus == kEAGLCPGPURestartStatusBlacklisted) {
635         LOG(WebGL, "The GPU has either reset or blacklisted us (%p). Lose the context.", this);
636         forceContextLost();
637         [EAGLContext setCurrentContext:0];
638     }
639 #elif USE(ANGLE)
640     // FIXME: check via KHR_robustness.
641     restartStatus = 0;
642 #endif
643 }
644
645 #if USE(OPENGL_ES)
646 void GraphicsContext3D::presentRenderbuffer()
647 {
648     makeContextCurrent();
649     if (m_attrs.antialias)
650         resolveMultisamplingIfNecessary();
651
652     ::glFlush();
653     ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
654     [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER];
655     [EAGLContext setCurrentContext:nil];
656 }
657 #endif
658
659 bool GraphicsContext3D::texImageIOSurface2D(GC3Denum target, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, IOSurfaceRef surface, GC3Duint plane)
660 {
661 #if USE(OPENGL)
662     return kCGLNoError == CGLTexImageIOSurface2D(platformGraphicsContext3D(), target, internalFormat, width, height, format, type, surface, plane);
663 #elif USE(OPENGL_ES) && !PLATFORM(IOS_FAMILY_SIMULATOR)
664     return [platformGraphicsContext3D() texImageIOSurface:surface target:target internalFormat:internalFormat width:width height:height format:format type:type plane:plane];
665 #else
666     UNUSED_PARAM(target);
667     UNUSED_PARAM(internalFormat);
668     UNUSED_PARAM(width);
669     UNUSED_PARAM(height);
670     UNUSED_PARAM(format);
671     UNUSED_PARAM(type);
672     UNUSED_PARAM(surface);
673     UNUSED_PARAM(plane);
674     return false;
675 #endif
676 }
677
678 #if USE(OPENGL)
679 void GraphicsContext3D::allocateIOSurfaceBackingStore(IntSize size)
680 {
681     LOG(WebGL, "GraphicsContext3D::allocateIOSurfaceBackingStore at %d x %d. (%p)", size.width(), size.height(), this);
682     [m_webGLLayer allocateIOSurfaceBackingStoreWithSize:size usingAlpha:m_attrs.alpha];
683 }
684
685 void GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer()
686 {
687     LOG(WebGL, "GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer(). (%p)", this);
688     [m_webGLLayer bindFramebufferToNextAvailableSurface];
689 }
690
691 void GraphicsContext3D::updateCGLContext()
692 {
693     if (!m_contextObj)
694         return;
695
696     LOG(WebGL, "Detected a mux switch or display reconfiguration. Call CGLUpdateContext. (%p)", this);
697
698     makeContextCurrent();
699     CGLUpdateContext(m_contextObj);
700     m_hasSwitchedToHighPerformanceGPU = true;
701 }
702
703 #endif // USE(OPENGL)
704
705 #if USE(OPENGL) || USE(ANGLE)
706 void GraphicsContext3D::setContextVisibility(bool isVisible)
707 {
708     if (m_powerPreferenceUsedForCreation == GraphicsContext3DPowerPreference::HighPerformance) {
709         if (isVisible)
710             GraphicsContext3DManager::sharedManager().addContextRequiringHighPerformance(this);
711         else
712             GraphicsContext3DManager::sharedManager().removeContextRequiringHighPerformance(this);
713     }
714 }
715 #endif // USE(OPENGL) || USE(ANGLE)
716
717 #if USE(ANGLE)
718 void GraphicsContext3D::allocateIOSurfaceBackingStore(IntSize size)
719 {
720     LOG(WebGL, "GraphicsContext3D::allocateIOSurfaceBackingStore at %d x %d. (%p)", size.width(), size.height(), this);
721     [m_webGLLayer allocateIOSurfaceBackingStoreWithSize:size usingAlpha:m_attrs.alpha];
722 }
723
724 void GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer()
725 {
726     LOG(WebGL, "GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer(). (%p)", this);
727     [m_webGLLayer bindFramebufferToNextAvailableSurface];
728 }
729 #endif // USE(ANGLE)
730
731 bool GraphicsContext3D::isGLES2Compliant() const
732 {
733     return m_isForWebGL2;
734 }
735
736 void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
737 {
738 }
739
740 void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
741 {
742 }
743
744 void GraphicsContext3D::simulateContextChanged()
745 {
746     GraphicsContext3DManager::sharedManager().updateAllContexts();
747 }
748
749 bool GraphicsContext3D::allowOfflineRenderers() const
750 {
751 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
752     // When WindowServer access is blocked in the WebProcess, there is no way
753     // for OpenGL to decide which GPU is connected to a display (online/offline).
754     // OpenGL will then consider all GPUs, or renderers, as offline, which means
755     // all offline renderers need to be considered when finding a pixel format.
756     // In WebKit legacy, there will still be a WindowServer connection, and
757     // m_displayMask will not be set in this case.
758     if (primaryOpenGLDisplayMask())
759         return true;
760 #elif PLATFORM(MACCATALYST)
761     // FIXME: <rdar://53062794> We're very inconsistent about WEBPROCESS_WINDOWSERVER_BLOCKING
762     // and MAC/MACCATALYST and OPENGL/OPENGLES.
763     return true;
764 #endif
765         
766 #if HAVE(APPLE_GRAPHICS_CONTROL)
767     if (hasLowAndHighPowerGPUs())
768         return true;
769 #endif
770     
771     return false;
772 }
773
774 #if PLATFORM(MAC)
775 void GraphicsContext3D::screenDidChange(PlatformDisplayID displayID)
776 {
777     if (!m_contextObj)
778         return;
779 #if USE(ANGLE)
780     UNUSED_PARAM(displayID);
781 #else
782     // FIXME: figure out whether to integrate more code into ANGLE to have this effect.
783 #if USE(OPENGL)
784     if (!m_hasSwitchedToHighPerformanceGPU)
785         setGPUByRegistryID(m_contextObj, CGLGetPixelFormat(m_contextObj), gpuIDForDisplay(displayID));
786 #endif
787 #endif // USE(ANGLE)
788 }
789 #endif // !PLATFORM(MAC)
790
791 }
792
793 #endif // ENABLE(GRAPHICS_CONTEXT_3D)