2 * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #if ENABLE(GRAPHICS_CONTEXT_3D)
29 #import "GraphicsContext3D.h"
31 #if PLATFORM(IOS_FAMILY) && !USE(ANGLE)
32 #import "GraphicsContext3DIOS.h"
35 #import "CanvasRenderingContext.h"
36 #import "GraphicsContext.h"
37 #import "GraphicsContext3DManager.h"
38 #import "HTMLCanvasElement.h"
39 #import "HostWindow.h"
40 #import "ImageBuffer.h"
42 #import "WebGLLayer.h"
43 #import "WebGLObject.h"
44 #import "WebGLRenderingContextBase.h"
45 #import <CoreGraphics/CGBitmapContext.h>
46 #import <sys/sysctl.h>
48 #import <wtf/BlockObjCExceptions.h>
49 #import <wtf/text/CString.h>
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>
59 #import <IOKit/IOKitLib.h>
60 #import <OpenGL/CGLRenderers.h>
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>
78 #if USE(OPENGL_ES) || USE(OPENGL)
79 #include "Extensions3DOpenGL.h"
81 #include "Extensions3DANGLE.h"
85 #import "ScreenProperties.h"
90 static const unsigned statusCheckThreshold = 5;
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;
97 GraphicsContext3DPrivate(GraphicsContext3D*) { }
99 ~GraphicsContext3DPrivate() { }
102 RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
104 // This implementation doesn't currently support rendering directly to the HostWindow.
105 if (renderStyle == RenderDirectlyToHostWindow)
108 // Make space for the incoming context if we're full.
109 GraphicsContext3DManager::sharedManager().recycleContextIfNecessary();
110 if (GraphicsContext3DManager::sharedManager().hasTooManyContexts())
113 RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle));
115 if (!context->m_contextObj)
118 GraphicsContext3DManager::sharedManager().addContext(context.get(), hostWindow);
123 Ref<GraphicsContext3D> GraphicsContext3D::createShared(GraphicsContext3D& sharedContext)
125 auto hostWindow = GraphicsContext3DManager::sharedManager().hostWindowForContext(&sharedContext);
126 auto context = adoptRef(*new GraphicsContext3D(sharedContext.getContextAttributes(), hostWindow, sharedContext.m_renderStyle, &sharedContext));
128 GraphicsContext3DManager::sharedManager().addContext(context.ptr(), hostWindow);
133 #if PLATFORM(MAC) && USE(OPENGL) // FIXME: This probably should be just USE(OPENGL) - see <rdar://53062794>.
135 static void setGPUByRegistryID(PlatformGraphicsContext3D contextObj, CGLPixelFormatObj pixelFormatObj, IORegistryGPUID preferredGPUID)
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.
141 if (!contextObj || !preferredGPUID)
144 GLint virtualScreenCount = 0;
145 CGLError error = CGLDescribePixelFormat(pixelFormatObj, 0, kCGLPFAVirtualScreenCount, &virtualScreenCount);
146 ASSERT(error == kCGLNoError);
148 GLint firstAcceleratedScreen = -1;
150 for (GLint virtualScreen = 0; virtualScreen < virtualScreenCount; ++virtualScreen) {
151 GLint displayMask = 0;
152 error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFADisplayMask, &displayMask);
153 ASSERT(error == kCGLNoError);
155 auto gpuID = gpuIDForDisplayMask(displayMask);
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);
164 if (firstAcceleratedScreen < 0) {
165 GLint isAccelerated = 0;
166 error = CGLDescribePixelFormat(pixelFormatObj, virtualScreen, kCGLPFAAccelerated, &isAccelerated);
167 ASSERT(error == kCGLNoError);
169 firstAcceleratedScreen = virtualScreen;
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);
181 #endif // PLATFORM(MAC) && (USE(OPENGL) || USE(ANGLE))
183 GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle, GraphicsContext3D* sharedContext)
185 , m_private(makeUnique<GraphicsContext3DPrivate>(this))
188 #if HAVE(APPLE_GRAPHICS_CONTROL)
189 m_powerPreferenceUsedForCreation = (hasLowAndHighPowerGPUs() && attrs.powerPreference == GraphicsContext3DPowerPreference::HighPerformance) ? GraphicsContext3DPowerPreference::HighPerformance : GraphicsContext3DPowerPreference::Default;
191 m_powerPreferenceUsedForCreation = GraphicsContext3DPowerPreference::Default;
196 if (m_attrs.isWebGL2)
197 m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, SH_WEBGL2_SPEC);
199 m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT);
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)
207 UNUSED_PARAM(hostWindow);
208 EAGLRenderingAPI api = m_attrs.isWebGL2 ? kEAGLRenderingAPIOpenGLES3 : kEAGLRenderingAPIOpenGLES2;
210 m_contextObj = [[EAGLContext alloc] initWithAPI:api];
212 m_contextObj = [[EAGLContext alloc] initWithAPI:api sharegroup:sharedContext->m_contextObj.sharegroup];
213 makeContextCurrent();
215 if (m_attrs.isWebGL2)
216 ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART_FIXED_INDEX);
219 bool useMultisampling = m_attrs.antialias;
221 Vector<CGLPixelFormatAttribute> attribs;
222 CGLPixelFormatObj pixelFormatObj = 0;
223 GLint numPixelFormats = 0;
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));
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);
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));
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));
253 attribs.append(static_cast<CGLPixelFormatAttribute>(0));
255 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
257 if (!numPixelFormats)
260 CGLError err = CGLCreateContext(pixelFormatObj, sharedContext ? sharedContext->m_contextObj : nullptr, &m_contextObj);
261 GLint abortOnBlacklist = 0;
262 CGLSetParameter(m_contextObj, kCGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
264 #if PLATFORM(MAC) // FIXME: This probably should be USE(OPENGL) - see <rdar://53062794>.
266 auto gpuID = (hostWindow && hostWindow->displayID()) ? gpuIDForDisplay(hostWindow->displayID()) : primaryGPUID();
267 setGPUByRegistryID(m_contextObj, pixelFormatObj, gpuID);
270 UNUSED_PARAM(hostWindow);
273 CGLDestroyPixelFormat(pixelFormatObj);
275 if (err != kCGLNoError || !m_contextObj) {
276 // We were unable to create the context.
281 m_isForWebGL2 = attrs.isWebGL2;
283 CGLSetCurrentContext(m_contextObj);
285 // WebGL 2 expects ES 3-only PRIMITIVE_RESTART_FIXED_INDEX to be enabled; we must emulate this on non-ES 3 systems.
287 ::glEnable(GraphicsContext3D::PRIMITIVE_RESTART);
290 UNUSED_PARAM(hostWindow);
291 UNUSED_PARAM(sharedContext);
293 m_displayObj = EGL_GetDisplay(EGL_DEFAULT_DISPLAY);
294 if (m_displayObj == EGL_NO_DISPLAY)
296 EGLint majorVersion, minorVersion;
297 if (EGL_Initialize(m_displayObj, &majorVersion, &minorVersion) == EGL_FALSE) {
298 LOG(WebGL, "EGLDisplay Initialization failed.");
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);
306 EGLint configAttributes[] = {
307 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
314 EGLint numberConfigsReturned = 0;
315 EGL_ChooseConfig(m_displayObj, configAttributes, &config, 1, &numberConfigsReturned);
316 if (numberConfigsReturned != 1) {
317 LOG(WebGL, "EGLConfig Initialization failed.");
320 LOG(WebGL, "Got EGLConfig");
322 EGL_BindAPI(EGL_OPENGL_ES_API);
323 if (EGL_GetError() != EGL_SUCCESS) {
324 LOG(WebGL, "Unable to bind to OPENGL_ES_API");
328 std::vector<EGLint> contextAttributes;
329 if (attrs.isWebGL2) {
330 contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
331 contextAttributes.push_back(3);
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);
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);
347 contextAttributes.push_back(EGL_NONE);
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.");
354 LOG(WebGL, "Got EGLContext");
356 EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
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
363 static constexpr const char* optionalExtensions[] = {
364 "GL_EXT_debug_marker",
367 Extensions3D& extensions = getExtensions();
369 for (size_t i = 0; i < WTF_ARRAY_LENGTH(requiredExtensions); ++i) {
370 if (!extensions.supports(requiredExtensions[i])) {
371 LOG(WebGL, "Missing required extension.");
375 extensions.ensureEnabled(requiredExtensions[i]);
378 for (size_t i = 0; i < WTF_ARRAY_LENGTH(optionalExtensions); ++i) {
379 if (extensions.supports(optionalExtensions[i]))
380 extensions.ensureEnabled(optionalExtensions[i]);
383 #endif // #elif USE(ANGLE)
385 validateAttributes();
387 // Create the WebGLLayer
388 BEGIN_BLOCK_OBJC_EXCEPTIONS
389 m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
391 [m_webGLLayer setName:@"WebGL Layer"];
394 [m_webGLLayer setEGLDisplay:m_displayObj andConfig:config];
396 END_BLOCK_OBJC_EXCEPTIONS
399 if (useMultisampling)
400 ::glEnable(GL_MULTISAMPLE);
403 // Create the texture that will be used for the framebuffer.
405 ::glGenRenderbuffers(1, &m_texture);
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);
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);
425 #error Unsupported configuration
428 #if USE(OPENGL) || USE(OPENGL_ES)
429 // Create the framebuffer object.
430 ::glGenFramebuffersEXT(1, &m_fbo);
431 ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
433 m_state.boundFBO = m_fbo;
434 if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
435 ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
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);
447 gl::GenFramebuffers(1, &m_fbo);
448 gl::BindFramebuffer(GL_FRAMEBUFFER, m_fbo);
449 m_state.boundFBO = m_fbo;
451 if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
452 gl::GenRenderbuffers(1, &m_depthStencilBuffer);
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);
467 // ANGLE shader compiler initialization.
469 ShBuiltInResources ANGLEResources;
470 sh::InitBuiltInResources(&ANGLEResources);
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);
480 // Always set to 1 for OpenGL ES.
481 ANGLEResources.MaxDrawBuffers = 1;
483 GC3Dint range[2], precision;
484 getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision);
485 ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
487 m_compiler.setResources(ANGLEResources);
488 #endif // !USE(ANGLE)
491 ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
492 if (!isGLES2Compliant())
493 ::glEnable(GL_POINT_SPRITE);
496 #if USE(OPENGL) || USE(OPENGL_ES)
497 ::glClearColor(0, 0, 0, 0);
499 gl::ClearColor(0, 0, 0, 0);
502 LOG(WebGL, "Created a GraphicsContext3D (%p).", this);
505 GraphicsContext3D::~GraphicsContext3D()
507 GraphicsContext3DManager::sharedManager().removeContext(this);
511 makeContextCurrent();
512 [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
513 ::glDeleteRenderbuffers(1, &m_texture);
515 CGLSetCurrentContext(m_contextObj);
516 ::glDeleteTextures(1, &m_texture);
518 EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
519 gl::DeleteTextures(1, &m_texture);
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);
529 if (m_attrs.stencil || m_attrs.depth)
530 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
532 ::glDeleteFramebuffersEXT(1, &m_fbo);
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);
540 if (m_attrs.stencil || m_attrs.depth)
541 gl::DeleteRenderbuffers(1, &m_depthStencilBuffer);
543 gl::DeleteFramebuffers(1, &m_fbo);
547 [EAGLContext setCurrentContext:0];
548 [static_cast<EAGLContext*>(m_contextObj) release];
550 CGLSetCurrentContext(0);
551 CGLDestroyContext(m_contextObj);
553 EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
554 EGL_DestroyContext(m_displayObj, m_contextObj);
556 [m_webGLLayer setContext:nullptr];
559 LOG(WebGL, "Destroyed a GraphicsContext3D (%p).", this);
563 void GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height)
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];
569 [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)];
570 [m_webGLLayer setOpaque:!m_attrs.alpha];
572 [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<id<EAGLDrawable>>(m_webGLLayer.get())];
574 [m_webGLLayer setBounds:previousBounds];
578 bool GraphicsContext3D::makeContextCurrent()
584 if ([EAGLContext currentContext] != m_contextObj)
585 return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)];
587 CGLContextObj currentContext = CGLGetCurrentContext();
588 if (currentContext != m_contextObj)
589 return CGLSetCurrentContext(m_contextObj) == kCGLNoError;
591 if (EGL_GetCurrentContext() != m_contextObj)
592 return EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, m_contextObj);
597 void GraphicsContext3D::checkGPUStatus()
599 if (m_failNextStatusCheck) {
600 LOG(WebGL, "Pretending the GPU has reset (%p). Lose the context.", this);
601 m_failNextStatusCheck = false;
604 CGLSetCurrentContext(0);
606 [EAGLContext setCurrentContext:0];
608 EGL_MakeCurrent(m_displayObj, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
613 // Only do the check every statusCheckThreshold calls.
614 if (m_statusCheckCount)
617 m_statusCheckCount = (m_statusCheckCount + 1) % statusCheckThreshold;
619 GLint restartStatus = 0;
621 CGLGetParameter(platformGraphicsContext3D(), kCGLCPGPURestartStatus, &restartStatus);
622 if (restartStatus == kCGLCPGPURestartStatusBlacklisted) {
623 LOG(WebGL, "The GPU has blacklisted us (%p). Terminating.", this);
626 if (restartStatus == kCGLCPGPURestartStatusCaused) {
627 LOG(WebGL, "The GPU has reset us (%p). Lose the context.", this);
629 CGLSetCurrentContext(0);
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);
637 [EAGLContext setCurrentContext:0];
640 // FIXME: check via KHR_robustness.
646 void GraphicsContext3D::presentRenderbuffer()
648 makeContextCurrent();
649 if (m_attrs.antialias)
650 resolveMultisamplingIfNecessary();
653 ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
654 [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER];
655 [EAGLContext setCurrentContext:nil];
659 bool GraphicsContext3D::texImageIOSurface2D(GC3Denum target, GC3Denum internalFormat, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, IOSurfaceRef surface, GC3Duint plane)
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];
666 UNUSED_PARAM(target);
667 UNUSED_PARAM(internalFormat);
669 UNUSED_PARAM(height);
670 UNUSED_PARAM(format);
672 UNUSED_PARAM(surface);
679 void GraphicsContext3D::allocateIOSurfaceBackingStore(IntSize size)
681 LOG(WebGL, "GraphicsContext3D::allocateIOSurfaceBackingStore at %d x %d. (%p)", size.width(), size.height(), this);
682 [m_webGLLayer allocateIOSurfaceBackingStoreWithSize:size usingAlpha:m_attrs.alpha];
685 void GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer()
687 LOG(WebGL, "GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer(). (%p)", this);
688 [m_webGLLayer bindFramebufferToNextAvailableSurface];
691 void GraphicsContext3D::updateCGLContext()
696 LOG(WebGL, "Detected a mux switch or display reconfiguration. Call CGLUpdateContext. (%p)", this);
698 makeContextCurrent();
699 CGLUpdateContext(m_contextObj);
700 m_hasSwitchedToHighPerformanceGPU = true;
703 #endif // USE(OPENGL)
705 #if USE(OPENGL) || USE(ANGLE)
706 void GraphicsContext3D::setContextVisibility(bool isVisible)
708 if (m_powerPreferenceUsedForCreation == GraphicsContext3DPowerPreference::HighPerformance) {
710 GraphicsContext3DManager::sharedManager().addContextRequiringHighPerformance(this);
712 GraphicsContext3DManager::sharedManager().removeContextRequiringHighPerformance(this);
715 #endif // USE(OPENGL) || USE(ANGLE)
718 void GraphicsContext3D::allocateIOSurfaceBackingStore(IntSize size)
720 LOG(WebGL, "GraphicsContext3D::allocateIOSurfaceBackingStore at %d x %d. (%p)", size.width(), size.height(), this);
721 [m_webGLLayer allocateIOSurfaceBackingStoreWithSize:size usingAlpha:m_attrs.alpha];
724 void GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer()
726 LOG(WebGL, "GraphicsContext3D::updateFramebufferTextureBackingStoreFromLayer(). (%p)", this);
727 [m_webGLLayer bindFramebufferToNextAvailableSurface];
731 bool GraphicsContext3D::isGLES2Compliant() const
733 return m_isForWebGL2;
736 void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
740 void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
744 void GraphicsContext3D::simulateContextChanged()
746 GraphicsContext3DManager::sharedManager().updateAllContexts();
749 bool GraphicsContext3D::allowOfflineRenderers() const
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())
760 #elif PLATFORM(MACCATALYST)
761 // FIXME: <rdar://53062794> We're very inconsistent about WEBPROCESS_WINDOWSERVER_BLOCKING
762 // and MAC/MACCATALYST and OPENGL/OPENGLES.
766 #if HAVE(APPLE_GRAPHICS_CONTROL)
767 if (hasLowAndHighPowerGPUs())
775 void GraphicsContext3D::screenDidChange(PlatformDisplayID displayID)
780 UNUSED_PARAM(displayID);
782 // FIXME: figure out whether to integrate more code into ANGLE to have this effect.
784 if (!m_hasSwitchedToHighPerformanceGPU)
785 setGPUByRegistryID(m_contextObj, CGLGetPixelFormat(m_contextObj), gpuIDForDisplay(displayID));
789 #endif // !PLATFORM(MAC)
793 #endif // ENABLE(GRAPHICS_CONTEXT_3D)