Home | History | Annotate | Download | only in src
      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 
    209         GLXFBConfig* chooseFBConfig(int screen, const int *attrib_list, int *nelements)
    210         {
    211             return m_glXChooseFBConfig(m_display, screen, attrib_list, nelements);
    212         }
    213 
    214         GLXContext createNewContext(GLXFBConfig config, int renderType, GLXContext shareList, Bool direct)
    215         {
    216             return m_glXCreateNewContext(m_display, config, renderType, shareList, direct);
    217         }
    218 
    219         GLXPbuffer createPbuffer(GLXFBConfig config, const int *attribList)
    220         {
    221             return m_glXCreatePbuffer(m_display, config, attribList);
    222         }
    223 
    224         void destroyPbuffer(GLXPbuffer pbuf)
    225         {
    226             m_glXDestroyPbuffer(m_display, pbuf);
    227         }
    228 
    229         Bool makeCurrent(GLXDrawable drawable, GLXContext ctx)
    230         {
    231             return m_glXMakeCurrent(m_display, drawable, ctx);
    232         }
    233 
    234         void destroyContext(GLXContext ctx)
    235         {
    236             m_glXDestroyContext(m_display, ctx);
    237         }
    238 
    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 
    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 
    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 
    335 GraphicsContext3DInternal::GLConnection::~GLConnection()
    336 {
    337     XCloseDisplay(m_display);
    338     dlclose(m_libGL);
    339 }
    340 
    341 #endif // OS(LINUX)
    342 
    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 
    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 
    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 
    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 
    633 PlatformGraphicsContext3D GraphicsContext3DInternal::platformGraphicsContext3D() const
    634 {
    635     return m_contextObj;
    636 }
    637 
    638 Platform3DObject GraphicsContext3DInternal::platformTexture() const
    639 {
    640     return m_texture;
    641 }
    642 
    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 
    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
    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 
    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 
    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 
    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 
    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*)
    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 
    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 
    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 
    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 
    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 
    981 GraphicsContext3D::Attributes GraphicsContext3DInternal::getContextAttributes()
    982 {
    983     return m_attrs;
    984 }
    985 
    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 
   1012 void GraphicsContext3DInternal::viewportImpl(long x, long y, unsigned long width, unsigned long height)
   1013 {
   1014     glViewport(x, y, width, height);
   1015 }
   1016 
   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 
   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 
   1141 GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs)
   1142     : m_currentWidth(0)
   1143     , m_currentHeight(0)
   1144     , m_internal(new GraphicsContext3DInternal(attrs))
   1145 {
   1146 }
   1147 
   1148 GraphicsContext3D::~GraphicsContext3D()
   1149 {
   1150 }
   1151 
   1152 PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() const
   1153 {
   1154     return m_internal->platformGraphicsContext3D();
   1155 }
   1156 
   1157 Platform3DObject GraphicsContext3D::platformTexture() const
   1158 {
   1159     return m_internal->platformTexture();
   1160 }
   1161 
   1162 void GraphicsContext3D::makeContextCurrent()
   1163 {
   1164     m_internal->makeContextCurrent();
   1165 }
   1166 
   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 
   1178 void GraphicsContext3D::beginPaint(WebGLRenderingContext* context)
   1179 {
   1180     m_internal->beginPaint(context);
   1181 }
   1182 
   1183 void GraphicsContext3D::endPaint()
   1184 {
   1185 }
   1186 
   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 
   1209 unsigned GraphicsContext3D::createBuffer()
   1210 {
   1211     makeContextCurrent();
   1212     GLuint o;
   1213     glGenBuffers(1, &o);
   1214     return o;
   1215 }
   1216 
   1217 unsigned GraphicsContext3D::createFramebuffer()
   1218 {
   1219     makeContextCurrent();
   1220     GLuint o = 0;
   1221     glGenFramebuffersEXT(1, &o);
   1222     return o;
   1223 }
   1224 
   1225 unsigned GraphicsContext3D::createProgram()
   1226 {
   1227     makeContextCurrent();
   1228     return glCreateProgram();
   1229 }
   1230 
   1231 unsigned GraphicsContext3D::createRenderbuffer()
   1232 {
   1233     makeContextCurrent();
   1234     GLuint o;
   1235     glGenRenderbuffersEXT(1, &o);
   1236     return o;
   1237 }
   1238 
   1239 unsigned GraphicsContext3D::createShader(unsigned long type)
   1240 {
   1241     makeContextCurrent();
   1242     return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
   1243 }
   1244 
   1245 unsigned GraphicsContext3D::createTexture()
   1246 {
   1247     makeContextCurrent();
   1248     GLuint o;
   1249     glGenTextures(1, &o);
   1250     return o;
   1251 }
   1252 
   1253 void GraphicsContext3D::deleteBuffer(unsigned buffer)
   1254 {
   1255     makeContextCurrent();
   1256     glDeleteBuffers(1, &buffer);
   1257 }
   1258 
   1259 void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer)
   1260 {
   1261     makeContextCurrent();
   1262     glDeleteFramebuffersEXT(1, &framebuffer);
   1263 }
   1264 
   1265 void GraphicsContext3D::deleteProgram(unsigned program)
   1266 {
   1267     makeContextCurrent();
   1268     glDeleteProgram(program);
   1269 }
   1270 
   1271 void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer)
   1272 {
   1273     makeContextCurrent();
   1274     glDeleteRenderbuffersEXT(1, &renderbuffer);
   1275 }
   1276 
   1277 void GraphicsContext3D::deleteShader(unsigned shader)
   1278 {
   1279     makeContextCurrent();
   1280     glDeleteShader(shader);
   1281 }
   1282 
   1283 void GraphicsContext3D::deleteTexture(unsigned texture)
   1284 {
   1285     makeContextCurrent();
   1286     glDeleteTextures(1, &texture);
   1287 }
   1288 
   1289 void GraphicsContext3D::activeTexture(unsigned long texture)
   1290 {
   1291     m_internal->activeTexture(texture);
   1292 }
   1293 
   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 
   1306 void GraphicsContext3D::bindBuffer(unsigned long target,
   1307                                    WebGLBuffer* buffer)
   1308 {
   1309     m_internal->bindBuffer(target, buffer);
   1310 }
   1311 
   1312 void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* framebuffer)
   1313 {
   1314     m_internal->bindFramebuffer(target, framebuffer);
   1315 }
   1316 
   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 
   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 
   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 
   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 
   1368 unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target)
   1369 {
   1370     makeContextCurrent();
   1371     return glCheckFramebufferStatusEXT(target);
   1372 }
   1373 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1561 void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value)
   1562 {
   1563     makeContextCurrent();
   1564     glGetBooleanv(pname, value);
   1565 }
   1566 
   1567 void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value)
   1568 {
   1569     makeContextCurrent();
   1570     glGetBufferParameteriv(target, pname, value);
   1571 }
   1572 
   1573 GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
   1574 {
   1575     return m_internal->getContextAttributes();
   1576 }
   1577 
   1578 unsigned long GraphicsContext3D::getError()
   1579 {
   1580     return m_internal->getError();
   1581 }
   1582 
   1583 void GraphicsContext3D::getFloatv(unsigned long pname, float* value)
   1584 {
   1585     makeContextCurrent();
   1586     glGetFloatv(pname, value);
   1587 }
   1588 
   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 
   1598 void GraphicsContext3D::getIntegerv(unsigned long pname, int* value)
   1599 {
   1600     makeContextCurrent();
   1601     glGetIntegerv(pname, value);
   1602 }
   1603 
   1604 void GraphicsContext3D::getProgramiv(WebGLProgram* program,
   1605                                      unsigned long pname,
   1606                                      int* value)
   1607 {
   1608     makeContextCurrent();
   1609     glGetProgramiv(EXTRACT(program), pname, value);
   1610 }
   1611 
   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 
   1631 void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target,
   1632                                                    unsigned long pname,
   1633                                                    int* value)
   1634 {
   1635     makeContextCurrent();
   1636     glGetRenderbufferParameterivEXT(target, pname, value);
   1637 }
   1638 
   1639 void GraphicsContext3D::getShaderiv(WebGLShader* shader,
   1640                                     unsigned long pname,
   1641                                     int* value)
   1642 {
   1643     makeContextCurrent();
   1644     glGetShaderiv(EXTRACT(shader), pname, value);
   1645 }
   1646 
   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 
   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 
   1685 String GraphicsContext3D::getString(unsigned long name)
   1686 {
   1687     makeContextCurrent();
   1688     return String(reinterpret_cast<const char*>(glGetString(name)));
   1689 }
   1690 
   1691 void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value)
   1692 {
   1693     makeContextCurrent();
   1694     glGetTexParameterfv(target, pname, value);
   1695 }
   1696 
   1697 void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value)
   1698 {
   1699     makeContextCurrent();
   1700     glGetTexParameteriv(target, pname, value);
   1701 }
   1702 
   1703 void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value)
   1704 {
   1705     makeContextCurrent();
   1706     glGetUniformfv(EXTRACT(program), location, value);
   1707 }
   1708 
   1709 void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value)
   1710 {
   1711     makeContextCurrent();
   1712     glGetUniformiv(EXTRACT(program), location, value);
   1713 }
   1714 
   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 
   1724 void GraphicsContext3D::getVertexAttribfv(unsigned long index,
   1725                                           unsigned long pname,
   1726                                           float* value)
   1727 {
   1728     makeContextCurrent();
   1729     glGetVertexAttribfv(index, pname, value);
   1730 }
   1731 
   1732 void GraphicsContext3D::getVertexAttribiv(unsigned long index,
   1733                                           unsigned long pname,
   1734                                           int* value)
   1735 {
   1736     makeContextCurrent();
   1737     glGetVertexAttribiv(index, pname, value);
   1738 }
   1739 
   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 
   1749 bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer)
   1750 {
   1751     makeContextCurrent();
   1752     return glIsBuffer(EXTRACT(buffer));
   1753 }
   1754 
   1755 bool GraphicsContext3D::isEnabled(unsigned long cap)
   1756 {
   1757     makeContextCurrent();
   1758     return glIsEnabled(cap);
   1759 }
   1760 
   1761 bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer)
   1762 {
   1763     makeContextCurrent();
   1764     return glIsFramebufferEXT(EXTRACT(framebuffer));
   1765 }
   1766 
   1767 bool GraphicsContext3D::isProgram(WebGLProgram* program)
   1768 {
   1769     makeContextCurrent();
   1770     return glIsProgram(EXTRACT(program));
   1771 }
   1772 
   1773 bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
   1774 {
   1775     makeContextCurrent();
   1776     return glIsRenderbufferEXT(EXTRACT(renderbuffer));
   1777 }
   1778 
   1779 bool GraphicsContext3D::isShader(WebGLShader* shader)
   1780 {
   1781     makeContextCurrent();
   1782     return glIsShader(EXTRACT(shader));
   1783 }
   1784 
   1785 bool GraphicsContext3D::isTexture(WebGLTexture* texture)
   1786 {
   1787     makeContextCurrent();
   1788     return glIsTexture(EXTRACT(texture));
   1789 }
   1790 
   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 
   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 
   1821 void GraphicsContext3D::releaseShaderCompiler()
   1822 {
   1823 }
   1824 
   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 
   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 
   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.
   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.
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2150 void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* value, int size)
   2151 {
   2152     makeContextCurrent();
   2153     glUniformMatrix2fv(location, size, transpose, value);
   2154 }
   2155 
   2156 void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* value, int size)
   2157 {
   2158     makeContextCurrent();
   2159     glUniformMatrix3fv(location, size, transpose, value);
   2160 }
   2161 
   2162 void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* value, int size)
   2163 {
   2164     makeContextCurrent();
   2165     glUniformMatrix4fv(location, size, transpose, value);
   2166 }
   2167 
   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 
   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 
   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 
   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 
   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 
   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