35a0cd8c8030f7338ca069d82fef4577fd558fdc
[WebKit-https.git] / Source / WebCore / platform / graphics / mac / GraphicsContext3DMac.mm
1 /*
2  * Copyright (C) 2009 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
30 #include "GraphicsContext3D.h"
31 #if PLATFORM(IOS)
32 #include "GraphicsContext3DIOS.h"
33 #endif
34
35 #import <wtf/BlockObjCExceptions.h>
36
37 #include "CanvasRenderingContext.h"
38 #include <CoreGraphics/CGBitmapContext.h>
39 #include "Extensions3DOpenGL.h"
40 #include "GraphicsContext.h"
41 #include "HTMLCanvasElement.h"
42 #include "ImageBuffer.h"
43 #include "Logging.h"
44 #include "WebGLLayer.h"
45 #include "WebGLObject.h"
46 #include "WebGLRenderingContextBase.h"
47 #include <sys/sysctl.h>
48 #include <sysexits.h>
49 #include <wtf/text/CString.h>
50
51 #if PLATFORM(IOS)
52 #import "OpenGLESSPI.h"
53 #import <OpenGLES/ES2/glext.h>
54 #import <OpenGLES/EAGL.h>
55 #import <OpenGLES/EAGLDrawable.h>
56 #import <QuartzCore/QuartzCore.h>
57 #else
58 #include <IOKit/IOKitLib.h>
59 #include <OpenGL/CGLRenderers.h>
60 #include <OpenGL/gl.h>
61 #endif
62
63 namespace WebCore {
64
65 #if PLATFORM(MAC)
66
67 enum {
68     kAGCOpen,
69     kAGCClose
70 };
71
72 static io_connect_t attachToAppleGraphicsControl()
73 {
74     mach_port_t masterPort;
75
76     if (IOMasterPort(MACH_PORT_NULL, &masterPort) != KERN_SUCCESS)
77         return MACH_PORT_NULL;
78
79     CFDictionaryRef classToMatch = IOServiceMatching("AppleGraphicsControl");
80     if (!classToMatch)
81         return MACH_PORT_NULL;
82
83     kern_return_t kernResult;
84     io_iterator_t iterator;
85     if ((kernResult = IOServiceGetMatchingServices(masterPort, classToMatch, &iterator)) != KERN_SUCCESS)
86         return MACH_PORT_NULL;
87
88     io_service_t serviceObject = IOIteratorNext(iterator);
89     IOObjectRelease(iterator);
90     if (!serviceObject)
91         return MACH_PORT_NULL;
92
93     io_connect_t dataPort;
94     IOObjectRetain(serviceObject);
95     kernResult = IOServiceOpen(serviceObject, mach_task_self(), 0, &dataPort);
96     IOObjectRelease(serviceObject);
97
98     return (kernResult == KERN_SUCCESS) ? dataPort : MACH_PORT_NULL;
99 }
100
101 static bool hasMuxCapability()
102 {
103     io_connect_t dataPort = attachToAppleGraphicsControl();
104
105     if (dataPort == MACH_PORT_NULL)
106         return false;
107
108     bool result;
109     if (IOConnectCallScalarMethod(dataPort, kAGCOpen, nullptr, 0, nullptr, nullptr) == KERN_SUCCESS) {
110         IOConnectCallScalarMethod(dataPort, kAGCClose, nullptr, 0, nullptr, nullptr);
111         result = true;
112     } else
113         result = false;
114
115     IOServiceClose(dataPort);
116
117     if (result) {
118         // This is detecting Mac hardware with an Intel g575 GPU, which
119         // we don't want to make available to muxing.
120         // Based on information from Apple's OpenGL team, such devices
121         // have four or fewer processors.
122         // <rdar://problem/30060378>
123         int names[2] = { CTL_HW, HW_NCPU };
124         int cpuCount;
125         size_t cpuCountLength = sizeof(cpuCount);
126         sysctl(names, 2, &cpuCount, &cpuCountLength, nullptr, 0);
127         result = cpuCount > 4;
128     }
129     
130     return result;
131 }
132
133 static bool hasMuxableGPU()
134 {
135     static bool canMux = hasMuxCapability();
136     return canMux;
137 }
138
139 #endif
140
141 const unsigned MaxContexts = 16;
142
143 class GraphicsContext3DManager {
144 public:
145     GraphicsContext3DManager()
146         : m_disableHighPerformanceGPUTimer(*this, &GraphicsContext3DManager::disableHighPerformanceGPUTimerFired)
147     {
148     }
149
150     void addContext(GraphicsContext3D*);
151     void removeContext(GraphicsContext3D*);
152
153     void addContextRequiringHighPerformance(GraphicsContext3D*);
154     void removeContextRequiringHighPerformance(GraphicsContext3D*);
155
156     void recycleContextIfNecessary();
157     bool hasTooManyContexts() const { return m_contexts.size() >= MaxContexts; }
158
159     void updateAllContexts();
160
161 private:
162     void updateHighPerformanceState();
163     void disableHighPerformanceGPUTimerFired();
164
165     Vector<GraphicsContext3D*> m_contexts;
166     HashSet<GraphicsContext3D*> m_contextsRequiringHighPerformance;
167
168     Timer m_disableHighPerformanceGPUTimer;
169
170 #if PLATFORM(MAC)
171     CGLPixelFormatObj m_pixelFormatObj { nullptr };
172 #endif
173 };
174
175 static GraphicsContext3DManager& manager()
176 {
177     static NeverDestroyed<GraphicsContext3DManager> s_manager;
178     return s_manager;
179 }
180
181 #if PLATFORM(MAC)
182 static void displayWasReconfigured(CGDirectDisplayID, CGDisplayChangeSummaryFlags flags, void*)
183 {
184     if (flags & kCGDisplaySetModeFlag)
185         manager().updateAllContexts();
186 }
187 #endif
188
189 void GraphicsContext3DManager::updateAllContexts()
190 {
191 #if PLATFORM(MAC)
192     for (auto* context : m_contexts) {
193         context->updateCGLContext();
194         context->dispatchContextChangedNotification();
195     }
196 #endif
197 }
198
199 void GraphicsContext3DManager::addContext(GraphicsContext3D* context)
200 {
201     ASSERT(context);
202     if (!context)
203         return;
204
205 #if PLATFORM(MAC)
206     if (!m_contexts.size())
207         CGDisplayRegisterReconfigurationCallback(displayWasReconfigured, nullptr);
208 #endif
209
210     ASSERT(!m_contexts.contains(context));
211     m_contexts.append(context);
212 }
213
214 void GraphicsContext3DManager::removeContext(GraphicsContext3D* context)
215 {
216     ASSERT(m_contexts.contains(context));
217     m_contexts.removeFirst(context);
218     removeContextRequiringHighPerformance(context);
219
220 #if PLATFORM(MAC)
221     if (!m_contexts.size())
222         CGDisplayRemoveReconfigurationCallback(displayWasReconfigured, nullptr);
223 #endif
224 }
225
226 void GraphicsContext3DManager::addContextRequiringHighPerformance(GraphicsContext3D* context)
227 {
228     ASSERT(context);
229     if (!context)
230         return;
231
232     ASSERT(m_contexts.contains(context));
233     ASSERT(!m_contextsRequiringHighPerformance.contains(context));
234
235     LOG(WebGL, "This context (%p) requires the high-performance GPU.", context);
236     m_contextsRequiringHighPerformance.add(context);
237
238     updateHighPerformanceState();
239 }
240
241 void GraphicsContext3DManager::removeContextRequiringHighPerformance(GraphicsContext3D* context)
242 {
243     if (!m_contextsRequiringHighPerformance.contains(context))
244         return;
245
246     LOG(WebGL, "This context (%p) no longer requires the high-performance GPU.", context);
247     m_contextsRequiringHighPerformance.remove(context);
248
249     updateHighPerformanceState();
250 }
251
252 void GraphicsContext3DManager::updateHighPerformanceState()
253 {
254 #if PLATFORM(MAC)
255     if (!hasMuxableGPU())
256         return;
257
258     if (m_contextsRequiringHighPerformance.size()) {
259
260         if (m_disableHighPerformanceGPUTimer.isActive()) {
261             LOG(WebGL, "Cancel pending timer for turning off high-performance GPU.");
262             m_disableHighPerformanceGPUTimer.stop();
263         }
264
265         if (!m_pixelFormatObj) {
266             LOG(WebGL, "Turning on high-performance GPU.");
267
268             static NeverDestroyed<Vector<CGLPixelFormatAttribute>> pixelFormatAttributes;
269             Vector<CGLPixelFormatAttribute>& attributes = pixelFormatAttributes.get();
270             if (!attributes.size()) {
271                 attributes.append(kCGLPFAAccelerated);
272                 attributes.append(kCGLPFAColorSize);
273                 attributes.append(static_cast<CGLPixelFormatAttribute>(32));
274                 attributes.append(static_cast<CGLPixelFormatAttribute>(0));
275             }
276             GLint numPixelFormats = 0;
277             CGLChoosePixelFormat(attributes.data(), &m_pixelFormatObj, &numPixelFormats);
278         }
279
280     } else if (m_pixelFormatObj) {
281         // Don't immediately turn off the high-performance GPU. The user might be
282         // swapping back and forth between tabs or windows, and we don't want to cause
283         // churn if we can avoid it.
284         if (!m_disableHighPerformanceGPUTimer.isActive()) {
285             LOG(WebGL, "Set a timer to turn off high-performance GPU.");
286             // FIXME: Expose this value as a Setting, which would require this class
287             // to reference a frame, page or document.
288             static const int timeToKeepHighPerformanceGPUAliveInSeconds = 10;
289             m_disableHighPerformanceGPUTimer.startOneShot(timeToKeepHighPerformanceGPUAliveInSeconds);
290         }
291     }
292 #endif
293 }
294
295 void GraphicsContext3DManager::disableHighPerformanceGPUTimerFired()
296 {
297 #if PLATFORM(MAC)
298     if (!m_contextsRequiringHighPerformance.size() && m_pixelFormatObj) {
299         LOG(WebGL, "Turning off high-performance GPU.");
300         CGLReleasePixelFormat(m_pixelFormatObj);
301         m_pixelFormatObj = nullptr;
302     }
303 #endif
304 }
305
306 void GraphicsContext3DManager::recycleContextIfNecessary()
307 {
308     if (hasTooManyContexts()) {
309         LOG(WebGL, "Manager recycled context (%p).", m_contexts.at(0));
310         m_contexts.at(0)->recycleContext();
311     }
312 }
313
314 const int GPUStatusCheckThreshold = 5;
315 int GraphicsContext3D::GPUCheckCounter = 0;
316
317 // FIXME: This class is currently empty on Mac, but will get populated as 
318 // the restructuring in https://bugs.webkit.org/show_bug.cgi?id=66903 is done
319 class GraphicsContext3DPrivate {
320 public:
321     GraphicsContext3DPrivate(GraphicsContext3D*) { }
322     
323     ~GraphicsContext3DPrivate() { }
324 };
325
326 #if PLATFORM(MAC)
327
328 static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest, bool antialias, bool useGLES3)
329 {
330     attribs.clear();
331     
332     attribs.append(kCGLPFAColorSize);
333     attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
334     attribs.append(kCGLPFADepthSize);
335     attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
336
337     // This attribute, while mentioning offline renderers, is actually
338     // allowing us to request the integrated graphics on a dual GPU
339     // system, and not force the discrete GPU.
340     // See https://developer.apple.com/library/mac/technotes/tn2229/_index.html
341     attribs.append(kCGLPFAAllowOfflineRenderers);
342
343     if (accelerated)
344         attribs.append(kCGLPFAAccelerated);
345     else {
346         attribs.append(kCGLPFARendererID);
347         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
348     }
349         
350     if (supersample && !antialias)
351         attribs.append(kCGLPFASupersample);
352         
353     if (closest)
354         attribs.append(kCGLPFAClosestPolicy);
355
356     if (antialias) {
357         attribs.append(kCGLPFAMultisample);
358         attribs.append(kCGLPFASampleBuffers);
359         attribs.append(static_cast<CGLPixelFormatAttribute>(1));
360         attribs.append(kCGLPFASamples);
361         attribs.append(static_cast<CGLPixelFormatAttribute>(4));
362     }
363
364     if (useGLES3) {
365         // FIXME: Instead of backing a WebGL2 GraphicsContext3D with a OpenGL 3.2 context, we should instead back it with ANGLE.
366         // Use an OpenGL 3.2 context for now until the ANGLE backend is ready.
367         attribs.append(kCGLPFAOpenGLProfile);
368         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core));
369     }
370         
371     attribs.append(static_cast<CGLPixelFormatAttribute>(0));
372 }
373 #endif // !PLATFORM(IOS)
374
375 RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
376 {
377     // This implementation doesn't currently support rendering directly to the HostWindow.
378     if (renderStyle == RenderDirectlyToHostWindow)
379         return nullptr;
380
381     // Make space for the incoming context if we're full.
382     manager().recycleContextIfNecessary();
383     if (manager().hasTooManyContexts())
384         return nullptr;
385
386     RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle));
387
388     if (!context->m_contextObj)
389         return nullptr;
390
391     manager().addContext(context.get());
392
393     return context;
394 }
395
396 GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
397     : m_currentWidth(0)
398     , m_currentHeight(0)
399     , m_contextObj(0)
400 #if PLATFORM(IOS)
401     , m_compiler(SH_ESSL_OUTPUT)
402 #endif
403     , m_attrs(attrs)
404     , m_texture(0)
405     , m_compositorTexture(0)
406     , m_fbo(0)
407     , m_depthStencilBuffer(0)
408     , m_layerComposited(false)
409     , m_internalColorFormat(0)
410     , m_multisampleFBO(0)
411     , m_multisampleDepthStencilBuffer(0)
412     , m_multisampleColorBuffer(0)
413     , m_private(std::make_unique<GraphicsContext3DPrivate>(this))
414     , m_webglContext(0)
415 {
416     UNUSED_PARAM(hostWindow);
417     UNUSED_PARAM(renderStyle);
418
419 #if PLATFORM(IOS)
420     EAGLRenderingAPI api = m_attrs.useGLES3 ? kEAGLRenderingAPIOpenGLES3 : kEAGLRenderingAPIOpenGLES2;
421     m_contextObj = [[EAGLContext alloc] initWithAPI:api];
422     makeContextCurrent();
423 #else
424     Vector<CGLPixelFormatAttribute> attribs;
425     CGLPixelFormatObj pixelFormatObj = 0;
426     GLint numPixelFormats = 0;
427     
428     // If we're configured to demand the software renderer, we'll
429     // do so. We attempt to create contexts in this order:
430     //
431     // 1) 32 bit RGBA/32 bit depth/supersampled
432     // 2) 32 bit RGBA/32 bit depth
433     // 3) 32 bit RGBA/16 bit depth
434     //
435     // If we were not forced into software mode already, our final attempt is
436     // to try that:
437     //
438     // 4) closest to 32 bit RGBA/16 bit depth/software renderer
439     //
440     // If none of that works, we simply fail and set m_contextObj to 0.
441
442     bool useMultisampling = m_attrs.antialias;
443
444     m_powerPreferenceUsedForCreation = (hasMuxableGPU() && attrs.powerPreference == GraphicsContext3DPowerPreference::HighPerformance) ? GraphicsContext3DPowerPreference::HighPerformance : GraphicsContext3DPowerPreference::Default;
445
446     setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, true, false, useMultisampling, attrs.useGLES3);
447     CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
448
449     if (!numPixelFormats) {
450         setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.useGLES3);
451         CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
452
453         if (!numPixelFormats) {
454             setPixelFormat(attribs, 32, 16, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.useGLES3);
455             CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
456
457             if (!attrs.forceSoftwareRenderer && !numPixelFormats) {
458                 setPixelFormat(attribs, 32, 16, false, false, true, false, attrs.useGLES3);
459                 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
460                 useMultisampling = false;
461             }
462         }
463     }
464
465     if (numPixelFormats == 0)
466         return;
467
468     CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
469     GLint abortOnBlacklist = 0;
470 #if PLATFORM(MAC)
471     CGLSetParameter(m_contextObj, kCGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
472 #elif PLATFORM(IOS)
473     CGLSetParameter(m_contextObj, kEAGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
474 #endif
475
476     CGLDestroyPixelFormat(pixelFormatObj);
477     
478     if (err != kCGLNoError || !m_contextObj) {
479         // We were unable to create the context.
480         m_contextObj = 0;
481         return;
482     }
483
484     m_isForWebGL2 = attrs.useGLES3;
485
486     // Set the current context to the one given to us.
487     CGLSetCurrentContext(m_contextObj);
488
489 #endif // !PLATFORM(IOS)
490     
491     validateAttributes();
492
493     // Create the WebGLLayer
494     BEGIN_BLOCK_OBJC_EXCEPTIONS
495         m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
496 #ifndef NDEBUG
497         [m_webGLLayer setName:@"WebGL Layer"];
498 #endif
499     END_BLOCK_OBJC_EXCEPTIONS
500
501 #if !PLATFORM(IOS)
502     if (useMultisampling)
503         ::glEnable(GL_MULTISAMPLE);
504 #endif
505
506 #if PLATFORM(IOS)
507     ::glGenRenderbuffers(1, &m_texture);
508 #else
509     // create a texture to render into
510     ::glGenTextures(1, &m_texture);
511     ::glBindTexture(GL_TEXTURE_2D, m_texture);
512     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
513     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
514     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
515     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
516     ::glGenTextures(1, &m_compositorTexture);
517     ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
518     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
519     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
520     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
521     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
522     ::glBindTexture(GL_TEXTURE_2D, 0);
523 #endif
524
525     // create an FBO
526     ::glGenFramebuffersEXT(1, &m_fbo);
527     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
528
529     m_state.boundFBO = m_fbo;
530     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
531         ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
532
533     // create an multisample FBO
534     if (m_attrs.antialias) {
535         ::glGenFramebuffersEXT(1, &m_multisampleFBO);
536         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
537         m_state.boundFBO = m_multisampleFBO;
538         ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
539         if (m_attrs.stencil || m_attrs.depth)
540             ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
541     }
542     
543     // ANGLE initialization.
544
545     ShBuiltInResources ANGLEResources;
546     ShInitBuiltInResources(&ANGLEResources);
547
548     getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
549     getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
550     getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
551     getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
552     getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
553     getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
554     getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
555
556     // Always set to 1 for OpenGL ES.
557     ANGLEResources.MaxDrawBuffers = 1;
558     
559     GC3Dint range[2], precision;
560     getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision);
561     ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
562
563     m_compiler.setResources(ANGLEResources);
564     
565 #if !PLATFORM(IOS)
566     ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
567     if (!isGLES2Compliant())
568         ::glEnable(GL_POINT_SPRITE);
569 #endif
570
571     ::glClearColor(0, 0, 0, 0);
572
573     LOG(WebGL, "Created a GraphicsContext3D (%p).", this);
574 }
575
576 GraphicsContext3D::~GraphicsContext3D()
577 {
578     manager().removeContext(this);
579
580     if (m_contextObj) {
581 #if PLATFORM(IOS)
582         makeContextCurrent();
583         [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
584         ::glDeleteRenderbuffers(1, &m_texture);
585 #else
586         CGLSetCurrentContext(m_contextObj);
587         ::glDeleteTextures(1, &m_texture);
588         ::glDeleteTextures(1, &m_compositorTexture);
589 #endif
590         if (m_attrs.antialias) {
591             ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
592             if (m_attrs.stencil || m_attrs.depth)
593                 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
594             ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
595         } else {
596             if (m_attrs.stencil || m_attrs.depth)
597                 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
598         }
599         ::glDeleteFramebuffersEXT(1, &m_fbo);
600 #if PLATFORM(IOS)
601         [EAGLContext setCurrentContext:0];
602         [static_cast<EAGLContext*>(m_contextObj) release];
603 #else
604         CGLSetCurrentContext(0);
605         CGLDestroyContext(m_contextObj);
606 #endif
607         [m_webGLLayer setContext:nullptr];
608     }
609
610     LOG(WebGL, "Destroyed a GraphicsContext3D (%p).", this);
611 }
612
613 #if PLATFORM(IOS)
614 void GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height)
615 {
616     // We need to make a call to setBounds below to update the backing store size but we also
617     // do not want to clobber the bounds set during layout.
618     CGRect previousBounds = [m_webGLLayer.get() bounds];
619
620     [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)];
621     [m_webGLLayer setOpaque:(m_internalColorFormat != GL_RGBA8)];
622
623     [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<id<EAGLDrawable>>(m_webGLLayer.get())];
624
625     [m_webGLLayer setBounds:previousBounds];
626 }
627 #endif
628
629 bool GraphicsContext3D::makeContextCurrent()
630 {
631     if (!m_contextObj)
632         return false;
633
634 #if PLATFORM(IOS)
635     if ([EAGLContext currentContext] != m_contextObj)
636         return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)];
637 #else
638     CGLContextObj currentContext = CGLGetCurrentContext();
639     if (currentContext != m_contextObj)
640         return CGLSetCurrentContext(m_contextObj) == kCGLNoError;
641 #endif
642     return true;
643 }
644
645 void GraphicsContext3D::checkGPUStatusIfNecessary()
646 {
647     bool needsCheck = !GPUCheckCounter;
648     GPUCheckCounter = (GPUCheckCounter + 1) % GPUStatusCheckThreshold;
649
650     if (!needsCheck)
651         return;
652
653     GLint restartStatus = 0;
654 #if PLATFORM(MAC)
655     CGLGetParameter(platformGraphicsContext3D(), kCGLCPGPURestartStatus, &restartStatus);
656     if (restartStatus == kCGLCPGPURestartStatusBlacklisted) {
657         LOG(WebGL, "The GPU has blacklisted us (%p). Terminating.", this);
658         exit(EX_OSERR);
659     }
660     if (restartStatus == kCGLCPGPURestartStatusCaused) {
661         LOG(WebGL, "The GPU has reset us (%p). Lose the context.", this);
662         forceContextLost();
663         CGLSetCurrentContext(0);
664     }
665 #elif PLATFORM(IOS)
666     EAGLContext* currentContext = static_cast<EAGLContext*>(PlatformGraphicsContext3D());
667     [currentContext getParameter:kEAGLCPGPURestartStatus to:&restartStatus];
668     if (restartStatus == kEAGLCPGPURestartStatusCaused || restartStatus == kEAGLCPGPURestartStatusBlacklisted) {
669         LOG(WebGL, "The GPU has either reset or blacklisted us (%p). Lose the context.", this);
670         forceContextLost();
671         [EAGLContext setCurrentContext:0];
672     }
673 #endif
674 }
675
676 #if PLATFORM(IOS)
677 void GraphicsContext3D::endPaint()
678 {
679     makeContextCurrent();
680     if (m_attrs.antialias)
681         resolveMultisamplingIfNecessary();
682     ::glFlush();
683     ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
684     [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER];
685     [EAGLContext setCurrentContext:nil];
686 }
687 #endif
688
689 #if PLATFORM(MAC)
690 void GraphicsContext3D::updateCGLContext()
691 {
692     if (!m_contextObj)
693         return;
694
695     LOG(WebGL, "Detected a mux switch or display reconfiguration. Call CGLUpdateContext. (%p)", this);
696
697     makeContextCurrent();
698     CGLUpdateContext(m_contextObj);
699 }
700
701 void GraphicsContext3D::setContextVisibility(bool isVisible)
702 {
703     if (m_powerPreferenceUsedForCreation == GraphicsContext3DPowerPreference::HighPerformance) {
704         if (isVisible)
705             manager().addContextRequiringHighPerformance(this);
706         else
707             manager().removeContextRequiringHighPerformance(this);
708     }
709 }
710 #endif
711
712 bool GraphicsContext3D::isGLES2Compliant() const
713 {
714     return m_isForWebGL2;
715 }
716
717 void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
718 {
719 }
720
721 void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
722 {
723 }
724
725 void GraphicsContext3D::simulateContextChanged()
726 {
727     manager().updateAllContexts();
728 }
729
730 }
731
732 #endif // ENABLE(GRAPHICS_CONTEXT_3D)