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