2011-04-04 Martin Robinson <mrobinson@igalia.com>
[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 COMPUTER, 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 COMPUTER, 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(WEBGL)
29
30 #include "GraphicsContext3D.h"
31
32 #import "BlockExceptions.h"
33
34 #include "ANGLE/ShaderLang.h"
35 #include "ArrayBuffer.h"
36 #include "ArrayBufferView.h"
37 #include "CanvasRenderingContext.h"
38 #include <CoreGraphics/CGBitmapContext.h>
39 #include "Extensions3DOpenGL.h"
40 #include "Float32Array.h"
41 #include "GraphicsContext.h"
42 #include "HTMLCanvasElement.h"
43 #include "ImageBuffer.h"
44 #include "Int32Array.h"
45 #include "NotImplemented.h"
46 #include <OpenGL/CGLRenderers.h>
47 #include <OpenGL/gl.h>
48 #include "Uint8Array.h"
49 #include "WebGLLayer.h"
50 #include "WebGLObject.h"
51 #include <wtf/UnusedParam.h>
52 #include <wtf/text/CString.h>
53
54 namespace WebCore {
55
56 static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest)
57 {
58     attribs.clear();
59     
60     attribs.append(kCGLPFAColorSize);
61     attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
62     attribs.append(kCGLPFADepthSize);
63     attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
64     
65     if (accelerated)
66         attribs.append(kCGLPFAAccelerated);
67     else {
68         attribs.append(kCGLPFARendererID);
69         attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
70     }
71         
72     if (supersample)
73         attribs.append(kCGLPFASupersample);
74         
75     if (closest)
76         attribs.append(kCGLPFAClosestPolicy);
77         
78     attribs.append(static_cast<CGLPixelFormatAttribute>(0));
79 }
80
81 PassRefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle)
82 {
83     // This implementation doesn't currently support rendering directly to the HostWindow.
84     if (renderStyle == RenderDirectlyToHostWindow)
85         return 0;
86     RefPtr<GraphicsContext3D> context = adoptRef(new GraphicsContext3D(attrs, hostWindow, false));
87     return context->m_contextObj ? context.release() : 0;
88 }
89
90 GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool)
91     : m_currentWidth(0)
92     , m_currentHeight(0)
93     , m_contextObj(0)
94     , m_attrs(attrs)
95     , m_texture(0)
96     , m_compositorTexture(0)
97     , m_fbo(0)
98     , m_depthStencilBuffer(0)
99     , m_layerComposited(false)
100     , m_internalColorFormat(0)
101     , m_boundFBO(0)
102     , m_activeTexture(0)
103     , m_boundTexture0(0)
104     , m_multisampleFBO(0)
105     , m_multisampleDepthStencilBuffer(0)
106     , m_multisampleColorBuffer(0)
107 {
108     UNUSED_PARAM(hostWindow);
109
110     Vector<CGLPixelFormatAttribute> attribs;
111     CGLPixelFormatObj pixelFormatObj = 0;
112     GLint numPixelFormats = 0;
113     
114     // We will try:
115     //
116     //  1) 32 bit RGBA/32 bit depth/accelerated/supersampled
117     //  2) 32 bit RGBA/32 bit depth/accelerated
118     //  3) 32 bit RGBA/16 bit depth/accelerated
119     //  4) closest to 32 bit RGBA/16 bit depth/software renderer
120     //
121     //  If none of that works, we simply fail and set m_contextObj to 0.
122     
123     setPixelFormat(attribs, 32, 32, true, true, false);
124     CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
125     if (numPixelFormats == 0) {
126         setPixelFormat(attribs, 32, 32, true, false, false);
127         CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
128         
129         if (numPixelFormats == 0) {
130             setPixelFormat(attribs, 32, 16, true, false, false);
131             CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
132         
133             if (numPixelFormats == 0) {
134                 setPixelFormat(attribs, 32, 16, false, false, true);
135                 CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
136         
137                 if (numPixelFormats == 0) {
138                     // Could not find an acceptable renderer - fail
139                     return;
140                 }
141             }
142         }
143     }
144     
145     CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
146     CGLDestroyPixelFormat(pixelFormatObj);
147     
148     if (err != kCGLNoError || !m_contextObj) {
149         // Could not create the context - fail
150         m_contextObj = 0;
151         return;
152     }
153
154     // Set the current context to the one given to us.
155     CGLSetCurrentContext(m_contextObj);
156     
157     validateAttributes();
158
159     // Create the WebGLLayer
160     BEGIN_BLOCK_OBJC_EXCEPTIONS
161         m_webGLLayer.adoptNS([[WebGLLayer alloc] initWithGraphicsContext3D:this]);
162 #ifndef NDEBUG
163         [m_webGLLayer.get() setName:@"WebGL Layer"];
164 #endif    
165     END_BLOCK_OBJC_EXCEPTIONS
166     
167     // create a texture to render into
168     ::glGenTextures(1, &m_texture);
169     ::glBindTexture(GL_TEXTURE_2D, m_texture);
170     ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
171     ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
172     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
173     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
174     ::glGenTextures(1, &m_compositorTexture);
175     ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
176     ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
177     ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
178     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
179     ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
180     ::glBindTexture(GL_TEXTURE_2D, 0);
181     
182     // create an FBO
183     ::glGenFramebuffersEXT(1, &m_fbo);
184     ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
185     
186     m_boundFBO = m_fbo;
187     if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth))
188         ::glGenRenderbuffersEXT(1, &m_depthStencilBuffer);
189
190     // create an multisample FBO
191     if (m_attrs.antialias) {
192         ::glGenFramebuffersEXT(1, &m_multisampleFBO);
193         ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
194         m_boundFBO = m_multisampleFBO;
195         ::glGenRenderbuffersEXT(1, &m_multisampleColorBuffer);
196         if (m_attrs.stencil || m_attrs.depth)
197             ::glGenRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
198     }
199     
200     // ANGLE initialization.
201
202     ShBuiltInResources ANGLEResources;
203     ShInitBuiltInResources(&ANGLEResources);
204
205     getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs);
206     getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors);
207     getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors);
208     getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits);
209     getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits);
210     getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits);
211     getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors);
212
213     // Always set to 1 for OpenGL ES.
214     ANGLEResources.MaxDrawBuffers = 1;
215     
216     m_compiler.setResources(ANGLEResources);
217     
218     ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
219     ::glEnable(GL_POINT_SPRITE);
220
221     ::glClearColor(0, 0, 0, 0);
222 }
223
224 GraphicsContext3D::~GraphicsContext3D()
225 {
226     if (m_contextObj) {
227         CGLSetCurrentContext(m_contextObj);
228         ::glDeleteTextures(1, &m_texture);
229         ::glDeleteTextures(1, &m_compositorTexture);
230         if (m_attrs.antialias) {
231             ::glDeleteRenderbuffersEXT(1, &m_multisampleColorBuffer);
232             if (m_attrs.stencil || m_attrs.depth)
233                 ::glDeleteRenderbuffersEXT(1, &m_multisampleDepthStencilBuffer);
234             ::glDeleteFramebuffersEXT(1, &m_multisampleFBO);
235         } else {
236             if (m_attrs.stencil || m_attrs.depth)
237                 ::glDeleteRenderbuffersEXT(1, &m_depthStencilBuffer);
238         }
239         ::glDeleteFramebuffersEXT(1, &m_fbo);
240         CGLSetCurrentContext(0);
241         CGLDestroyContext(m_contextObj);
242     }
243 }
244
245 void GraphicsContext3D::makeContextCurrent()
246 {
247     if (!m_contextObj)
248         return;
249
250     CGLContextObj currentContext = CGLGetCurrentContext();
251     if (currentContext != m_contextObj)
252         CGLSetCurrentContext(m_contextObj);
253 }
254
255 bool GraphicsContext3D::isGLES2Compliant() const
256 {
257     return false;
258 }
259
260 void GraphicsContext3D::setContextLostCallback(PassOwnPtr<ContextLostCallback>)
261 {
262 }
263
264 }
265
266 #endif // ENABLE(WEBGL)