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 |