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