Unreviewed, rolling out r212637.
[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 #endif
195 }
196
197 void GraphicsContext3DManager::addContext(GraphicsContext3D* context)
198 {
199     ASSERT(context);
200     if (!context)
201         return;
202
203 #if PLATFORM(MAC)
204     if (!m_contexts.size())
205         CGDisplayRegisterReconfigurationCallback(displayWasReconfigured, nullptr);
206 #endif
207
208     ASSERT(!m_contexts.contains(context));
209     m_contexts.append(context);
210 }
211
212 void GraphicsContext3DManager::removeContext(GraphicsContext3D* context)
213 {
214     ASSERT(m_contexts.contains(context));
215     m_contexts.removeFirst(context);
216     removeContextRequiringHighPerformance(context);
217
218 #if PLATFORM(MAC)
219     if (!m_contexts.size())
220         CGDisplayRemoveReconfigurationCallback(displayWasReconfigured, nullptr);
221 #endif
222 }
223
224 void GraphicsContext3DManager::addContextRequiringHighPerformance(GraphicsContext3D* context)
225 {
226     ASSERT(context);
227     if (!context)
228         return;
229
230     ASSERT(m_contexts.contains(context));
231     ASSERT(!m_contextsRequiringHighPerformance.contains(context));
232
233     LOG(WebGL, "This context (%p) requires the high-performance GPU.", context);
234     m_contextsRequiringHighPerformance.add(context);
235
236     updateHighPerformanceState();
237 }
238
239 void GraphicsContext3DManager::removeContextRequiringHighPerformance(GraphicsContext3D* context)
240 {
241     if (!m_contextsRequiringHighPerformance.contains(context))
242         return;
243
244     LOG(WebGL, "This context (%p) no longer requires the high-performance GPU.", context);
245     m_contextsRequiringHighPerformance.remove(context);
246
247     updateHighPerformanceState();
248 }
249
250 void GraphicsContext3DManager::updateHighPerformanceState()
251 {
252 #if PLATFORM(MAC)
253     if (!hasMuxableGPU())
254         return;
255
256     if (m_contextsRequiringHighPerformance.size()) {
257
258         if (m_disableHighPerformanceGPUTimer.isActive()) {
259             LOG(WebGL, "Cancel pending timer for turning off high-performance GPU.");
260             m_disableHighPerformanceGPUTimer.stop();
261         }
262
263         if (!m_pixelFormatObj) {
264             LOG(WebGL, "Turning on high-performance GPU.");
265
266             static NeverDestroyed<Vector<CGLPixelFormatAttribute>> pixelFormatAttributes;
267             Vector<CGLPixelFormatAttribute>& attributes = pixelFormatAttributes.get();
268             if (!attributes.size()) {
269                 attributes.append(kCGLPFAAccelerated);
270                 attributes.append(kCGLPFAColorSize);
271                 attributes.append(static_cast<CGLPixelFormatAttribute>(32));
272                 attributes.append(static_cast<CGLPixelFormatAttribute>(0));
273             }
274             GLint numPixelFormats = 0;
275             CGLChoosePixelFormat(attributes.data(), &m_pixelFormatObj, &numPixelFormats);
276         }
277
278     } else if (m_pixelFormatObj) {
279         // Don't immediately turn off the high-performance GPU. The user might be
280         // swapping back and forth between tabs or windows, and we don't want to cause
281         // churn if we can avoid it.
282         if (!m_disableHighPerformanceGPUTimer.isActive()) {
283             LOG(WebGL, "Set a timer to turn off high-performance GPU.");
284             // FIXME: Expose this value as a Setting, which would require this class
285             // to reference a frame, page or document.
286             static const int timeToKeepHighPerformanceGPUAliveInSeconds = 10;
287             m_disableHighPerformanceGPUTimer.startOneShot(timeToKeepHighPerformanceGPUAliveInSeconds);
288         }
289     }
290 #endif
291 }
292
293 void GraphicsContext3DManager::disableHighPerformanceGPUTimerFired()
294 {
295 #if PLATFORM(MAC)
296     if (!m_contextsRequiringHighPerformance.size() && m_pixelFormatObj) {
297         LOG(WebGL, "Turning off high-performance GPU.");
298         CGLReleasePixelFormat(m_pixelFormatObj);
299         m_pixelFormatObj = nullptr;
300     }
301 #endif
302 }
303
304 void GraphicsContext3DManager::recycleContextIfNecessary()
305 {
306     if (hasTooManyContexts()) {
307         LOG(WebGL, "Manager recycled context (%p).", m_contexts.at(0));
308         m_contexts.at(0)->recycleContext();
309     }
310 }
311
312 const int GPUStatusCheckThreshold = 5;
313 int GraphicsContext3D::GPUCheckCounter = 0;
314
315 // FIXME: This class is currently empty on Mac, but will get populated as 
316 // the restructuring in https://bugs.webkit.org/show_bug.cgi?id=66903 is done
317 class GraphicsContext3DPrivate {
318 public:
319     GraphicsContext3DPrivate(GraphicsContext3D*) { }
320     
321     ~GraphicsContext3DPrivate() { }
322 };
323
324 #if PLATFORM(MAC)
325
326 static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest, bool antialias, bool useGLES3)
327 {
328     attribs.clear();
329     
330     attribs.append(kCGLPFAColorSize);
331     attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
332     attribs.append(kCGLPFADepthSize);
333     attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
334
335     // This attribute, while mentioning offline renderers, is actually
336     // allowing us to request the integrated graphics on a dual GPU
337     // system, and not force the discrete GPU.
338     // See https://developer.apple.com/library/mac/technotes/tn2229/_index.html
339     attribs.append(kCGLPFAAllowOfflineRenderers);
340
341     if (accelerated)
342         attribs.append(kCGLPFAAccelerated);
343     else {
344         attribs.append(kCGLPFARendererID);
345         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
346     }
347         
348     if (supersample && !antialias)
349         attribs.append(kCGLPFASupersample);
350         
351     if (closest)
352         attribs.append(kCGLPFAClosestPolicy);
353
354     if (antialias) {
355         attribs.append(kCGLPFAMultisample);
356         attribs.append(kCGLPFASampleBuffers);
357         attribs.append(static_cast<CGLPixelFormatAttribute>(1));
358         attribs.append(kCGLPFASamples);
359         attribs.append(static_cast<CGLPixelFormatAttribute>(4));
360     }
361
362     if (useGLES3) {
363         // FIXME: Instead of backing a WebGL2 GraphicsContext3D with a OpenGL 3.2 context, we should instead back it with ANGLE.
364         // Use an OpenGL 3.2 context for now until the ANGLE backend is ready.
365         attribs.append(kCGLPFAOpenGLProfile);
366         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_3_2_Core));
367     }
368         
369     attribs.append(static_cast<CGLPixelFormatAttribute>(0));
370 }
371 #endif // !PLATFORM(IOS)
372
373 RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
374 {
375     // This implementation doesn't currently support rendering directly to the HostWindow.
376     if (renderStyle == RenderDirectlyToHostWindow)
377         return nullptr;
378
379     // Make space for the incoming context if we're full.
380     manager().recycleContextIfNecessary();
381     if (manager().hasTooManyContexts())
382         return nullptr;
383
384     RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, renderStyle));
385
386     if (!context->m_contextObj)
387         return nullptr;
388
389     manager().addContext(context.get());
390
391     return context;
392 }
393
394 GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
395     : m_currentWidth(0)
396     , m_currentHeight(0)
397     , m_contextObj(0)
398 #if PLATFORM(IOS)
399     , m_compiler(SH_ESSL_OUTPUT)
400 #endif
401     , m_attrs(attrs)
402     , m_texture(0)
403     , m_compositorTexture(0)
404     , m_fbo(0)
405     , m_depthStencilBuffer(0)
406     , m_layerComposited(false)
407     , m_internalColorFormat(0)
408     , m_multisampleFBO(0)
409     , m_multisampleDepthStencilBuffer(0)
410     , m_multisampleColorBuffer(0)
411     , m_private(std::make_unique<GraphicsContext3DPrivate>(this))
412     , m_webglContext(0)
413 {
414     UNUSED_PARAM(hostWindow);
415     UNUSED_PARAM(renderStyle);
416
417 #if PLATFORM(IOS)
418     EAGLRenderingAPI api = m_attrs.useGLES3 ? kEAGLRenderingAPIOpenGLES3 : kEAGLRenderingAPIOpenGLES2;
419     m_contextObj = [[EAGLContext alloc] initWithAPI:api];
420     makeContextCurrent();
421 #else
422     Vector<CGLPixelFormatAttribute> attribs;
423     CGLPixelFormatObj pixelFormatObj = 0;
424     GLint numPixelFormats = 0;
425     
426     // If we're configured to demand the software renderer, we'll
427     // do so. We attempt to create contexts in this order:
428     //
429     // 1) 32 bit RGBA/32 bit depth/supersampled
430     // 2) 32 bit RGBA/32 bit depth
431     // 3) 32 bit RGBA/16 bit depth
432     //
433     // If we were not forced into software mode already, our final attempt is
434     // to try that:
435     //
436     // 4) closest to 32 bit RGBA/16 bit depth/software renderer
437     //
438     // If none of that works, we simply fail and set m_contextObj to 0.
439
440     bool useMultisampling = m_attrs.antialias;
441
442     m_powerPreferenceUsedForCreation = (hasMuxableGPU() && attrs.powerPreference == GraphicsContext3DPowerPreference::HighPerformance) ? GraphicsContext3DPowerPreference::HighPerformance : GraphicsContext3DPowerPreference::Default;
443
444     setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, true, false, useMultisampling, attrs.useGLES3);
445     CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
446
447     if (!numPixelFormats) {
448         setPixelFormat(attribs, 32, 32, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.useGLES3);
449         CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
450
451         if (!numPixelFormats) {
452             setPixelFormat(attribs, 32, 16, !attrs.forceSoftwareRenderer, false, false, useMultisampling, attrs.useGLES3);
453             CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
454
455             if (!attrs.forceSoftwareRenderer && !numPixelFormats) {
456                 setPixelFormat(attribs, 32, 16, false, false, true, false, attrs.useGLES3);
457                 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
458                 useMultisampling = false;
459             }
460         }
461     }
462
463     if (numPixelFormats == 0)
464         return;
465
466     CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
467     GLint abortOnBlacklist = 0;
468 #if PLATFORM(MAC)
469     CGLSetParameter(m_contextObj, kCGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
470 #elif PLATFORM(IOS)
471     CGLSetParameter(m_contextObj, kEAGLCPAbortOnGPURestartStatusBlacklisted, &abortOnBlacklist);
472 #endif
473
474     CGLDestroyPixelFormat(pixelFormatObj);
475     
476     if (err != kCGLNoError || !m_contextObj) {
477         // We were unable to create the context.
478         m_contextObj = 0;
479         return;
480     }
481
482     m_isForWebGL2 = attrs.useGLES3;
483
484     // Set the current context to the one given to us.
485     CGLSetCurrentContext(m_contextObj);
486
487 #endif // !PLATFORM(IOS)
488     
489     validateAttributes();
490
491     // Create the WebGLLayer
492     BEGIN_BLOCK_OBJC_EXCEPTIONS
493         m_webGLLayer = adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
494 #ifndef NDEBUG
495         [m_webGLLayer setName:@"WebGL Layer"];
496 #endif
497     END_BLOCK_OBJC_EXCEPTIONS
498
499 #if !PLATFORM(IOS)
500     if (useMultisampling)
501         ::glEnable(GL_MULTISAMPLE);
502 #endif
503
504 #if PLATFORM(IOS)
505     ::glGenRenderbuffers(1, &m_texture);
506 #else
507     // create a texture to render into
508     ::glGenTextures(1, &m_texture);
509     ::glBindTexture(GL_TEXTURE_2D, m_texture);
510     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
511     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
512     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
513     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
514     ::glGenTextures(1, &m_compositorTexture);
515     ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
516     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
517     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
518     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
519     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
520     ::glBindTexture(GL_TEXTURE_2D, 0);
521 #endif
522
523     // create an FBO
524     ::glGenFramebuffersEXT(1, &m_fbo);
525     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
526
527     m_state.boundFBO = m_fbo;
528     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
529         ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
530
531     // create an multisample FBO
532     if (m_attrs.antialias) {
533         ::glGenFramebuffersEXT(1, &m_multisampleFBO);
534         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
535         m_state.boundFBO = m_multisampleFBO;
536         ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
537         if (m_attrs.stencil || m_attrs.depth)
538             ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
539     }
540     
541     // ANGLE initialization.
542
543     ShBuiltInResources ANGLEResources;
544     ShInitBuiltInResources(&ANGLEResources);
545
546     getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
547     getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
548     getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
549     getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
550     getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
551     getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
552     getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
553
554     // Always set to 1 for OpenGL ES.
555     ANGLEResources.MaxDrawBuffers = 1;
556     
557     GC3Dint range[2], precision;
558     getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision);
559     ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision);
560
561     m_compiler.setResources(ANGLEResources);
562     
563 #if !PLATFORM(IOS)
564     ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
565     if (!isGLES2Compliant())
566         ::glEnable(GL_POINT_SPRITE);
567 #endif
568
569     ::glClearColor(0, 0, 0, 0);
570
571     LOG(WebGL, "Created a GraphicsContext3D (%p).", this);
572 }
573
574 GraphicsContext3D::~GraphicsContext3D()
575 {
576     manager().removeContext(this);
577
578     if (m_contextObj) {
579 #if PLATFORM(IOS)
580         makeContextCurrent();
581         [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:nil];
582         ::glDeleteRenderbuffers(1, &m_texture);
583 #else
584         CGLSetCurrentContext(m_contextObj);
585         ::glDeleteTextures(1, &m_texture);
586         ::glDeleteTextures(1, &m_compositorTexture);
587 #endif
588         if (m_attrs.antialias) {
589             ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
590             if (m_attrs.stencil || m_attrs.depth)
591                 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
592             ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
593         } else {
594             if (m_attrs.stencil || m_attrs.depth)
595                 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
596         }
597         ::glDeleteFramebuffersEXT(1, &m_fbo);
598 #if PLATFORM(IOS)
599         [EAGLContext setCurrentContext:0];
600         [static_cast<EAGLContext*>(m_contextObj) release];
601 #else
602         CGLSetCurrentContext(0);
603         CGLDestroyContext(m_contextObj);
604 #endif
605         [m_webGLLayer setContext:nullptr];
606     }
607
608     LOG(WebGL, "Destroyed a GraphicsContext3D (%p).", this);
609 }
610
611 #if PLATFORM(IOS)
612 void GraphicsContext3D::setRenderbufferStorageFromDrawable(GC3Dsizei width, GC3Dsizei height)
613 {
614     // We need to make a call to setBounds below to update the backing store size but we also
615     // do not want to clobber the bounds set during layout.
616     CGRect previousBounds = [m_webGLLayer.get() bounds];
617
618     [m_webGLLayer setBounds:CGRectMake(0, 0, width, height)];
619     [m_webGLLayer setOpaque:(m_internalColorFormat != GL_RGBA8)];
620
621     [m_contextObj renderbufferStorage:GL_RENDERBUFFER fromDrawable:static_cast<id<EAGLDrawable>>(m_webGLLayer.get())];
622
623     [m_webGLLayer setBounds:previousBounds];
624 }
625 #endif
626
627 bool GraphicsContext3D::makeContextCurrent()
628 {
629     if (!m_contextObj)
630         return false;
631
632 #if PLATFORM(IOS)
633     if ([EAGLContext currentContext] != m_contextObj)
634         return [EAGLContext setCurrentContext:static_cast<EAGLContext*>(m_contextObj)];
635 #else
636     CGLContextObj currentContext = CGLGetCurrentContext();
637     if (currentContext != m_contextObj)
638         return CGLSetCurrentContext(m_contextObj) == kCGLNoError;
639 #endif
640     return true;
641 }
642
643 void GraphicsContext3D::checkGPUStatusIfNecessary()
644 {
645     bool needsCheck = !GPUCheckCounter;
646     GPUCheckCounter = (GPUCheckCounter + 1) % GPUStatusCheckThreshold;
647
648     if (!needsCheck)
649         return;
650
651     GLint restartStatus = 0;
652 #if PLATFORM(MAC)
653     CGLGetParameter(platformGraphicsContext3D(), kCGLCPGPURestartStatus, &restartStatus);
654     if (restartStatus == kCGLCPGPURestartStatusBlacklisted) {
655         LOG(WebGL, "The GPU has blacklisted us (%p). Terminating.", this);
656         exit(EX_OSERR);
657     }
658     if (restartStatus == kCGLCPGPURestartStatusCaused) {
659         LOG(WebGL, "The GPU has reset us (%p). Lose the context.", this);
660         forceContextLost();
661         CGLSetCurrentContext(0);
662     }
663 #elif PLATFORM(IOS)
664     EAGLContext* currentContext = static_cast<EAGLContext*>(PlatformGraphicsContext3D());
665     [currentContext getParameter:kEAGLCPGPURestartStatus to:&restartStatus];
666     if (restartStatus == kEAGLCPGPURestartStatusCaused || restartStatus == kEAGLCPGPURestartStatusBlacklisted) {
667         LOG(WebGL, "The GPU has either reset or blacklisted us (%p). Lose the context.", this);
668         forceContextLost();
669         [EAGLContext setCurrentContext:0];
670     }
671 #endif
672 }
673
674 #if PLATFORM(IOS)
675 void GraphicsContext3D::endPaint()
676 {
677     makeContextCurrent();
678     if (m_attrs.antialias)
679         resolveMultisamplingIfNecessary();
680     ::glFlush();
681     ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
682     [static_cast<EAGLContext*>(m_contextObj) presentRenderbuffer:GL_RENDERBUFFER];
683     [EAGLContext setCurrentContext:nil];
684 }
685 #endif
686
687 #if PLATFORM(MAC)
688 void GraphicsContext3D::updateCGLContext()
689 {
690     if (!m_contextObj)
691         return;
692
693     LOG(WebGL, "Detected a mux switch or display reconfiguration. Call CGLUpdateContext. (%p)", this);
694
695     makeContextCurrent();
696     CGLUpdateContext(m_contextObj);
697 }
698
699 void GraphicsContext3D::setContextVisibility(bool isVisible)
700 {
701     if (m_powerPreferenceUsedForCreation == GraphicsContext3DPowerPreference::HighPerformance) {
702         if (isVisible)
703             manager().addContextRequiringHighPerformance(this);
704         else
705             manager().removeContextRequiringHighPerformance(this);
706     }
707 }
708 #endif
709
710 bool GraphicsContext3D::isGLES2Compliant() const
711 {
712     return m_isForWebGL2;
713 }
714
715 void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
716 {
717 }
718
719 void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
720 {
721 }
722
723 }
724
725 #endif // ENABLE(GRAPHICS_CONTEXT_3D)