• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 
33 #if ENABLE(3D_CANVAS)
34 
35 #include "GraphicsContext3D.h"
36 
37 #include "CachedImage.h"
38 #include "CString.h"
39 #include "HTMLCanvasElement.h"
40 #include "HTMLImageElement.h"
41 #include "ImageBuffer.h"
42 #include "ImageData.h"
43 #include "NotImplemented.h"
44 #include "WebGLBuffer.h"
45 #include "WebGLByteArray.h"
46 #include "WebGLFloatArray.h"
47 #include "WebGLFramebuffer.h"
48 #include "WebGLIntArray.h"
49 #include "WebGLProgram.h"
50 #include "WebGLRenderbuffer.h"
51 #include "WebGLRenderingContext.h"
52 #include "WebGLShader.h"
53 #include "WebGLTexture.h"
54 #include "WebGLUnsignedByteArray.h"
55 
56 #include <stdio.h>
57 #include <wtf/FastMalloc.h>
58 
59 #if OS(WINDOWS)
60 #include <windows.h>
61 #endif
62 
63 #include "GL/glew.h"
64 
65 #if PLATFORM(CG)
66 #include "GraphicsContext.h"
67 #include <CoreGraphics/CGContext.h>
68 #include <CoreGraphics/CGBitmapContext.h>
69 #include <CoreGraphics/CGImage.h>
70 #include <OpenGL/OpenGL.h>
71 #else
72 #define FLIP_FRAMEBUFFER_VERTICALLY
73 #endif
74 
75 #if PLATFORM(SKIA)
76 #include "NativeImageSkia.h"
77 #endif
78 
79 #if OS(DARWIN)
80 #define USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER
81 #endif
82 
83 #if OS(LINUX)
84 #include <dlfcn.h>
85 #include "GL/glxew.h"
86 #endif
87 
88 using namespace std;
89 
90 namespace WebCore {
91 
92 // GraphicsContext3DInternal -----------------------------------------------------
93 
94 // Uncomment this to render to a separate window for debugging
95 // #define RENDER_TO_DEBUGGING_WINDOW
96 
97 #define EXTRACT(val) (!val ? 0 : val->object())
98 
99 class GraphicsContext3DInternal {
100 public:
101     GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs);
102     ~GraphicsContext3DInternal();
103 
104     bool makeContextCurrent();
105 
106     PlatformGraphicsContext3D platformGraphicsContext3D() const;
107     Platform3DObject platformTexture() const;
108 
109     void reshape(int width, int height);
110 
111     void beginPaint(WebGLRenderingContext* context);
112 
113     bool validateTextureTarget(int target);
114     bool validateTextureParameter(int param);
115 
116     void activeTexture(unsigned long texture);
117     void bindBuffer(unsigned long target,
118                     WebGLBuffer* buffer);
119     void bindFramebuffer(unsigned long target,
120                          WebGLFramebuffer* framebuffer);
121     void bindTexture(unsigned long target,
122                      WebGLTexture* texture);
123     void bufferDataImpl(unsigned long target, int size, const void* data, unsigned long usage);
124     void disableVertexAttribArray(unsigned long index);
125     void enableVertexAttribArray(unsigned long index);
126     unsigned long getError();
127     GraphicsContext3D::Attributes getContextAttributes();
128     void vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
129                              unsigned long stride, unsigned long offset);
130     void viewportImpl(long x, long y, unsigned long width, unsigned long height);
131 
132     void synthesizeGLError(unsigned long error);
133 
134 private:
135     GraphicsContext3D::Attributes m_attrs;
136 
137     unsigned int m_texture;
138     unsigned int m_fbo;
139     unsigned int m_depthBuffer;
140     unsigned int m_cachedWidth, m_cachedHeight;
141 
142     // For tracking which FBO is bound
143     unsigned int m_boundFBO;
144 
145 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
146     unsigned char* m_scanline;
147     void flipVertically(unsigned char* framebuffer,
148                         unsigned int width,
149                         unsigned int height);
150 #endif
151 
152     // Note: we aren't currently using this information, but we will
153     // need to in order to verify that all enabled vertex arrays have
154     // a valid buffer bound -- to avoid crashes on certain cards.
155     unsigned int m_boundArrayBuffer;
156     class VertexAttribPointerState {
157     public:
158         VertexAttribPointerState();
159 
160         bool enabled;
161         unsigned long buffer;
162         unsigned long indx;
163         int size;
164         int type;
165         bool normalized;
166         unsigned long stride;
167         unsigned long offset;
168     };
169 
170     enum {
171         NumTrackedPointerStates = 2
172     };
173     VertexAttribPointerState m_vertexAttribPointerState[NumTrackedPointerStates];
174 
175     // Errors raised by synthesizeGLError().
176     ListHashSet<unsigned long> m_syntheticErrors;
177 
178 #if PLATFORM(SKIA)
179     // If the width and height of the Canvas's backing store don't
180     // match those that we were given in the most recent call to
181     // reshape(), then we need an intermediate bitmap to read back the
182     // frame buffer into. This seems to happen when CSS styles are
183     // used to resize the Canvas.
184     SkBitmap* m_resizingBitmap;
185 #endif
186 
187     static bool s_initializedGLEW;
188 #if OS(WINDOWS)
189     HWND  m_canvasWindow;
190     HDC   m_canvasDC;
191     HGLRC m_contextObj;
192 #elif PLATFORM(CG)
193     CGLPBufferObj m_pbuffer;
194     CGLContextObj m_contextObj;
195     unsigned char* m_renderOutput;
196 #elif OS(LINUX)
197     GLXContext m_contextObj;
198     GLXPbuffer m_pbuffer;
199 
200     // In order to avoid problems caused by linking against libGL, we
201     // dynamically look up all the symbols we need.
202     // http://code.google.com/p/chromium/issues/detail?id=16800
203     class GLConnection {
204       public:
205         ~GLConnection();
206 
207         static GLConnection* create();
208 
chooseFBConfig(int screen,const int * attrib_list,int * nelements)209         GLXFBConfig* chooseFBConfig(int screen, const int *attrib_list, int *nelements)
210         {
211             return m_glXChooseFBConfig(m_display, screen, attrib_list, nelements);
212         }
213 
createNewContext(GLXFBConfig config,int renderType,GLXContext shareList,Bool direct)214         GLXContext createNewContext(GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)
215         {
216             return m_glXCreateNewContext(m_display, config, renderType, shareList, direct);
217         }
218 
createPbuffer(GLXFBConfig config,const int * attribList)219         GLXPbuffer createPbuffer(GLXFBConfig config, const int *attribList)
220         {
221             return m_glXCreatePbuffer(m_display, config, attribList);
222         }
223 
destroyPbuffer(GLXPbuffer pbuf)224         void destroyPbuffer(GLXPbuffer pbuf)
225         {
226             m_glXDestroyPbuffer(m_display, pbuf);
227         }
228 
makeCurrent(GLXDrawable drawable,GLXContext ctx)229         Bool makeCurrent(GLXDrawable drawable, GLXContext ctx)
230         {
231             return m_glXMakeCurrent(m_display, drawable, ctx);
232         }
233 
destroyContext(GLXContext ctx)234         void destroyContext(GLXContext ctx)
235         {
236             m_glXDestroyContext(m_display, ctx);
237         }
238 
getCurrentContext()239         GLXContext getCurrentContext()
240         {
241             return m_glXGetCurrentContext();
242         }
243 
244       private:
245         Display* m_display;
246         void* m_libGL;
247         PFNGLXCHOOSEFBCONFIGPROC m_glXChooseFBConfig;
248         PFNGLXCREATENEWCONTEXTPROC m_glXCreateNewContext;
249         PFNGLXCREATEPBUFFERPROC m_glXCreatePbuffer;
250         PFNGLXDESTROYPBUFFERPROC m_glXDestroyPbuffer;
251         typedef Bool (* PFNGLXMAKECURRENTPROC)(Display* dpy, GLXDrawable drawable, GLXContext ctx);
252         PFNGLXMAKECURRENTPROC m_glXMakeCurrent;
253         typedef void (* PFNGLXDESTROYCONTEXTPROC)(Display* dpy, GLXContext ctx);
254         PFNGLXDESTROYCONTEXTPROC m_glXDestroyContext;
255         typedef GLXContext (* PFNGLXGETCURRENTCONTEXTPROC)(void);
256         PFNGLXGETCURRENTCONTEXTPROC m_glXGetCurrentContext;
257 
GLConnection(Display * display,void * libGL,PFNGLXCHOOSEFBCONFIGPROC chooseFBConfig,PFNGLXCREATENEWCONTEXTPROC createNewContext,PFNGLXCREATEPBUFFERPROC createPbuffer,PFNGLXDESTROYPBUFFERPROC destroyPbuffer,PFNGLXMAKECURRENTPROC makeCurrent,PFNGLXDESTROYCONTEXTPROC destroyContext,PFNGLXGETCURRENTCONTEXTPROC getCurrentContext)258         GLConnection(Display* display,
259                      void* libGL,
260                      PFNGLXCHOOSEFBCONFIGPROC chooseFBConfig,
261                      PFNGLXCREATENEWCONTEXTPROC createNewContext,
262                      PFNGLXCREATEPBUFFERPROC createPbuffer,
263                      PFNGLXDESTROYPBUFFERPROC destroyPbuffer,
264                      PFNGLXMAKECURRENTPROC makeCurrent,
265                      PFNGLXDESTROYCONTEXTPROC destroyContext,
266                      PFNGLXGETCURRENTCONTEXTPROC getCurrentContext)
267             : m_libGL(libGL)
268             , m_display(display)
269             , m_glXChooseFBConfig(chooseFBConfig)
270             , m_glXCreateNewContext(createNewContext)
271             , m_glXCreatePbuffer(createPbuffer)
272             , m_glXDestroyPbuffer(destroyPbuffer)
273             , m_glXMakeCurrent(makeCurrent)
274             , m_glXDestroyContext(destroyContext)
275             , m_glXGetCurrentContext(getCurrentContext)
276         {
277         }
278     };
279 
280     static GLConnection* s_gl;
281 #else
282     #error Must port GraphicsContext3D to your platform
283 #endif
284 };
285 
286 bool GraphicsContext3DInternal::s_initializedGLEW = false;
287 
288 #if OS(LINUX)
289 GraphicsContext3DInternal::GLConnection* GraphicsContext3DInternal::s_gl = 0;
290 
create()291 GraphicsContext3DInternal::GLConnection* GraphicsContext3DInternal::GLConnection::create()
292 {
293     Display* dpy = XOpenDisplay(0);
294     if (!dpy) {
295         printf("GraphicsContext3D: error opening X display\n");
296         return 0;
297     }
298 
299     // We use RTLD_GLOBAL semantics so that GLEW initialization works;
300     // GLEW expects to be able to open the current process's handle
301     // and do dlsym's of GL entry points from there.
302     void* libGL = dlopen("libGL.so.1", RTLD_LAZY | RTLD_GLOBAL);
303     if (!libGL) {
304         XCloseDisplay(dpy);
305         printf("GraphicsContext3D: error opening libGL.so.1: %s\n", dlerror());
306         return 0;
307     }
308 
309     PFNGLXCHOOSEFBCONFIGPROC chooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) dlsym(libGL, "glXChooseFBConfig");
310     PFNGLXCREATENEWCONTEXTPROC createNewContext = (PFNGLXCREATENEWCONTEXTPROC) dlsym(libGL, "glXCreateNewContext");
311     PFNGLXCREATEPBUFFERPROC createPbuffer = (PFNGLXCREATEPBUFFERPROC) dlsym(libGL, "glXCreatePbuffer");
312     PFNGLXDESTROYPBUFFERPROC destroyPbuffer = (PFNGLXDESTROYPBUFFERPROC) dlsym(libGL, "glXDestroyPbuffer");
313     PFNGLXMAKECURRENTPROC makeCurrent = (PFNGLXMAKECURRENTPROC) dlsym(libGL, "glXMakeCurrent");
314     PFNGLXDESTROYCONTEXTPROC destroyContext = (PFNGLXDESTROYCONTEXTPROC) dlsym(libGL, "glXDestroyContext");
315     PFNGLXGETCURRENTCONTEXTPROC getCurrentContext = (PFNGLXGETCURRENTCONTEXTPROC) dlsym(libGL, "glXGetCurrentContext");
316     if (!chooseFBConfig || !createNewContext || !createPbuffer
317         || !destroyPbuffer || !makeCurrent || !destroyContext
318         || !getCurrentContext) {
319         XCloseDisplay(dpy);
320         dlclose(libGL);
321         printf("GraphicsContext3D: error looking up bootstrapping entry points\n");
322         return 0;
323     }
324     return new GLConnection(dpy,
325                             libGL,
326                             chooseFBConfig,
327                             createNewContext,
328                             createPbuffer,
329                             destroyPbuffer,
330                             makeCurrent,
331                             destroyContext,
332                             getCurrentContext);
333 }
334 
~GLConnection()335 GraphicsContext3DInternal::GLConnection::~GLConnection()
336 {
337     XCloseDisplay(m_display);
338     dlclose(m_libGL);
339 }
340 
341 #endif // OS(LINUX)
342 
VertexAttribPointerState()343 GraphicsContext3DInternal::VertexAttribPointerState::VertexAttribPointerState()
344     : enabled(false)
345     , buffer(0)
346     , indx(0)
347     , size(0)
348     , type(0)
349     , normalized(false)
350     , stride(0)
351     , offset(0)
352 {
353 }
354 
GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs)355 GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs)
356     : m_attrs(attrs)
357     , m_texture(0)
358     , m_fbo(0)
359     , m_depthBuffer(0)
360     , m_boundFBO(0)
361 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
362     , m_scanline(0)
363 #endif
364     , m_boundArrayBuffer(0)
365 #if PLATFORM(SKIA)
366     , m_resizingBitmap(0)
367 #endif
368 #if OS(WINDOWS)
369     , m_canvasWindow(0)
370     , m_canvasDC(0)
371     , m_contextObj(0)
372 #elif PLATFORM(CG)
373     , m_pbuffer(0)
374     , m_contextObj(0)
375     , m_renderOutput(0)
376 #elif OS(LINUX)
377     , m_contextObj(0)
378     , m_pbuffer(0)
379 #else
380 #error Must port to your platform
381 #endif
382 {
383     // FIXME: we need to take into account the user's requested
384     // context creation attributes, in particular stencil and
385     // antialias, and determine which could and could not be honored
386     // based on the capabilities of the OpenGL implementation.
387     m_attrs.alpha = true;
388     m_attrs.depth = true;
389     m_attrs.stencil = false;
390     m_attrs.antialias = false;
391     m_attrs.premultipliedAlpha = true;
392 
393 #if OS(WINDOWS)
394     WNDCLASS wc;
395     if (!GetClassInfo(GetModuleHandle(0), L"CANVASGL", &wc)) {
396         ZeroMemory(&wc, sizeof(WNDCLASS));
397         wc.style = CS_OWNDC;
398         wc.hInstance = GetModuleHandle(0);
399         wc.lpfnWndProc = DefWindowProc;
400         wc.lpszClassName = L"CANVASGL";
401 
402         if (!RegisterClass(&wc)) {
403             printf("GraphicsContext3D: RegisterClass failed\n");
404             return;
405         }
406     }
407 
408     m_canvasWindow = CreateWindow(L"CANVASGL", L"CANVASGL",
409                                   WS_CAPTION,
410                                   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
411                                   CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
412     if (!m_canvasWindow) {
413         printf("GraphicsContext3DInternal: CreateWindow failed\n");
414         return;
415     }
416 
417     // get the device context
418     m_canvasDC = GetDC(m_canvasWindow);
419     if (!m_canvasDC) {
420         printf("GraphicsContext3DInternal: GetDC failed\n");
421         return;
422     }
423 
424     // find default pixel format
425     PIXELFORMATDESCRIPTOR pfd;
426     ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
427     pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
428     pfd.nVersion = 1;
429     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL
430 #ifdef RENDER_TO_DEBUGGING_WINDOW
431         | PFD_DOUBLEBUFFER
432 #endif // RENDER_TO_DEBUGGING_WINDOW
433         ;
434     int pixelformat = ChoosePixelFormat(m_canvasDC, &pfd);
435 
436     // set the pixel format for the dc
437     if (!SetPixelFormat(m_canvasDC, pixelformat, &pfd)) {
438         printf("GraphicsContext3D: SetPixelFormat failed\n");
439         return;
440     }
441 
442     // create rendering context
443     m_contextObj = wglCreateContext(m_canvasDC);
444     if (!m_contextObj) {
445         printf("GraphicsContext3D: wglCreateContext failed\n");
446         return;
447     }
448 
449     if (!wglMakeCurrent(m_canvasDC, m_contextObj)) {
450         printf("GraphicsContext3D: wglMakeCurrent failed\n");
451         return;
452     }
453 
454 #ifdef RENDER_TO_DEBUGGING_WINDOW
455     typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval);
456     PFNWGLSWAPINTERVALEXTPROC setSwapInterval = 0;
457     setSwapInterval = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT");
458     if (setSwapInterval)
459         setSwapInterval(1);
460 #endif // RENDER_TO_DEBUGGING_WINDOW
461 
462 #elif PLATFORM(CG)
463     // Create a 1x1 pbuffer and associated context to bootstrap things
464     CGLPixelFormatAttribute attribs[] = {
465         (CGLPixelFormatAttribute) kCGLPFAPBuffer,
466         (CGLPixelFormatAttribute) 0
467     };
468     CGLPixelFormatObj pixelFormat;
469     GLint numPixelFormats;
470     if (CGLChoosePixelFormat(attribs, &pixelFormat, &numPixelFormats) != kCGLNoError) {
471         printf("GraphicsContext3D: error choosing pixel format\n");
472         return;
473     }
474     if (!pixelFormat) {
475         printf("GraphicsContext3D: no pixel format selected\n");
476         return;
477     }
478     CGLContextObj context;
479     CGLError res = CGLCreateContext(pixelFormat, 0, &context);
480     CGLDestroyPixelFormat(pixelFormat);
481     if (res != kCGLNoError) {
482         printf("GraphicsContext3D: error creating context\n");
483         return;
484     }
485     CGLPBufferObj pbuffer;
486     if (CGLCreatePBuffer(1, 1, GL_TEXTURE_2D, GL_RGBA, 0, &pbuffer) != kCGLNoError) {
487         CGLDestroyContext(context);
488         printf("GraphicsContext3D: error creating pbuffer\n");
489         return;
490     }
491     if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) {
492         CGLDestroyContext(context);
493         CGLDestroyPBuffer(pbuffer);
494         printf("GraphicsContext3D: error attaching pbuffer to context\n");
495         return;
496     }
497     if (CGLSetCurrentContext(context) != kCGLNoError) {
498         CGLDestroyContext(context);
499         CGLDestroyPBuffer(pbuffer);
500         printf("GraphicsContext3D: error making context current\n");
501         return;
502     }
503     m_pbuffer = pbuffer;
504     m_contextObj = context;
505 #elif OS(LINUX)
506     if (!s_gl) {
507         s_gl = GLConnection::create();
508         if (!s_gl)
509             return;
510     }
511 
512     int configAttrs[] = {
513         GLX_DRAWABLE_TYPE,
514         GLX_PBUFFER_BIT,
515         GLX_RENDER_TYPE,
516         GLX_RGBA_BIT,
517         GLX_DOUBLEBUFFER,
518         0,
519         0
520     };
521     int nelements = 0;
522     GLXFBConfig* config = s_gl->chooseFBConfig(0, configAttrs, &nelements);
523     if (!config) {
524         printf("GraphicsContext3D: glXChooseFBConfig failed\n");
525         return;
526     }
527     if (!nelements) {
528         printf("GraphicsContext3D: glXChooseFBConfig returned 0 elements\n");
529         XFree(config);
530         return;
531     }
532     GLXContext context = s_gl->createNewContext(config[0], GLX_RGBA_TYPE, 0, True);
533     if (!context) {
534         printf("GraphicsContext3D: glXCreateNewContext failed\n");
535         XFree(config);
536         return;
537     }
538     int pbufferAttrs[] = {
539         GLX_PBUFFER_WIDTH,
540         1,
541         GLX_PBUFFER_HEIGHT,
542         1,
543         0
544     };
545     GLXPbuffer pbuffer = s_gl->createPbuffer(config[0], pbufferAttrs);
546     XFree(config);
547     if (!pbuffer) {
548         printf("GraphicsContext3D: glxCreatePbuffer failed\n");
549         return;
550     }
551     if (!s_gl->makeCurrent(pbuffer, context)) {
552         printf("GraphicsContext3D: glXMakeCurrent failed\n");
553         return;
554     }
555     m_contextObj = context;
556     m_pbuffer = pbuffer;
557 #else
558 #error Must port to your platform
559 #endif
560 
561     if (!s_initializedGLEW) {
562         // Initialize GLEW and check for GL 2.0 support by the drivers.
563         GLenum glewInitResult = glewInit();
564         if (glewInitResult != GLEW_OK) {
565             printf("GraphicsContext3D: GLEW initialization failed\n");
566             return;
567         }
568         if (!glewIsSupported("GL_VERSION_2_0")) {
569             printf("GraphicsContext3D: OpenGL 2.0 not supported\n");
570             return;
571         }
572         s_initializedGLEW = true;
573     }
574 }
575 
~GraphicsContext3DInternal()576 GraphicsContext3DInternal::~GraphicsContext3DInternal()
577 {
578     makeContextCurrent();
579 #ifndef RENDER_TO_DEBUGGING_WINDOW
580     glDeleteRenderbuffersEXT(1, &m_depthBuffer);
581     glDeleteTextures(1, &m_texture);
582 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
583     if (m_scanline)
584         delete[] m_scanline;
585 #endif
586     glDeleteFramebuffersEXT(1, &m_fbo);
587 #endif // !RENDER_TO_DEBUGGING_WINDOW
588 #if PLATFORM(SKIA)
589     if (m_resizingBitmap)
590         delete m_resizingBitmap;
591 #endif
592 #if OS(WINDOWS)
593     wglMakeCurrent(0, 0);
594     wglDeleteContext(m_contextObj);
595     ReleaseDC(m_canvasWindow, m_canvasDC);
596     DestroyWindow(m_canvasWindow);
597 #elif PLATFORM(CG)
598     CGLSetCurrentContext(0);
599     CGLDestroyContext(m_contextObj);
600     CGLDestroyPBuffer(m_pbuffer);
601     if (m_renderOutput)
602         delete[] m_renderOutput;
603 #elif OS(LINUX)
604     s_gl->makeCurrent(0, 0);
605     s_gl->destroyContext(m_contextObj);
606     s_gl->destroyPbuffer(m_pbuffer);
607 #else
608 #error Must port to your platform
609 #endif
610     m_contextObj = 0;
611 }
612 
makeContextCurrent()613 bool GraphicsContext3DInternal::makeContextCurrent()
614 {
615 #if OS(WINDOWS)
616     if (wglGetCurrentContext() != m_contextObj)
617         if (wglMakeCurrent(m_canvasDC, m_contextObj))
618             return true;
619 #elif PLATFORM(CG)
620     if (CGLGetCurrentContext() != m_contextObj)
621         if (CGLSetCurrentContext(m_contextObj) == kCGLNoError)
622             return true;
623 #elif OS(LINUX)
624     if (s_gl->getCurrentContext() != m_contextObj)
625         if (s_gl->makeCurrent(m_pbuffer, m_contextObj))
626             return true;
627 #else
628 #error Must port to your platform
629 #endif
630     return false;
631 }
632 
platformGraphicsContext3D() const633 PlatformGraphicsContext3D GraphicsContext3DInternal::platformGraphicsContext3D() const
634 {
635     return m_contextObj;
636 }
637 
platformTexture() const638 Platform3DObject GraphicsContext3DInternal::platformTexture() const
639 {
640     return m_texture;
641 }
642 
createTextureObject(GLenum target)643 static int createTextureObject(GLenum target)
644 {
645     GLuint texture = 0;
646     glGenTextures(1, &texture);
647     glBindTexture(target, texture);
648     glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
649     glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
650     return texture;
651 }
652 
reshape(int width,int height)653 void GraphicsContext3DInternal::reshape(int width, int height)
654 {
655 #ifdef RENDER_TO_DEBUGGING_WINDOW
656     SetWindowPos(m_canvasWindow, HWND_TOP, 0, 0, width, height,
657                  SWP_NOMOVE);
658     ShowWindow(m_canvasWindow, SW_SHOW);
659 #endif
660 
661     m_cachedWidth = width;
662     m_cachedHeight = height;
663     makeContextCurrent();
664 
665 #ifndef RENDER_TO_DEBUGGING_WINDOW
666 #ifdef USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER
667     // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on Mac OS X
668     GLenum target = GL_TEXTURE_RECTANGLE_ARB;
669 #else
670     GLenum target = GL_TEXTURE_2D;
671 #endif
672     if (!m_texture) {
673         // Generate the texture object
674         m_texture = createTextureObject(target);
675         // Generate the framebuffer object
676         glGenFramebuffersEXT(1, &m_fbo);
677         // Generate the depth buffer
678         glGenRenderbuffersEXT(1, &m_depthBuffer);
679     }
680 
681     // Reallocate the color and depth buffers
682     glBindTexture(target, m_texture);
683     glTexImage2D(target, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
684     glBindTexture(target, 0);
685 
686     glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
687     m_boundFBO = m_fbo;
688     glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
689     glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
690     glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
691 
692     glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, m_texture, 0);
693     glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
694     GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
695     if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
696         printf("GraphicsContext3D: framebuffer was incomplete\n");
697 
698         // FIXME: cleanup.
699         notImplemented();
700     }
701 #endif  // RENDER_TO_DEBUGGING_WINDOW
702 
703 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
704     if (m_scanline) {
705         delete[] m_scanline;
706         m_scanline = 0;
707     }
708     m_scanline = new unsigned char[width * 4];
709 #endif  // FLIP_FRAMEBUFFER_VERTICALLY
710 
711     glClear(GL_COLOR_BUFFER_BIT);
712 
713 #if PLATFORM(CG)
714     // Need to reallocate the client-side backing store.
715     // FIXME: make this more efficient.
716     if (m_renderOutput) {
717         delete[] m_renderOutput;
718         m_renderOutput = 0;
719     }
720     int rowBytes = width * 4;
721     m_renderOutput = new unsigned char[height * rowBytes];
722 #endif  // PLATFORM(CG)
723 }
724 
725 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
flipVertically(unsigned char * framebuffer,unsigned int width,unsigned int height)726 void GraphicsContext3DInternal::flipVertically(unsigned char* framebuffer,
727                                                unsigned int width,
728                                                unsigned int height)
729 {
730     unsigned char* scanline = m_scanline;
731     if (!scanline)
732         return;
733     unsigned int rowBytes = width * 4;
734     unsigned int count = height / 2;
735     for (unsigned int i = 0; i < count; i++) {
736         unsigned char* rowA = framebuffer + i * rowBytes;
737         unsigned char* rowB = framebuffer + (height - i - 1) * rowBytes;
738         // FIXME: this is where the multiplication of the alpha
739         // channel into the color buffer will need to occur if the
740         // user specifies the "premultiplyAlpha" flag in the context
741         // creation attributes.
742         memcpy(scanline, rowB, rowBytes);
743         memcpy(rowB, rowA, rowBytes);
744         memcpy(rowA, scanline, rowBytes);
745     }
746 }
747 #endif
748 
beginPaint(WebGLRenderingContext * context)749 void GraphicsContext3DInternal::beginPaint(WebGLRenderingContext* context)
750 {
751     makeContextCurrent();
752 
753 #ifdef RENDER_TO_DEBUGGING_WINDOW
754     SwapBuffers(m_canvasDC);
755 #else
756     // Earlier versions of this code used the GPU to flip the
757     // framebuffer vertically before reading it back for compositing
758     // via software. This code was quite complicated, used a lot of
759     // GPU memory, and didn't provide an obvious speedup. Since this
760     // vertical flip is only a temporary solution anyway until Chrome
761     // is fully GPU composited, it wasn't worth the complexity.
762 
763     HTMLCanvasElement* canvas = context->canvas();
764     ImageBuffer* imageBuffer = canvas->buffer();
765     unsigned char* pixels = 0;
766     bool mustRestoreFBO = (m_boundFBO != m_fbo);
767     if (mustRestoreFBO)
768         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
769 #if PLATFORM(SKIA)
770     const SkBitmap* canvasBitmap = imageBuffer->context()->platformContext()->bitmap();
771     const SkBitmap* readbackBitmap = 0;
772     ASSERT(canvasBitmap->config() == SkBitmap::kARGB_8888_Config);
773     if (canvasBitmap->width() == m_cachedWidth && canvasBitmap->height() == m_cachedHeight) {
774         // This is the fastest and most common case. We read back
775         // directly into the canvas's backing store.
776         readbackBitmap = canvasBitmap;
777         if (m_resizingBitmap) {
778             delete m_resizingBitmap;
779             m_resizingBitmap = 0;
780         }
781     } else {
782         // We need to allocate a temporary bitmap for reading back the
783         // pixel data. We will then use Skia to rescale this bitmap to
784         // the size of the canvas's backing store.
785         if (m_resizingBitmap && (m_resizingBitmap->width() != m_cachedWidth || m_resizingBitmap->height() != m_cachedHeight)) {
786             delete m_resizingBitmap;
787             m_resizingBitmap = 0;
788         }
789         if (!m_resizingBitmap) {
790             m_resizingBitmap = new SkBitmap();
791             m_resizingBitmap->setConfig(SkBitmap::kARGB_8888_Config,
792                                         m_cachedWidth,
793                                         m_cachedHeight);
794             if (!m_resizingBitmap->allocPixels()) {
795                 delete m_resizingBitmap;
796                 m_resizingBitmap = 0;
797                 return;
798             }
799         }
800         readbackBitmap = m_resizingBitmap;
801     }
802 
803     // Read back the frame buffer.
804     SkAutoLockPixels bitmapLock(*readbackBitmap);
805     pixels = static_cast<unsigned char*>(readbackBitmap->getPixels());
806     glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_BYTE, pixels);
807 #elif PLATFORM(CG)
808     if (m_renderOutput) {
809         pixels = m_renderOutput;
810         glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
811     }
812 #else
813 #error Must port to your platform
814 #endif
815 
816     if (mustRestoreFBO)
817         glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_boundFBO);
818 
819 #ifdef FLIP_FRAMEBUFFER_VERTICALLY
820     if (pixels)
821         flipVertically(pixels, m_cachedWidth, m_cachedHeight);
822 #endif
823 
824 #if PLATFORM(SKIA)
825     if (m_resizingBitmap) {
826         // We need to draw the resizing bitmap into the canvas's backing store.
827         SkCanvas canvas(*canvasBitmap);
828         SkRect dst;
829         dst.set(0, 0, canvasBitmap->width(), canvasBitmap->height());
830         canvas.drawBitmapRect(*m_resizingBitmap, 0, dst);
831     }
832 #elif PLATFORM(CG)
833     if (m_renderOutput) {
834         int rowBytes = m_cachedWidth * 4;
835         CGDataProviderRef dataProvider = CGDataProviderCreateWithData(0, m_renderOutput, rowBytes * m_cachedHeight, 0);
836         CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
837         CGImageRef cgImage = CGImageCreate(m_cachedWidth,
838                                            m_cachedHeight,
839                                            8,
840                                            32,
841                                            rowBytes,
842                                            colorSpace,
843                                            kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
844                                            dataProvider,
845                                            0,
846                                            false,
847                                            kCGRenderingIntentDefault);
848         // CSS styling may cause the canvas's content to be resized on
849         // the page. Go back to the Canvas to figure out the correct
850         // width and height to draw.
851         CGRect rect = CGRectMake(0, 0,
852                                  context->canvas()->width(),
853                                  context->canvas()->height());
854         // We want to completely overwrite the previous frame's
855         // rendering results.
856         CGContextSetBlendMode(imageBuffer->context()->platformContext(),
857                               kCGBlendModeCopy);
858         CGContextSetInterpolationQuality(imageBuffer->context()->platformContext(),
859                                          kCGInterpolationNone);
860         CGContextDrawImage(imageBuffer->context()->platformContext(),
861                            rect, cgImage);
862         CGImageRelease(cgImage);
863         CGColorSpaceRelease(colorSpace);
864         CGDataProviderRelease(dataProvider);
865     }
866 #else
867 #error Must port to your platform
868 #endif
869 
870 #endif  // RENDER_TO_DEBUGGING_WINDOW
871 }
872 
activeTexture(unsigned long texture)873 void GraphicsContext3DInternal::activeTexture(unsigned long texture)
874 {
875     // FIXME: query number of textures available.
876     if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0+32)
877         // FIXME: raise exception.
878         return;
879 
880     makeContextCurrent();
881     glActiveTexture(texture);
882 }
883 
bindBuffer(unsigned long target,WebGLBuffer * buffer)884 void GraphicsContext3DInternal::bindBuffer(unsigned long target,
885                                            WebGLBuffer* buffer)
886 {
887     makeContextCurrent();
888     GLuint bufID = EXTRACT(buffer);
889     if (target == GL_ARRAY_BUFFER)
890         m_boundArrayBuffer = bufID;
891     glBindBuffer(target, bufID);
892 }
893 
bindFramebuffer(unsigned long target,WebGLFramebuffer * framebuffer)894 void GraphicsContext3DInternal::bindFramebuffer(unsigned long target,
895                                                 WebGLFramebuffer* framebuffer)
896 {
897     makeContextCurrent();
898     GLuint id = EXTRACT(framebuffer);
899     if (!id)
900         id = m_fbo;
901     glBindFramebufferEXT(target, id);
902     m_boundFBO = id;
903 }
904 
905 // If we didn't have to hack GL_TEXTURE_WRAP_R for cube maps,
906 // we could just use:
907 // GL_SAME_METHOD_2_X2(BindTexture, bindTexture, unsigned long, WebGLTexture*)
bindTexture(unsigned long target,WebGLTexture * texture)908 void GraphicsContext3DInternal::bindTexture(unsigned long target,
909                                             WebGLTexture* texture)
910 {
911     makeContextCurrent();
912     unsigned int textureObject = EXTRACT(texture);
913 
914     glBindTexture(target, textureObject);
915 
916     // FIXME: GL_TEXTURE_WRAP_R isn't exposed in the OpenGL ES 2.0
917     // API. On desktop OpenGL implementations it seems necessary to
918     // set this wrap mode to GL_CLAMP_TO_EDGE to get correct behavior
919     // of cube maps.
920     if (texture) {
921         if (target == GL_TEXTURE_CUBE_MAP) {
922             if (!texture->isCubeMapRWrapModeInitialized()) {
923                 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
924                 texture->setCubeMapRWrapModeInitialized(true);
925             }
926         } else
927             texture->setCubeMapRWrapModeInitialized(false);
928     }
929 }
930 
bufferDataImpl(unsigned long target,int size,const void * data,unsigned long usage)931 void GraphicsContext3DInternal::bufferDataImpl(unsigned long target, int size, const void* data, unsigned long usage)
932 {
933     makeContextCurrent();
934     // FIXME: make this verification more efficient.
935     GLint binding = 0;
936     GLenum binding_target = GL_ARRAY_BUFFER_BINDING;
937     if (target == GL_ELEMENT_ARRAY_BUFFER)
938         binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
939     glGetIntegerv(binding_target, &binding);
940     if (binding <= 0) {
941         // FIXME: raise exception.
942         // LogMessagef(("bufferData: no buffer bound"));
943         return;
944     }
945 
946     glBufferData(target,
947                    size,
948                    data,
949                    usage);
950 }
951 
disableVertexAttribArray(unsigned long index)952 void GraphicsContext3DInternal::disableVertexAttribArray(unsigned long index)
953 {
954     makeContextCurrent();
955     if (index < NumTrackedPointerStates)
956         m_vertexAttribPointerState[index].enabled = false;
957     glDisableVertexAttribArray(index);
958 }
959 
enableVertexAttribArray(unsigned long index)960 void GraphicsContext3DInternal::enableVertexAttribArray(unsigned long index)
961 {
962     makeContextCurrent();
963     if (index < NumTrackedPointerStates)
964         m_vertexAttribPointerState[index].enabled = true;
965     glEnableVertexAttribArray(index);
966 }
967 
getError()968 unsigned long GraphicsContext3DInternal::getError()
969 {
970     if (m_syntheticErrors.size() > 0) {
971         ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin();
972         unsigned long err = *iter;
973         m_syntheticErrors.remove(iter);
974         return err;
975     }
976 
977     makeContextCurrent();
978     return glGetError();
979 }
980 
getContextAttributes()981 GraphicsContext3D::Attributes GraphicsContext3DInternal::getContextAttributes()
982 {
983     return m_attrs;
984 }
985 
vertexAttribPointer(unsigned long indx,int size,int type,bool normalized,unsigned long stride,unsigned long offset)986 void GraphicsContext3DInternal::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
987                                                     unsigned long stride, unsigned long offset)
988 {
989     makeContextCurrent();
990 
991     if (m_boundArrayBuffer <= 0) {
992         // FIXME: raise exception.
993         // LogMessagef(("bufferData: no buffer bound"));
994         return;
995     }
996 
997     if (indx < NumTrackedPointerStates) {
998         VertexAttribPointerState& state = m_vertexAttribPointerState[indx];
999         state.buffer = m_boundArrayBuffer;
1000         state.indx = indx;
1001         state.size = size;
1002         state.type = type;
1003         state.normalized = normalized;
1004         state.stride = stride;
1005         state.offset = offset;
1006     }
1007 
1008     glVertexAttribPointer(indx, size, type, normalized, stride,
1009                           reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
1010 }
1011 
viewportImpl(long x,long y,unsigned long width,unsigned long height)1012 void GraphicsContext3DInternal::viewportImpl(long x, long y, unsigned long width, unsigned long height)
1013 {
1014     glViewport(x, y, width, height);
1015 }
1016 
synthesizeGLError(unsigned long error)1017 void GraphicsContext3DInternal::synthesizeGLError(unsigned long error)
1018 {
1019     m_syntheticErrors.add(error);
1020 }
1021 
1022 // GraphicsContext3D -----------------------------------------------------
1023 
1024 /* Helper macros for when we're just wrapping a gl method, so that
1025  * we can avoid having to type this 500 times.  Note that these MUST
1026  * NOT BE USED if we need to check any of the parameters.
1027  */
1028 
1029 #define GL_SAME_METHOD_0(glname, name)                                         \
1030 void GraphicsContext3D::name()                                                 \
1031 {                                                                              \
1032     makeContextCurrent();                                                      \
1033     gl##glname();                                                              \
1034 }
1035 
1036 #define GL_SAME_METHOD_1(glname, name, t1)                                     \
1037 void GraphicsContext3D::name(t1 a1)                                            \
1038 {                                                                              \
1039     makeContextCurrent();                                                      \
1040     gl##glname(a1);                                                            \
1041 }
1042 
1043 #define GL_SAME_METHOD_1_X(glname, name, t1)                                   \
1044 void GraphicsContext3D::name(t1 a1)                                            \
1045 {                                                                              \
1046     makeContextCurrent();                                                      \
1047     gl##glname(EXTRACT(a1));                                                   \
1048 }
1049 
1050 #define GL_SAME_METHOD_2(glname, name, t1, t2)                                 \
1051 void GraphicsContext3D::name(t1 a1, t2 a2)                                     \
1052 {                                                                              \
1053     makeContextCurrent();                                                      \
1054     gl##glname(a1, a2);                                                        \
1055 }
1056 
1057 #define GL_SAME_METHOD_2_X12(glname, name, t1, t2)                             \
1058 void GraphicsContext3D::name(t1 a1, t2 a2)                                     \
1059 {                                                                              \
1060     makeContextCurrent();                                                      \
1061     gl##glname(EXTRACT(a1), EXTRACT(a2));                                      \
1062 }
1063 
1064 #define GL_SAME_METHOD_2_X2(glname, name, t1, t2)                              \
1065 void GraphicsContext3D::name(t1 a1, t2 a2)                                     \
1066 {                                                                              \
1067     makeContextCurrent();                                                      \
1068     gl##glname(a1, EXTRACT(a2));                                               \
1069 }
1070 
1071 #define GL_SAME_METHOD_3(glname, name, t1, t2, t3)                             \
1072 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3)                              \
1073 {                                                                              \
1074     makeContextCurrent();                                                      \
1075     gl##glname(a1, a2, a3);                                                    \
1076 }
1077 
1078 #define GL_SAME_METHOD_3_X12(glname, name, t1, t2, t3)                         \
1079 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3)                              \
1080 {                                                                              \
1081     makeContextCurrent();                                                      \
1082     gl##glname(EXTRACT(a1), EXTRACT(a2), a3);                                  \
1083 }
1084 
1085 #define GL_SAME_METHOD_3_X2(glname, name, t1, t2, t3)                          \
1086 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3)                              \
1087 {                                                                              \
1088     makeContextCurrent();                                                      \
1089     gl##glname(a1, EXTRACT(a2), a3);                                           \
1090 }
1091 
1092 #define GL_SAME_METHOD_4(glname, name, t1, t2, t3, t4)                         \
1093 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4)                       \
1094 {                                                                              \
1095     makeContextCurrent();                                                      \
1096     gl##glname(a1, a2, a3, a4);                                                \
1097 }
1098 
1099 #define GL_SAME_METHOD_4_X4(glname, name, t1, t2, t3, t4)                      \
1100 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4)                       \
1101 {                                                                              \
1102     makeContextCurrent();                                                      \
1103     gl##glname(a1, a2, a3, EXTRACT(a4));                                       \
1104 }
1105 
1106 #define GL_SAME_METHOD_5(glname, name, t1, t2, t3, t4, t5)                     \
1107 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)                \
1108 {                                                                              \
1109     makeContextCurrent();                                                      \
1110     gl##glname(a1, a2, a3, a4, a5);                                            \
1111 }
1112 
1113 #define GL_SAME_METHOD_5_X4(glname, name, t1, t2, t3, t4, t5)                  \
1114 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)                \
1115 {                                                                              \
1116     makeContextCurrent();                                                      \
1117     gl##glname(a1, a2, a3, EXTRACT(a4), a5);                                   \
1118 }
1119 
1120 #define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6)                 \
1121 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6)         \
1122 {                                                                              \
1123     makeContextCurrent();                                                      \
1124     gl##glname(a1, a2, a3, a4, a5, a6);                                        \
1125 }
1126 
1127 #define GL_SAME_METHOD_8(glname, name, t1, t2, t3, t4, t5, t6, t7, t8)         \
1128 void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8)   \
1129 {                                                                              \
1130     makeContextCurrent();                                                      \
1131     gl##glname(a1, a2, a3, a4, a5, a6, a7, a8);                                \
1132 }
1133 
create(GraphicsContext3D::Attributes attrs)1134 PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs)
1135 {
1136     PassOwnPtr<GraphicsContext3D> context = new GraphicsContext3D(attrs);
1137     // FIXME: add error checking
1138     return context;
1139 }
1140 
GraphicsContext3D(GraphicsContext3D::Attributes attrs)1141 GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs)
1142     : m_currentWidth(0)
1143     , m_currentHeight(0)
1144     , m_internal(new GraphicsContext3DInternal(attrs))
1145 {
1146 }
1147 
~GraphicsContext3D()1148 GraphicsContext3D::~GraphicsContext3D()
1149 {
1150 }
1151 
platformGraphicsContext3D() const1152 PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() const
1153 {
1154     return m_internal->platformGraphicsContext3D();
1155 }
1156 
platformTexture() const1157 Platform3DObject GraphicsContext3D::platformTexture() const
1158 {
1159     return m_internal->platformTexture();
1160 }
1161 
makeContextCurrent()1162 void GraphicsContext3D::makeContextCurrent()
1163 {
1164     m_internal->makeContextCurrent();
1165 }
1166 
reshape(int width,int height)1167 void GraphicsContext3D::reshape(int width, int height)
1168 {
1169     if (width == m_currentWidth && height == m_currentHeight)
1170         return;
1171 
1172     m_currentWidth = width;
1173     m_currentHeight = height;
1174 
1175     m_internal->reshape(width, height);
1176 }
1177 
beginPaint(WebGLRenderingContext * context)1178 void GraphicsContext3D::beginPaint(WebGLRenderingContext* context)
1179 {
1180     m_internal->beginPaint(context);
1181 }
1182 
endPaint()1183 void GraphicsContext3D::endPaint()
1184 {
1185 }
1186 
sizeInBytes(int type)1187 int GraphicsContext3D::sizeInBytes(int type)
1188 {
1189     switch (type) {
1190     case GL_BYTE:
1191         return sizeof(GLbyte);
1192     case GL_UNSIGNED_BYTE:
1193         return sizeof(GLubyte);
1194     case GL_SHORT:
1195         return sizeof(GLshort);
1196     case GL_UNSIGNED_SHORT:
1197         return sizeof(GLushort);
1198     case GL_INT:
1199         return sizeof(GLint);
1200     case GL_UNSIGNED_INT:
1201         return sizeof(GLuint);
1202     case GL_FLOAT:
1203         return sizeof(GLfloat);
1204     default: // FIXME: default cases are discouraged in WebKit.
1205         return 0;
1206     }
1207 }
1208 
createBuffer()1209 unsigned GraphicsContext3D::createBuffer()
1210 {
1211     makeContextCurrent();
1212     GLuint o;
1213     glGenBuffers(1, &o);
1214     return o;
1215 }
1216 
createFramebuffer()1217 unsigned GraphicsContext3D::createFramebuffer()
1218 {
1219     makeContextCurrent();
1220     GLuint o = 0;
1221     glGenFramebuffersEXT(1, &o);
1222     return o;
1223 }
1224 
createProgram()1225 unsigned GraphicsContext3D::createProgram()
1226 {
1227     makeContextCurrent();
1228     return glCreateProgram();
1229 }
1230 
createRenderbuffer()1231 unsigned GraphicsContext3D::createRenderbuffer()
1232 {
1233     makeContextCurrent();
1234     GLuint o;
1235     glGenRenderbuffersEXT(1, &o);
1236     return o;
1237 }
1238 
createShader(unsigned long type)1239 unsigned GraphicsContext3D::createShader(unsigned long type)
1240 {
1241     makeContextCurrent();
1242     return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
1243 }
1244 
createTexture()1245 unsigned GraphicsContext3D::createTexture()
1246 {
1247     makeContextCurrent();
1248     GLuint o;
1249     glGenTextures(1, &o);
1250     return o;
1251 }
1252 
deleteBuffer(unsigned buffer)1253 void GraphicsContext3D::deleteBuffer(unsigned buffer)
1254 {
1255     makeContextCurrent();
1256     glDeleteBuffers(1, &buffer);
1257 }
1258 
deleteFramebuffer(unsigned framebuffer)1259 void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer)
1260 {
1261     makeContextCurrent();
1262     glDeleteFramebuffersEXT(1, &framebuffer);
1263 }
1264 
deleteProgram(unsigned program)1265 void GraphicsContext3D::deleteProgram(unsigned program)
1266 {
1267     makeContextCurrent();
1268     glDeleteProgram(program);
1269 }
1270 
deleteRenderbuffer(unsigned renderbuffer)1271 void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer)
1272 {
1273     makeContextCurrent();
1274     glDeleteRenderbuffersEXT(1, &renderbuffer);
1275 }
1276 
deleteShader(unsigned shader)1277 void GraphicsContext3D::deleteShader(unsigned shader)
1278 {
1279     makeContextCurrent();
1280     glDeleteShader(shader);
1281 }
1282 
deleteTexture(unsigned texture)1283 void GraphicsContext3D::deleteTexture(unsigned texture)
1284 {
1285     makeContextCurrent();
1286     glDeleteTextures(1, &texture);
1287 }
1288 
activeTexture(unsigned long texture)1289 void GraphicsContext3D::activeTexture(unsigned long texture)
1290 {
1291     m_internal->activeTexture(texture);
1292 }
1293 
GL_SAME_METHOD_2_X12(AttachShader,attachShader,WebGLProgram *,WebGLShader *)1294 GL_SAME_METHOD_2_X12(AttachShader, attachShader, WebGLProgram*, WebGLShader*)
1295 
1296 void GraphicsContext3D::bindAttribLocation(WebGLProgram* program,
1297                                            unsigned long index,
1298                                            const String& name)
1299 {
1300     if (!program)
1301         return;
1302     makeContextCurrent();
1303     glBindAttribLocation(EXTRACT(program), index, name.utf8().data());
1304 }
1305 
bindBuffer(unsigned long target,WebGLBuffer * buffer)1306 void GraphicsContext3D::bindBuffer(unsigned long target,
1307                                    WebGLBuffer* buffer)
1308 {
1309     m_internal->bindBuffer(target, buffer);
1310 }
1311 
bindFramebuffer(unsigned long target,WebGLFramebuffer * framebuffer)1312 void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* framebuffer)
1313 {
1314     m_internal->bindFramebuffer(target, framebuffer);
1315 }
1316 
GL_SAME_METHOD_2_X2(BindRenderbufferEXT,bindRenderbuffer,unsigned long,WebGLRenderbuffer *)1317 GL_SAME_METHOD_2_X2(BindRenderbufferEXT, bindRenderbuffer, unsigned long, WebGLRenderbuffer*)
1318 
1319 // If we didn't have to hack GL_TEXTURE_WRAP_R for cube maps,
1320 // we could just use:
1321 // GL_SAME_METHOD_2_X2(BindTexture, bindTexture, unsigned long, WebGLTexture*)
1322 void GraphicsContext3D::bindTexture(unsigned long target,
1323                                     WebGLTexture* texture)
1324 {
1325     m_internal->bindTexture(target, texture);
1326 }
1327 
GL_SAME_METHOD_4(BlendColor,blendColor,double,double,double,double)1328 GL_SAME_METHOD_4(BlendColor, blendColor, double, double, double, double)
1329 
1330 GL_SAME_METHOD_1(BlendEquation, blendEquation, unsigned long)
1331 
1332 GL_SAME_METHOD_2(BlendEquationSeparate, blendEquationSeparate, unsigned long, unsigned long)
1333 
1334 GL_SAME_METHOD_2(BlendFunc, blendFunc, unsigned long, unsigned long)
1335 
1336 GL_SAME_METHOD_4(BlendFuncSeparate, blendFuncSeparate, unsigned long, unsigned long, unsigned long, unsigned long)
1337 
1338 void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage)
1339 {
1340     m_internal->bufferDataImpl(target, size, 0, usage);
1341 }
1342 
bufferData(unsigned long target,WebGLArray * array,unsigned long usage)1343 void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage)
1344 {
1345     m_internal->bufferDataImpl(target, array->byteLength(), array->baseAddress(), usage);
1346 }
1347 
bufferSubData(unsigned long target,long offset,WebGLArray * array)1348 void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array)
1349 {
1350     if (!array || !array->length())
1351         return;
1352 
1353     makeContextCurrent();
1354     // FIXME: make this verification more efficient.
1355     GLint binding = 0;
1356     GLenum binding_target = GL_ARRAY_BUFFER_BINDING;
1357     if (target == GL_ELEMENT_ARRAY_BUFFER)
1358         binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
1359     glGetIntegerv(binding_target, &binding);
1360     if (binding <= 0) {
1361         // FIXME: raise exception.
1362         // LogMessagef(("bufferSubData: no buffer bound"));
1363         return;
1364     }
1365     glBufferSubData(target, offset, array->byteLength(), array->baseAddress());
1366 }
1367 
checkFramebufferStatus(unsigned long target)1368 unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target)
1369 {
1370     makeContextCurrent();
1371     return glCheckFramebufferStatusEXT(target);
1372 }
1373 
GL_SAME_METHOD_1(Clear,clear,unsigned long)1374 GL_SAME_METHOD_1(Clear, clear, unsigned long)
1375 
1376 GL_SAME_METHOD_4(ClearColor, clearColor, double, double, double, double)
1377 
1378 GL_SAME_METHOD_1(ClearDepth, clearDepth, double)
1379 
1380 GL_SAME_METHOD_1(ClearStencil, clearStencil, long)
1381 
1382 GL_SAME_METHOD_4(ColorMask, colorMask, bool, bool, bool, bool)
1383 
1384 GL_SAME_METHOD_1_X(CompileShader, compileShader, WebGLShader*)
1385 
1386 GL_SAME_METHOD_8(CopyTexImage2D, copyTexImage2D, unsigned long, long, unsigned long, long, long, unsigned long, unsigned long, long)
1387 
1388 GL_SAME_METHOD_8(CopyTexSubImage2D, copyTexSubImage2D, unsigned long, long, long, long, long, long, unsigned long, unsigned long)
1389 
1390 GL_SAME_METHOD_1(CullFace, cullFace, unsigned long)
1391 
1392 GL_SAME_METHOD_1(DepthFunc, depthFunc, unsigned long)
1393 
1394 GL_SAME_METHOD_1(DepthMask, depthMask, bool)
1395 
1396 GL_SAME_METHOD_2(DepthRange, depthRange, double, double)
1397 
1398 void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader)
1399 {
1400     if (!program || !shader)
1401         return;
1402 
1403     makeContextCurrent();
1404     glDetachShader(EXTRACT(program), EXTRACT(shader));
1405 }
1406 
GL_SAME_METHOD_1(Disable,disable,unsigned long)1407 GL_SAME_METHOD_1(Disable, disable, unsigned long)
1408 
1409 void GraphicsContext3D::disableVertexAttribArray(unsigned long index)
1410 {
1411     m_internal->disableVertexAttribArray(index);
1412 }
1413 
drawArrays(unsigned long mode,long first,long count)1414 void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count)
1415 {
1416     switch (mode) {
1417     case GL_TRIANGLES:
1418     case GL_TRIANGLE_STRIP:
1419     case GL_TRIANGLE_FAN:
1420     case GL_POINTS:
1421     case GL_LINE_STRIP:
1422     case GL_LINE_LOOP:
1423     case GL_LINES:
1424         break;
1425     default: // FIXME: default cases are discouraged in WebKit.
1426         // FIXME: output log message, raise exception.
1427         // LogMessage(NS_LITERAL_CSTRING("drawArrays: invalid mode"));
1428         // return NS_ERROR_DOM_SYNTAX_ERR;
1429         return;
1430     }
1431 
1432     if (first+count < first || first+count < count) {
1433         // FIXME: output log message, raise exception.
1434         // LogMessage(NS_LITERAL_CSTRING("drawArrays: overflow in first+count"));
1435         // return NS_ERROR_INVALID_ARG;
1436         return;
1437     }
1438 
1439     // FIXME: validate against currently bound buffer.
1440     // if (!ValidateBuffers(first+count))
1441     //     return NS_ERROR_INVALID_ARG;
1442 
1443     makeContextCurrent();
1444     glDrawArrays(mode, first, count);
1445 }
1446 
drawElements(unsigned long mode,unsigned long count,unsigned long type,long offset)1447 void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset)
1448 {
1449     makeContextCurrent();
1450     // FIXME: make this verification more efficient.
1451     GLint binding = 0;
1452     GLenum binding_target = GL_ELEMENT_ARRAY_BUFFER_BINDING;
1453     glGetIntegerv(binding_target, &binding);
1454     if (binding <= 0) {
1455         // FIXME: raise exception.
1456         // LogMessagef(("bufferData: no buffer bound"));
1457         return;
1458     }
1459     glDrawElements(mode, count, type,
1460                    reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
1461 }
1462 
GL_SAME_METHOD_1(Enable,enable,unsigned long)1463 GL_SAME_METHOD_1(Enable, enable, unsigned long)
1464 
1465 void GraphicsContext3D::enableVertexAttribArray(unsigned long index)
1466 {
1467     m_internal->enableVertexAttribArray(index);
1468 }
1469 
GL_SAME_METHOD_0(Finish,finish)1470 GL_SAME_METHOD_0(Finish, finish)
1471 
1472 GL_SAME_METHOD_0(Flush, flush)
1473 
1474 GL_SAME_METHOD_4_X4(FramebufferRenderbufferEXT, framebufferRenderbuffer, unsigned long, unsigned long, unsigned long, WebGLRenderbuffer*)
1475 
1476 GL_SAME_METHOD_5_X4(FramebufferTexture2DEXT, framebufferTexture2D, unsigned long, unsigned long, unsigned long, WebGLTexture*, long)
1477 
1478 GL_SAME_METHOD_1(FrontFace, frontFace, unsigned long)
1479 
1480 void GraphicsContext3D::generateMipmap(unsigned long target)
1481 {
1482     makeContextCurrent();
1483     if (glGenerateMipmapEXT)
1484         glGenerateMipmapEXT(target);
1485     // FIXME: provide alternative code path? This will be unpleasant
1486     // to implement if glGenerateMipmapEXT is not available -- it will
1487     // require a texture readback and re-upload.
1488 }
1489 
getActiveAttrib(WebGLProgram * program,unsigned long index,ActiveInfo & info)1490 bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info)
1491 {
1492     if (!program) {
1493         synthesizeGLError(INVALID_VALUE);
1494         return false;
1495     }
1496     GLint maxNameLength = -1;
1497     glGetProgramiv(EXTRACT(program), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength);
1498     if (maxNameLength < 0)
1499         return false;
1500     GLchar* name = 0;
1501     if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) {
1502         synthesizeGLError(OUT_OF_MEMORY);
1503         return false;
1504     }
1505     GLsizei length = 0;
1506     GLint size = -1;
1507     GLenum type = 0;
1508     glGetActiveAttrib(EXTRACT(program), index, maxNameLength,
1509                       &length, &size, &type, name);
1510     if (size < 0) {
1511         fastFree(name);
1512         return false;
1513     }
1514     info.name = String(name, length);
1515     info.type = type;
1516     info.size = size;
1517     fastFree(name);
1518     return true;
1519 }
1520 
getActiveUniform(WebGLProgram * program,unsigned long index,ActiveInfo & info)1521 bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info)
1522 {
1523     if (!program) {
1524         synthesizeGLError(INVALID_VALUE);
1525         return false;
1526     }
1527     GLint maxNameLength = -1;
1528     glGetProgramiv(EXTRACT(program), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength);
1529     if (maxNameLength < 0)
1530         return false;
1531     GLchar* name = 0;
1532     if (!tryFastMalloc(maxNameLength * sizeof(GLchar)).getValue(name)) {
1533         synthesizeGLError(OUT_OF_MEMORY);
1534         return false;
1535     }
1536     GLsizei length = 0;
1537     GLint size = -1;
1538     GLenum type = 0;
1539     glGetActiveUniform(EXTRACT(program), index, maxNameLength,
1540                        &length, &size, &type, name);
1541     if (size < 0) {
1542         fastFree(name);
1543         return false;
1544     }
1545     info.name = String(name, length);
1546     info.type = type;
1547     info.size = size;
1548     fastFree(name);
1549     return true;
1550 }
1551 
getAttribLocation(WebGLProgram * program,const String & name)1552 int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name)
1553 {
1554     if (!program)
1555         return -1;
1556 
1557     makeContextCurrent();
1558     return glGetAttribLocation(EXTRACT(program), name.utf8().data());
1559 }
1560 
getBooleanv(unsigned long pname,unsigned char * value)1561 void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value)
1562 {
1563     makeContextCurrent();
1564     glGetBooleanv(pname, value);
1565 }
1566 
getBufferParameteriv(unsigned long target,unsigned long pname,int * value)1567 void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value)
1568 {
1569     makeContextCurrent();
1570     glGetBufferParameteriv(target, pname, value);
1571 }
1572 
getContextAttributes()1573 GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
1574 {
1575     return m_internal->getContextAttributes();
1576 }
1577 
getError()1578 unsigned long GraphicsContext3D::getError()
1579 {
1580     return m_internal->getError();
1581 }
1582 
getFloatv(unsigned long pname,float * value)1583 void GraphicsContext3D::getFloatv(unsigned long pname, float* value)
1584 {
1585     makeContextCurrent();
1586     glGetFloatv(pname, value);
1587 }
1588 
getFramebufferAttachmentParameteriv(unsigned long target,unsigned long attachment,unsigned long pname,int * value)1589 void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target,
1590                                                             unsigned long attachment,
1591                                                             unsigned long pname,
1592                                                             int* value)
1593 {
1594     makeContextCurrent();
1595     glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value);
1596 }
1597 
getIntegerv(unsigned long pname,int * value)1598 void GraphicsContext3D::getIntegerv(unsigned long pname, int* value)
1599 {
1600     makeContextCurrent();
1601     glGetIntegerv(pname, value);
1602 }
1603 
getProgramiv(WebGLProgram * program,unsigned long pname,int * value)1604 void GraphicsContext3D::getProgramiv(WebGLProgram* program,
1605                                      unsigned long pname,
1606                                      int* value)
1607 {
1608     makeContextCurrent();
1609     glGetProgramiv(EXTRACT(program), pname, value);
1610 }
1611 
getProgramInfoLog(WebGLProgram * program)1612 String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program)
1613 {
1614     makeContextCurrent();
1615     GLuint programID = EXTRACT(program);
1616     GLint logLength;
1617     glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &logLength);
1618     if (!logLength)
1619         return String();
1620     GLchar* log = 0;
1621     if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
1622         return String();
1623     GLsizei returnedLogLength;
1624     glGetProgramInfoLog(programID, logLength, &returnedLogLength, log);
1625     ASSERT(logLength == returnedLogLength + 1);
1626     String res = String(log, returnedLogLength);
1627     fastFree(log);
1628     return res;
1629 }
1630 
getRenderbufferParameteriv(unsigned long target,unsigned long pname,int * value)1631 void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target,
1632                                                    unsigned long pname,
1633                                                    int* value)
1634 {
1635     makeContextCurrent();
1636     glGetRenderbufferParameterivEXT(target, pname, value);
1637 }
1638 
getShaderiv(WebGLShader * shader,unsigned long pname,int * value)1639 void GraphicsContext3D::getShaderiv(WebGLShader* shader,
1640                                     unsigned long pname,
1641                                     int* value)
1642 {
1643     makeContextCurrent();
1644     glGetShaderiv(EXTRACT(shader), pname, value);
1645 }
1646 
getShaderInfoLog(WebGLShader * shader)1647 String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader)
1648 {
1649     makeContextCurrent();
1650     GLuint shaderID = EXTRACT(shader);
1651     GLint logLength;
1652     glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLength);
1653     if (!logLength)
1654         return String();
1655     GLchar* log = 0;
1656     if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
1657         return String();
1658     GLsizei returnedLogLength;
1659     glGetShaderInfoLog(shaderID, logLength, &returnedLogLength, log);
1660     ASSERT(logLength == returnedLogLength + 1);
1661     String res = String(log, returnedLogLength);
1662     fastFree(log);
1663     return res;
1664 }
1665 
getShaderSource(WebGLShader * shader)1666 String GraphicsContext3D::getShaderSource(WebGLShader* shader)
1667 {
1668     makeContextCurrent();
1669     GLuint shaderID = EXTRACT(shader);
1670     GLint logLength;
1671     glGetShaderiv(shaderID, GL_SHADER_SOURCE_LENGTH, &logLength);
1672     if (!logLength)
1673         return String();
1674     GLchar* log = 0;
1675     if (!tryFastMalloc(logLength * sizeof(GLchar)).getValue(log))
1676         return String();
1677     GLsizei returnedLogLength;
1678     glGetShaderSource(shaderID, logLength, &returnedLogLength, log);
1679     ASSERT(logLength == returnedLogLength + 1);
1680     String res = String(log, returnedLogLength);
1681     fastFree(log);
1682     return res;
1683 }
1684 
getString(unsigned long name)1685 String GraphicsContext3D::getString(unsigned long name)
1686 {
1687     makeContextCurrent();
1688     return String(reinterpret_cast<const char*>(glGetString(name)));
1689 }
1690 
getTexParameterfv(unsigned long target,unsigned long pname,float * value)1691 void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value)
1692 {
1693     makeContextCurrent();
1694     glGetTexParameterfv(target, pname, value);
1695 }
1696 
getTexParameteriv(unsigned long target,unsigned long pname,int * value)1697 void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value)
1698 {
1699     makeContextCurrent();
1700     glGetTexParameteriv(target, pname, value);
1701 }
1702 
getUniformfv(WebGLProgram * program,long location,float * value)1703 void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value)
1704 {
1705     makeContextCurrent();
1706     glGetUniformfv(EXTRACT(program), location, value);
1707 }
1708 
getUniformiv(WebGLProgram * program,long location,int * value)1709 void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value)
1710 {
1711     makeContextCurrent();
1712     glGetUniformiv(EXTRACT(program), location, value);
1713 }
1714 
getUniformLocation(WebGLProgram * program,const String & name)1715 long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name)
1716 {
1717     if (!program)
1718         return -1;
1719 
1720     makeContextCurrent();
1721     return glGetUniformLocation(EXTRACT(program), name.utf8().data());
1722 }
1723 
getVertexAttribfv(unsigned long index,unsigned long pname,float * value)1724 void GraphicsContext3D::getVertexAttribfv(unsigned long index,
1725                                           unsigned long pname,
1726                                           float* value)
1727 {
1728     makeContextCurrent();
1729     glGetVertexAttribfv(index, pname, value);
1730 }
1731 
getVertexAttribiv(unsigned long index,unsigned long pname,int * value)1732 void GraphicsContext3D::getVertexAttribiv(unsigned long index,
1733                                           unsigned long pname,
1734                                           int* value)
1735 {
1736     makeContextCurrent();
1737     glGetVertexAttribiv(index, pname, value);
1738 }
1739 
getVertexAttribOffset(unsigned long index,unsigned long pname)1740 long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname)
1741 {
1742     // FIXME: implement.
1743     notImplemented();
1744     return 0;
1745 }
1746 
1747 GL_SAME_METHOD_2(Hint, hint, unsigned long, unsigned long);
1748 
isBuffer(WebGLBuffer * buffer)1749 bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer)
1750 {
1751     makeContextCurrent();
1752     return glIsBuffer(EXTRACT(buffer));
1753 }
1754 
isEnabled(unsigned long cap)1755 bool GraphicsContext3D::isEnabled(unsigned long cap)
1756 {
1757     makeContextCurrent();
1758     return glIsEnabled(cap);
1759 }
1760 
isFramebuffer(WebGLFramebuffer * framebuffer)1761 bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer)
1762 {
1763     makeContextCurrent();
1764     return glIsFramebufferEXT(EXTRACT(framebuffer));
1765 }
1766 
isProgram(WebGLProgram * program)1767 bool GraphicsContext3D::isProgram(WebGLProgram* program)
1768 {
1769     makeContextCurrent();
1770     return glIsProgram(EXTRACT(program));
1771 }
1772 
isRenderbuffer(WebGLRenderbuffer * renderbuffer)1773 bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
1774 {
1775     makeContextCurrent();
1776     return glIsRenderbufferEXT(EXTRACT(renderbuffer));
1777 }
1778 
isShader(WebGLShader * shader)1779 bool GraphicsContext3D::isShader(WebGLShader* shader)
1780 {
1781     makeContextCurrent();
1782     return glIsShader(EXTRACT(shader));
1783 }
1784 
isTexture(WebGLTexture * texture)1785 bool GraphicsContext3D::isTexture(WebGLTexture* texture)
1786 {
1787     makeContextCurrent();
1788     return glIsTexture(EXTRACT(texture));
1789 }
1790 
GL_SAME_METHOD_1(LineWidth,lineWidth,double)1791 GL_SAME_METHOD_1(LineWidth, lineWidth, double)
1792 
1793 GL_SAME_METHOD_1_X(LinkProgram, linkProgram, WebGLProgram*)
1794 
1795 void GraphicsContext3D::pixelStorei(unsigned long pname, long param)
1796 {
1797     if (pname != GL_PACK_ALIGNMENT && pname != GL_UNPACK_ALIGNMENT) {
1798         // FIXME: Create a fake GL error and throw an exception.
1799         return;
1800     }
1801 
1802     makeContextCurrent();
1803     glPixelStorei(pname, param);
1804 }
1805 
GL_SAME_METHOD_2(PolygonOffset,polygonOffset,double,double)1806 GL_SAME_METHOD_2(PolygonOffset, polygonOffset, double, double)
1807 
1808 PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y,
1809                                                       unsigned long width, unsigned long height,
1810                                                       unsigned long format, unsigned long type) {
1811     // FIXME: support more pixel formats and types.
1812     if (!((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)))
1813         return 0;
1814 
1815     // FIXME: take into account pack alignment.
1816     RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4);
1817     glReadPixels(x, y, width, height, format, type, array->baseAddress());
1818     return array;
1819 }
1820 
releaseShaderCompiler()1821 void GraphicsContext3D::releaseShaderCompiler()
1822 {
1823 }
1824 
GL_SAME_METHOD_4(RenderbufferStorageEXT,renderbufferStorage,unsigned long,unsigned long,unsigned long,unsigned long)1825 GL_SAME_METHOD_4(RenderbufferStorageEXT, renderbufferStorage, unsigned long, unsigned long, unsigned long, unsigned long)
1826 
1827 GL_SAME_METHOD_2(SampleCoverage, sampleCoverage, double, bool)
1828 
1829 GL_SAME_METHOD_4(Scissor, scissor, long, long, unsigned long, unsigned long)
1830 
1831 void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& source)
1832 {
1833     makeContextCurrent();
1834     CString str = source.utf8();
1835     const char* data = str.data();
1836     GLint length = str.length();
1837     glShaderSource(EXTRACT(shader), 1, &data, &length);
1838 }
1839 
GL_SAME_METHOD_3(StencilFunc,stencilFunc,unsigned long,long,unsigned long)1840 GL_SAME_METHOD_3(StencilFunc, stencilFunc, unsigned long, long, unsigned long)
1841 
1842 GL_SAME_METHOD_4(StencilFuncSeparate, stencilFuncSeparate, unsigned long, unsigned long, long, unsigned long)
1843 
1844 GL_SAME_METHOD_1(StencilMask, stencilMask, unsigned long)
1845 
1846 GL_SAME_METHOD_2(StencilMaskSeparate, stencilMaskSeparate, unsigned long, unsigned long)
1847 
1848 GL_SAME_METHOD_3(StencilOp, stencilOp, unsigned long, unsigned long, unsigned long)
1849 
1850 GL_SAME_METHOD_4(StencilOpSeparate, stencilOpSeparate, unsigned long, unsigned long, unsigned long, unsigned long)
1851 
1852 void GraphicsContext3D::synthesizeGLError(unsigned long error)
1853 {
1854     m_internal->synthesizeGLError(error);
1855 }
1856 
texImage2D(unsigned target,unsigned level,unsigned internalformat,unsigned width,unsigned height,unsigned border,unsigned format,unsigned type,void * pixels)1857 int GraphicsContext3D::texImage2D(unsigned target,
1858                                   unsigned level,
1859                                   unsigned internalformat,
1860                                   unsigned width,
1861                                   unsigned height,
1862                                   unsigned border,
1863                                   unsigned format,
1864                                   unsigned type,
1865                                   void* pixels)
1866 {
1867     // FIXME: must do validation similar to JOGL's to ensure that
1868     // the incoming array is of the appropriate length.
1869     glTexImage2D(target,
1870                  level,
1871                  internalformat,
1872                  width,
1873                  height,
1874                  border,
1875                  format,
1876                  type,
1877                  pixels);
1878     return 0;
1879 }
1880 
1881 // Remove premultiplied alpha from color channels.
1882 // FIXME: this is lossy. Must retrieve original values from HTMLImageElement.
unmultiplyAlpha(unsigned char * rgbaData,int numPixels)1883 static void unmultiplyAlpha(unsigned char* rgbaData, int numPixels)
1884 {
1885     for (int j = 0; j < numPixels; j++) {
1886         float b = rgbaData[4*j+0] / 255.0f;
1887         float g = rgbaData[4*j+1] / 255.0f;
1888         float r = rgbaData[4*j+2] / 255.0f;
1889         float a = rgbaData[4*j+3] / 255.0f;
1890         if (a > 0.0f) {
1891             b /= a;
1892             g /= a;
1893             r /= a;
1894             b = (b > 1.0f) ? 1.0f : b;
1895             g = (g > 1.0f) ? 1.0f : g;
1896             r = (r > 1.0f) ? 1.0f : r;
1897             rgbaData[4*j+0] = (unsigned char) (b * 255.0f);
1898             rgbaData[4*j+1] = (unsigned char) (g * 255.0f);
1899             rgbaData[4*j+2] = (unsigned char) (r * 255.0f);
1900         }
1901     }
1902 }
1903 
1904 // FIXME: this must be changed to refer to the original image data
1905 // rather than unmultiplying the alpha channel.
texImage2DHelper(unsigned target,unsigned level,int width,int height,int rowBytes,bool flipY,bool premultiplyAlpha,GLenum format,bool skipAlpha,unsigned char * pixels)1906 static int texImage2DHelper(unsigned target, unsigned level,
1907                             int width, int height,
1908                             int rowBytes,
1909                             bool flipY,
1910                             bool premultiplyAlpha,
1911                             GLenum format,
1912                             bool skipAlpha,
1913                             unsigned char* pixels)
1914 {
1915     ASSERT(format == GL_RGBA || format == GL_BGRA);
1916     GLint internalFormat = GL_RGBA8;
1917     if (skipAlpha) {
1918         internalFormat = GL_RGB8;
1919         // Ignore the alpha channel
1920         premultiplyAlpha = true;
1921     }
1922     if (flipY) {
1923         // Need to flip images vertically. To avoid making a copy of
1924         // the entire image, we perform a ton of glTexSubImage2D
1925         // calls. FIXME: should rethink this strategy for efficiency.
1926         glTexImage2D(target, level, internalFormat,
1927                      width,
1928                      height,
1929                      0,
1930                      format,
1931                      GL_UNSIGNED_BYTE,
1932                      0);
1933         unsigned char* row = 0;
1934         bool allocatedRow = false;
1935         if (!premultiplyAlpha) {
1936             row = new unsigned char[rowBytes];
1937             allocatedRow = true;
1938         }
1939         for (int i = 0; i < height; i++) {
1940             if (premultiplyAlpha)
1941                 row = pixels + (rowBytes * i);
1942             else {
1943                 memcpy(row, pixels + (rowBytes * i), rowBytes);
1944                 unmultiplyAlpha(row, width);
1945             }
1946             glTexSubImage2D(target, level, 0, height - i - 1,
1947                             width, 1,
1948                             format,
1949                             GL_UNSIGNED_BYTE,
1950                             row);
1951         }
1952         if (allocatedRow)
1953             delete[] row;
1954     } else {
1955         // The pixels of cube maps' faces are defined with a top-down
1956         // scanline ordering, unlike GL_TEXTURE_2D, so when uploading
1957         // these, the above vertical flip is the wrong thing to do.
1958         if (premultiplyAlpha)
1959             glTexImage2D(target, level, internalFormat,
1960                          width,
1961                          height,
1962                          0,
1963                          format,
1964                          GL_UNSIGNED_BYTE,
1965                          pixels);
1966         else {
1967             glTexImage2D(target, level, internalFormat,
1968                          width,
1969                          height,
1970                          0,
1971                          format,
1972                          GL_UNSIGNED_BYTE,
1973                          0);
1974             unsigned char* row = new unsigned char[rowBytes];
1975             for (int i = 0; i < height; i++) {
1976                 memcpy(row, pixels + (rowBytes * i), rowBytes);
1977                 unmultiplyAlpha(row, width);
1978                 glTexSubImage2D(target, level, 0, i,
1979                                 width, 1,
1980                                 format,
1981                                 GL_UNSIGNED_BYTE,
1982                                 row);
1983             }
1984             delete[] row;
1985         }
1986     }
1987     return 0;
1988 }
1989 
texImage2D(unsigned target,unsigned level,Image * image,bool flipY,bool premultiplyAlpha)1990 int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image,
1991                                   bool flipY, bool premultiplyAlpha)
1992 {
1993     ASSERT(image);
1994 
1995     int res = -1;
1996 #if PLATFORM(SKIA)
1997     NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame();
1998     if (!skiaImage) {
1999         ASSERT_NOT_REACHED();
2000         return -1;
2001     }
2002     SkBitmap::Config skiaConfig = skiaImage->config();
2003     // FIXME: must support more image configurations.
2004     if (skiaConfig != SkBitmap::kARGB_8888_Config) {
2005         ASSERT_NOT_REACHED();
2006         return -1;
2007     }
2008     SkBitmap& skiaImageRef = *skiaImage;
2009     SkAutoLockPixels lock(skiaImageRef);
2010     int width = skiaImage->width();
2011     int height = skiaImage->height();
2012     unsigned char* pixels =
2013         reinterpret_cast<unsigned char*>(skiaImage->getPixels());
2014     int rowBytes = skiaImage->rowBytes();
2015     res = texImage2DHelper(target, level,
2016                            width, height,
2017                            rowBytes,
2018                            flipY, premultiplyAlpha,
2019                            GL_BGRA,
2020                            false,
2021                            pixels);
2022 #elif PLATFORM(CG)
2023     CGImageRef cgImage = image->nativeImageForCurrentFrame();
2024     if (!cgImage) {
2025         ASSERT_NOT_REACHED();
2026         return -1;
2027     }
2028     int width = CGImageGetWidth(cgImage);
2029     int height = CGImageGetHeight(cgImage);
2030     int rowBytes = width * 4;
2031     CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage);
2032     bool skipAlpha = (info == kCGImageAlphaNone
2033                    || info == kCGImageAlphaNoneSkipLast
2034                    || info == kCGImageAlphaNoneSkipFirst);
2035     unsigned char* imageData = new unsigned char[height * rowBytes];
2036     CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
2037     CGContextRef tmpContext = CGBitmapContextCreate(imageData, width, height, 8, rowBytes,
2038                                                     colorSpace,
2039                                                     kCGImageAlphaPremultipliedLast);
2040     CGColorSpaceRelease(colorSpace);
2041     CGContextSetBlendMode(tmpContext, kCGBlendModeCopy);
2042     CGContextDrawImage(tmpContext,
2043                        CGRectMake(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height)),
2044                        cgImage);
2045     CGContextRelease(tmpContext);
2046     res = texImage2DHelper(target, level, width, height, rowBytes,
2047                            flipY, premultiplyAlpha, GL_RGBA, skipAlpha, imageData);
2048     delete[] imageData;
2049 #else
2050 #error Must port to your platform
2051 #endif
2052     return res;
2053 }
2054 
2055 GL_SAME_METHOD_3(TexParameterf, texParameterf, unsigned, unsigned, float);
2056 
2057 GL_SAME_METHOD_3(TexParameteri, texParameteri, unsigned, unsigned, int);
2058 
texSubImage2D(unsigned target,unsigned level,unsigned xoffset,unsigned yoffset,unsigned width,unsigned height,unsigned format,unsigned type,void * pixels)2059 int GraphicsContext3D::texSubImage2D(unsigned target,
2060                                      unsigned level,
2061                                      unsigned xoffset,
2062                                      unsigned yoffset,
2063                                      unsigned width,
2064                                      unsigned height,
2065                                      unsigned format,
2066                                      unsigned type,
2067                                      void* pixels)
2068 {
2069     glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
2070     return 0;
2071 }
2072 
texSubImage2D(unsigned target,unsigned level,unsigned xoffset,unsigned yoffset,Image * image,bool flipY,bool premultiplyAlpha)2073 int GraphicsContext3D::texSubImage2D(unsigned target,
2074                                      unsigned level,
2075                                      unsigned xoffset,
2076                                      unsigned yoffset,
2077                                      Image* image,
2078                                      bool flipY,
2079                                      bool premultiplyAlpha)
2080 {
2081     // FIXME: implement.
2082     notImplemented();
2083     return -1;
2084 }
2085 
GL_SAME_METHOD_2(Uniform1f,uniform1f,long,float)2086 GL_SAME_METHOD_2(Uniform1f, uniform1f, long, float)
2087 
2088 void GraphicsContext3D::uniform1fv(long location, float* v, int size)
2089 {
2090     makeContextCurrent();
2091     glUniform1fv(location, size, v);
2092 }
2093 
GL_SAME_METHOD_2(Uniform1i,uniform1i,long,int)2094 GL_SAME_METHOD_2(Uniform1i, uniform1i, long, int)
2095 
2096 void GraphicsContext3D::uniform1iv(long location, int* v, int size)
2097 {
2098     makeContextCurrent();
2099     glUniform1iv(location, size, v);
2100 }
2101 
GL_SAME_METHOD_3(Uniform2f,uniform2f,long,float,float)2102 GL_SAME_METHOD_3(Uniform2f, uniform2f, long, float, float)
2103 
2104 void GraphicsContext3D::uniform2fv(long location, float* v, int size)
2105 {
2106     makeContextCurrent();
2107     glUniform2fv(location, size, v);
2108 }
2109 
GL_SAME_METHOD_3(Uniform2i,uniform2i,long,int,int)2110 GL_SAME_METHOD_3(Uniform2i, uniform2i, long, int, int)
2111 
2112 void GraphicsContext3D::uniform2iv(long location, int* v, int size)
2113 {
2114     makeContextCurrent();
2115     glUniform2iv(location, size, v);
2116 }
2117 
GL_SAME_METHOD_4(Uniform3f,uniform3f,long,float,float,float)2118 GL_SAME_METHOD_4(Uniform3f, uniform3f, long, float, float, float)
2119 
2120 void GraphicsContext3D::uniform3fv(long location, float* v, int size)
2121 {
2122     makeContextCurrent();
2123     glUniform3fv(location, size, v);
2124 }
2125 
GL_SAME_METHOD_4(Uniform3i,uniform3i,long,int,int,int)2126 GL_SAME_METHOD_4(Uniform3i, uniform3i, long, int, int, int)
2127 
2128 void GraphicsContext3D::uniform3iv(long location, int* v, int size)
2129 {
2130     makeContextCurrent();
2131     glUniform3iv(location, size, v);
2132 }
2133 
GL_SAME_METHOD_5(Uniform4f,uniform4f,long,float,float,float,float)2134 GL_SAME_METHOD_5(Uniform4f, uniform4f, long, float, float, float, float)
2135 
2136 void GraphicsContext3D::uniform4fv(long location, float* v, int size)
2137 {
2138     makeContextCurrent();
2139     glUniform4fv(location, size, v);
2140 }
2141 
GL_SAME_METHOD_5(Uniform4i,uniform4i,long,int,int,int,int)2142 GL_SAME_METHOD_5(Uniform4i, uniform4i, long, int, int, int, int)
2143 
2144 void GraphicsContext3D::uniform4iv(long location, int* v, int size)
2145 {
2146     makeContextCurrent();
2147     glUniform4iv(location, size, v);
2148 }
2149 
uniformMatrix2fv(long location,bool transpose,float * value,int size)2150 void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* value, int size)
2151 {
2152     makeContextCurrent();
2153     glUniformMatrix2fv(location, size, transpose, value);
2154 }
2155 
uniformMatrix3fv(long location,bool transpose,float * value,int size)2156 void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* value, int size)
2157 {
2158     makeContextCurrent();
2159     glUniformMatrix3fv(location, size, transpose, value);
2160 }
2161 
uniformMatrix4fv(long location,bool transpose,float * value,int size)2162 void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* value, int size)
2163 {
2164     makeContextCurrent();
2165     glUniformMatrix4fv(location, size, transpose, value);
2166 }
2167 
GL_SAME_METHOD_1_X(UseProgram,useProgram,WebGLProgram *)2168 GL_SAME_METHOD_1_X(UseProgram, useProgram, WebGLProgram*)
2169 
2170 GL_SAME_METHOD_1_X(ValidateProgram, validateProgram, WebGLProgram*)
2171 
2172 GL_SAME_METHOD_2(VertexAttrib1f, vertexAttrib1f, unsigned long, float)
2173 
2174 void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* values)
2175 {
2176     makeContextCurrent();
2177     glVertexAttrib1fv(indx, values);
2178 }
2179 
GL_SAME_METHOD_3(VertexAttrib2f,vertexAttrib2f,unsigned long,float,float)2180 GL_SAME_METHOD_3(VertexAttrib2f, vertexAttrib2f, unsigned long, float, float)
2181 
2182 void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* values)
2183 {
2184     makeContextCurrent();
2185     glVertexAttrib2fv(indx, values);
2186 }
2187 
GL_SAME_METHOD_4(VertexAttrib3f,vertexAttrib3f,unsigned long,float,float,float)2188 GL_SAME_METHOD_4(VertexAttrib3f, vertexAttrib3f, unsigned long, float, float, float)
2189 
2190 void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* values)
2191 {
2192     makeContextCurrent();
2193     glVertexAttrib3fv(indx, values);
2194 }
2195 
GL_SAME_METHOD_5(VertexAttrib4f,vertexAttrib4f,unsigned long,float,float,float,float)2196 GL_SAME_METHOD_5(VertexAttrib4f, vertexAttrib4f, unsigned long, float, float, float, float)
2197 
2198 void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* values)
2199 {
2200     makeContextCurrent();
2201     glVertexAttrib4fv(indx, values);
2202 }
2203 
vertexAttribPointer(unsigned long indx,int size,int type,bool normalized,unsigned long stride,unsigned long offset)2204 void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized,
2205                                             unsigned long stride, unsigned long offset)
2206 {
2207     m_internal->vertexAttribPointer(indx, size, type, normalized, stride, offset);
2208 }
2209 
viewport(long x,long y,unsigned long width,unsigned long height)2210 void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned long height)
2211 {
2212     makeContextCurrent();
2213     m_internal->viewportImpl(x, y, width, height);
2214 }
2215 
2216 }
2217 
2218 #endif // ENABLE(3D_CANVAS)
2219