1 /*
2 * Copyright (C) 2009 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27
28 #if ENABLE(WEBGL)
29
30 #include "WebGLRenderingContext.h"
31
32 #include "CachedImage.h"
33 #include "CanvasPixelArray.h"
34 #include "CheckedInt.h"
35 #include "WebKitLoseContext.h"
36 #include "Console.h"
37 #include "DOMWindow.h"
38 #include "Extensions3D.h"
39 #include "FrameView.h"
40 #include "HTMLCanvasElement.h"
41 #include "HTMLImageElement.h"
42 #include "HTMLVideoElement.h"
43 #include "ImageBuffer.h"
44 #include "ImageData.h"
45 #include "IntSize.h"
46 #include "NotImplemented.h"
47 #include "OESStandardDerivatives.h"
48 #include "OESTextureFloat.h"
49 #include "OESVertexArrayObject.h"
50 #include "RenderBox.h"
51 #include "RenderLayer.h"
52 #include "Settings.h"
53 #include "Uint16Array.h"
54 #include "WebGLActiveInfo.h"
55 #include "WebGLBuffer.h"
56 #include "WebGLContextAttributes.h"
57 #include "WebGLContextEvent.h"
58 #include "WebGLFramebuffer.h"
59 #include "WebGLProgram.h"
60 #include "WebGLRenderbuffer.h"
61 #include "WebGLShader.h"
62 #include "WebGLTexture.h"
63 #include "WebGLUniformLocation.h"
64
65 #include <wtf/ByteArray.h>
66 #include <wtf/OwnArrayPtr.h>
67 #include <wtf/PassOwnArrayPtr.h>
68 #include <wtf/text/StringBuilder.h>
69
70 #if PLATFORM(QT)
71 #undef emit
72 #endif
73
74 namespace WebCore {
75
76 const double secondsBetweenRestoreAttempts = 1.0;
77
78 namespace {
79
objectOrZero(WebGLObject * object)80 Platform3DObject objectOrZero(WebGLObject* object)
81 {
82 return object ? object->object() : 0;
83 }
84
clip1D(GC3Dint start,GC3Dsizei range,GC3Dsizei sourceRange,GC3Dint * clippedStart,GC3Dsizei * clippedRange)85 void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
86 {
87 ASSERT(clippedStart && clippedRange);
88 if (start < 0) {
89 range += start;
90 start = 0;
91 }
92 GC3Dint end = start + range;
93 if (end > sourceRange)
94 range -= end - sourceRange;
95 *clippedStart = start;
96 *clippedRange = range;
97 }
98
99 // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
clip2D(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Dsizei sourceWidth,GC3Dsizei sourceHeight,GC3Dint * clippedX,GC3Dint * clippedY,GC3Dsizei * clippedWidth,GC3Dsizei * clippedHeight)100 bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
101 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
102 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
103 {
104 ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
105 clip1D(x, width, sourceWidth, clippedX, clippedWidth);
106 clip1D(y, height, sourceHeight, clippedY, clippedHeight);
107 return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
108 }
109
110 // Return true if a character belongs to the ASCII subset as defined in
111 // GLSL ES 1.0 spec section 3.1.
validateCharacter(unsigned char c)112 bool validateCharacter(unsigned char c)
113 {
114 // Printing characters are valid except " $ ` @ \ ' DEL.
115 if (c >= 32 && c <= 126
116 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
117 return true;
118 // Horizontal tab, line feed, vertical tab, form feed, carriage return
119 // are also valid.
120 if (c >= 9 && c <= 13)
121 return true;
122 return false;
123 }
124
125 // Strips comments from shader text. This allows non-ASCII characters
126 // to be used in comments without potentially breaking OpenGL
127 // implementations not expecting characters outside the GLSL ES set.
128 class StripComments {
129 public:
StripComments(const String & str)130 StripComments(const String& str)
131 : m_parseState(BeginningOfLine)
132 , m_sourceString(str)
133 , m_length(str.length())
134 , m_position(0)
135 {
136 parse();
137 }
138
result()139 String result()
140 {
141 return m_builder.toString();
142 }
143
144 private:
hasMoreCharacters()145 bool hasMoreCharacters()
146 {
147 return (m_position < m_length);
148 }
149
parse()150 void parse()
151 {
152 while (hasMoreCharacters()) {
153 process(current());
154 // process() might advance the position.
155 if (hasMoreCharacters())
156 advance();
157 }
158 }
159
160 void process(UChar);
161
peek(UChar & character)162 bool peek(UChar& character)
163 {
164 if (m_position + 1 >= m_length)
165 return false;
166 character = m_sourceString[m_position + 1];
167 return true;
168 }
169
current()170 UChar current()
171 {
172 ASSERT(m_position < m_length);
173 return m_sourceString[m_position];
174 }
175
advance()176 void advance()
177 {
178 ++m_position;
179 }
180
isNewline(UChar character)181 bool isNewline(UChar character)
182 {
183 // Don't attempt to canonicalize newline related characters.
184 return (character == '\n' || character == '\r');
185 }
186
emit(UChar character)187 void emit(UChar character)
188 {
189 m_builder.append(character);
190 }
191
192 enum ParseState {
193 // Have not seen an ASCII non-whitespace character yet on
194 // this line. Possible that we might see a preprocessor
195 // directive.
196 BeginningOfLine,
197
198 // Have seen at least one ASCII non-whitespace character
199 // on this line.
200 MiddleOfLine,
201
202 // Handling a preprocessor directive. Passes through all
203 // characters up to the end of the line. Disables comment
204 // processing.
205 InPreprocessorDirective,
206
207 // Handling a single-line comment. The comment text is
208 // replaced with a single space.
209 InSingleLineComment,
210
211 // Handling a multi-line comment. Newlines are passed
212 // through to preserve line numbers.
213 InMultiLineComment
214 };
215
216 ParseState m_parseState;
217 String m_sourceString;
218 unsigned m_length;
219 unsigned m_position;
220 StringBuilder m_builder;
221 };
222
process(UChar c)223 void StripComments::process(UChar c)
224 {
225 if (isNewline(c)) {
226 // No matter what state we are in, pass through newlines
227 // so we preserve line numbers.
228 emit(c);
229
230 if (m_parseState != InMultiLineComment)
231 m_parseState = BeginningOfLine;
232
233 return;
234 }
235
236 UChar temp = 0;
237 switch (m_parseState) {
238 case BeginningOfLine:
239 if (WTF::isASCIISpace(c)) {
240 emit(c);
241 break;
242 }
243
244 if (c == '#') {
245 m_parseState = InPreprocessorDirective;
246 emit(c);
247 break;
248 }
249
250 // Transition to normal state and re-handle character.
251 m_parseState = MiddleOfLine;
252 process(c);
253 break;
254
255 case MiddleOfLine:
256 if (c == '/' && peek(temp)) {
257 if (temp == '/') {
258 m_parseState = InSingleLineComment;
259 emit(' ');
260 advance();
261 break;
262 }
263
264 if (temp == '*') {
265 m_parseState = InMultiLineComment;
266 // Emit the comment start in case the user has
267 // an unclosed comment and we want to later
268 // signal an error.
269 emit('/');
270 emit('*');
271 advance();
272 break;
273 }
274 }
275
276 emit(c);
277 break;
278
279 case InPreprocessorDirective:
280 // No matter what the character is, just pass it
281 // through. Do not parse comments in this state. This
282 // might not be the right thing to do long term, but it
283 // should handle the #error preprocessor directive.
284 emit(c);
285 break;
286
287 case InSingleLineComment:
288 // The newline code at the top of this function takes care
289 // of resetting our state when we get out of the
290 // single-line comment. Swallow all other characters.
291 break;
292
293 case InMultiLineComment:
294 if (c == '*' && peek(temp) && temp == '/') {
295 emit('*');
296 emit('/');
297 m_parseState = MiddleOfLine;
298 advance();
299 break;
300 }
301
302 // Swallow all other characters. Unclear whether we may
303 // want or need to just emit a space per character to try
304 // to preserve column numbers for debugging purposes.
305 break;
306 }
307 }
308 } // namespace anonymous
309
310 class WebGLStateRestorer {
311 public:
WebGLStateRestorer(WebGLRenderingContext * context,bool changed)312 WebGLStateRestorer(WebGLRenderingContext* context,
313 bool changed)
314 : m_context(context)
315 , m_changed(changed)
316 {
317 }
318
~WebGLStateRestorer()319 ~WebGLStateRestorer()
320 {
321 m_context->cleanupAfterGraphicsCall(m_changed);
322 }
323
324 private:
325 WebGLRenderingContext* m_context;
326 bool m_changed;
327 };
328
fired()329 void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired()
330 {
331 // Timer is started when m_contextLost is false. It will first call
332 // onLostContext, which will set m_contextLost to true. Then it will keep
333 // calling restoreContext and reschedule itself until m_contextLost is back
334 // to false.
335 if (!m_context->m_contextLost) {
336 m_context->onLostContext();
337 startOneShot(secondsBetweenRestoreAttempts);
338 } else {
339 // The rendering context is not restored if there is no handler for
340 // the context restored event.
341 if (!m_context->canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent))
342 return;
343
344 m_context->restoreContext();
345 if (m_context->m_contextLost)
346 startOneShot(secondsBetweenRestoreAttempts);
347 }
348 }
349
350 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
351 public:
WebGLRenderingContextLostCallback(WebGLRenderingContext * cb)352 WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_contextLostCallback(cb) {}
onContextLost()353 virtual void onContextLost() { m_contextLostCallback->forceLostContext(); }
~WebGLRenderingContextLostCallback()354 virtual ~WebGLRenderingContextLostCallback() {}
355 private:
356 WebGLRenderingContext* m_contextLostCallback;
357 };
358
create(HTMLCanvasElement * canvas,WebGLContextAttributes * attrs)359 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
360 {
361 HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
362 GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
363
364 if (attributes.antialias) {
365 Page* p = canvas->document()->page();
366 if (p && !p->settings()->openGLMultisamplingEnabled())
367 attributes.antialias = false;
368 }
369
370 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
371
372 if (!context) {
373 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
374 return 0;
375 }
376
377 return new WebGLRenderingContext(canvas, context, attributes);
378 }
379
WebGLRenderingContext(HTMLCanvasElement * passedCanvas,PassRefPtr<GraphicsContext3D> context,GraphicsContext3D::Attributes attributes)380 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
381 GraphicsContext3D::Attributes attributes)
382 : CanvasRenderingContext(passedCanvas)
383 , m_context(context)
384 , m_restoreTimer(this)
385 , m_videoCache(4)
386 , m_contextLost(false)
387 , m_attributes(attributes)
388 {
389 ASSERT(m_context);
390 setupFlags();
391 initializeNewContext();
392 }
393
initializeNewContext()394 void WebGLRenderingContext::initializeNewContext()
395 {
396 ASSERT(!m_contextLost);
397 m_needsUpdate = true;
398 m_markedCanvasDirty = false;
399 m_activeTextureUnit = 0;
400 m_packAlignment = 4;
401 m_unpackAlignment = 4;
402 m_unpackFlipY = false;
403 m_unpackPremultiplyAlpha = false;
404 m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
405 m_boundArrayBuffer = 0;
406 m_currentProgram = 0;
407 m_framebufferBinding = 0;
408 m_renderbufferBinding = 0;
409 m_stencilMask = 0xFFFFFFFF;
410 m_stencilMaskBack = 0xFFFFFFFF;
411 m_stencilFuncRef = 0;
412 m_stencilFuncRefBack = 0;
413 m_stencilFuncMask = 0xFFFFFFFF;
414 m_stencilFuncMaskBack = 0xFFFFFFFF;
415 m_layerCleared = false;
416
417 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
418 m_scissorEnabled = false;
419 m_clearDepth = 1;
420 m_clearStencil = 0;
421 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
422
423 GC3Dint numCombinedTextureImageUnits = 0;
424 m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
425 m_textureUnits.clear();
426 m_textureUnits.resize(numCombinedTextureImageUnits);
427
428 GC3Dint numVertexAttribs = 0;
429 m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
430 m_maxVertexAttribs = numVertexAttribs;
431
432 m_maxTextureSize = 0;
433 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
434 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
435 m_maxCubeMapTextureSize = 0;
436 m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
437 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
438
439 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
440 addObject(m_defaultVertexArrayObject.get());
441 m_boundVertexArrayObject = m_defaultVertexArrayObject;
442
443 m_vertexAttribValue.resize(m_maxVertexAttribs);
444
445 if (!isGLES2NPOTStrict())
446 createFallbackBlackTextures1x1();
447 if (!isGLES2Compliant())
448 initVertexAttrib0();
449
450 m_context->reshape(canvas()->width(), canvas()->height());
451 m_context->viewport(0, 0, canvas()->width(), canvas()->height());
452
453 m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
454 }
455
setupFlags()456 void WebGLRenderingContext::setupFlags()
457 {
458 ASSERT(m_context);
459
460 m_isGLES2Compliant = m_context->isGLES2Compliant();
461 m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
462 m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
463 if (m_isGLES2Compliant) {
464 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
465 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
466 } else {
467 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
468 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
469 }
470 }
471
~WebGLRenderingContext()472 WebGLRenderingContext::~WebGLRenderingContext()
473 {
474 detachAndRemoveAllObjects();
475 m_context->setContextLostCallback(0);
476 if (m_webkitLoseContext)
477 m_webkitLoseContext->contextDestroyed();
478 }
479
markContextChanged()480 void WebGLRenderingContext::markContextChanged()
481 {
482 if (m_framebufferBinding)
483 return;
484 m_context->markContextChanged();
485 m_layerCleared = false;
486 #if USE(ACCELERATED_COMPOSITING)
487 RenderBox* renderBox = canvas()->renderBox();
488 if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing())
489 renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
490 else {
491 #endif
492 if (!m_markedCanvasDirty)
493 canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
494 #if USE(ACCELERATED_COMPOSITING)
495 }
496 #endif
497 m_markedCanvasDirty = true;
498 }
499
clearIfComposited(GC3Dbitfield mask)500 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
501 {
502 if (isContextLost())
503 return false;
504
505 if (!m_context->layerComposited() || m_layerCleared
506 || m_attributes.preserveDrawingBuffer || m_framebufferBinding)
507 return false;
508
509 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
510
511 // Determine if it's possible to combine the clear the user asked for and this clear.
512 bool combinedClear = mask && !m_scissorEnabled;
513
514 m_context->disable(GraphicsContext3D::SCISSOR_TEST);
515 if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
516 m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
517 m_colorMask[1] ? m_clearColor[1] : 0,
518 m_colorMask[2] ? m_clearColor[2] : 0,
519 m_colorMask[3] ? m_clearColor[3] : 0);
520 else
521 m_context->clearColor(0, 0, 0, 0);
522 m_context->colorMask(true, true, true, true);
523 if (contextAttributes->depth() && (!combinedClear || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT)))
524 m_context->clearDepth(1.0f);
525 if (contextAttributes->stencil() && (!combinedClear || !(mask & GraphicsContext3D::STENCIL_BUFFER_BIT)))
526 m_context->clearStencil(0);
527 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
528 if (contextAttributes->depth())
529 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
530 if (contextAttributes->stencil())
531 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
532 m_context->clear(clearMask);
533
534 // Restore the state that the context set.
535 if (m_scissorEnabled)
536 m_context->enable(GraphicsContext3D::SCISSOR_TEST);
537 m_context->clearColor(m_clearColor[0], m_clearColor[1],
538 m_clearColor[2], m_clearColor[3]);
539 m_context->colorMask(m_colorMask[0], m_colorMask[1],
540 m_colorMask[2], m_colorMask[3]);
541 m_context->clearDepth(m_clearDepth);
542 m_context->clearStencil(m_clearStencil);
543 m_layerCleared = true;
544
545 return combinedClear;
546 }
547
markLayerComposited()548 void WebGLRenderingContext::markLayerComposited()
549 {
550 m_context->markLayerComposited();
551 }
552
paintRenderingResultsToCanvas()553 void WebGLRenderingContext::paintRenderingResultsToCanvas()
554 {
555 // Until the canvas is written to by the application, the clear that
556 // happened after it was composited should be ignored by the compositor.
557 if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer)
558 canvas()->makePresentationCopy();
559 else
560 canvas()->clearPresentationCopy();
561 clearIfComposited();
562 if (!m_markedCanvasDirty && !m_layerCleared)
563 return;
564 canvas()->clearCopiedImage();
565 m_markedCanvasDirty = false;
566 m_context->paintRenderingResultsToCanvas(this);
567 }
568
paintRenderingResultsToImageData()569 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
570 {
571 clearIfComposited();
572 return m_context->paintRenderingResultsToImageData();
573 }
574
paintsIntoCanvasBuffer() const575 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const
576 {
577 return m_context->paintsIntoCanvasBuffer();
578 }
579
reshape(int width,int height)580 void WebGLRenderingContext::reshape(int width, int height)
581 {
582 if (m_needsUpdate) {
583 #if USE(ACCELERATED_COMPOSITING)
584 RenderBox* renderBox = canvas()->renderBox();
585 if (renderBox && renderBox->hasLayer())
586 renderBox->layer()->contentChanged(RenderLayer::CanvasChanged);
587 #endif
588 m_needsUpdate = false;
589 }
590
591 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
592 // clear (and this matches what reshape will do).
593 m_context->reshape(width, height);
594 }
595
sizeInBytes(GC3Denum type)596 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
597 {
598 switch (type) {
599 case GraphicsContext3D::BYTE:
600 return sizeof(GC3Dbyte);
601 case GraphicsContext3D::UNSIGNED_BYTE:
602 return sizeof(GC3Dubyte);
603 case GraphicsContext3D::SHORT:
604 return sizeof(GC3Dshort);
605 case GraphicsContext3D::UNSIGNED_SHORT:
606 return sizeof(GC3Dushort);
607 case GraphicsContext3D::INT:
608 return sizeof(GC3Dint);
609 case GraphicsContext3D::UNSIGNED_INT:
610 return sizeof(GC3Duint);
611 case GraphicsContext3D::FLOAT:
612 return sizeof(GC3Dfloat);
613 }
614 ASSERT_NOT_REACHED();
615 return 0;
616 }
617
activeTexture(GC3Denum texture,ExceptionCode & ec)618 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
619 {
620 UNUSED_PARAM(ec);
621 if (isContextLost())
622 return;
623 if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
624 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
625 return;
626 }
627 m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
628 m_context->activeTexture(texture);
629 cleanupAfterGraphicsCall(false);
630 }
631
attachShader(WebGLProgram * program,WebGLShader * shader,ExceptionCode & ec)632 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
633 {
634 UNUSED_PARAM(ec);
635 if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
636 return;
637 if (!program->attachShader(shader)) {
638 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
639 return;
640 }
641 m_context->attachShader(objectOrZero(program), objectOrZero(shader));
642 shader->onAttached();
643 cleanupAfterGraphicsCall(false);
644 }
645
bindAttribLocation(WebGLProgram * program,GC3Duint index,const String & name,ExceptionCode & ec)646 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
647 {
648 UNUSED_PARAM(ec);
649 if (isContextLost() || !validateWebGLObject(program))
650 return;
651 if (!validateString(name))
652 return;
653 m_context->bindAttribLocation(objectOrZero(program), index, name);
654 cleanupAfterGraphicsCall(false);
655 }
656
checkObjectToBeBound(WebGLObject * object,bool & deleted)657 bool WebGLRenderingContext::checkObjectToBeBound(WebGLObject* object, bool& deleted)
658 {
659 deleted = false;
660 if (isContextLost())
661 return false;
662 if (object) {
663 if (object->context() != this) {
664 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
665 return false;
666 }
667 deleted = !object->object();
668 }
669 return true;
670 }
671
bindBuffer(GC3Denum target,WebGLBuffer * buffer,ExceptionCode & ec)672 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
673 {
674 UNUSED_PARAM(ec);
675 bool deleted;
676 if (!checkObjectToBeBound(buffer, deleted))
677 return;
678 if (deleted)
679 buffer = 0;
680 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
681 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
682 return;
683 }
684 if (target == GraphicsContext3D::ARRAY_BUFFER)
685 m_boundArrayBuffer = buffer;
686 else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
687 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
688 else {
689 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
690 return;
691 }
692
693 m_context->bindBuffer(target, objectOrZero(buffer));
694 if (buffer)
695 buffer->setTarget(target);
696 cleanupAfterGraphicsCall(false);
697 }
698
bindFramebuffer(GC3Denum target,WebGLFramebuffer * buffer,ExceptionCode & ec)699 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
700 {
701 UNUSED_PARAM(ec);
702 bool deleted;
703 if (!checkObjectToBeBound(buffer, deleted))
704 return;
705 if (deleted)
706 buffer = 0;
707 if (target != GraphicsContext3D::FRAMEBUFFER) {
708 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
709 return;
710 }
711 m_framebufferBinding = buffer;
712 m_context->bindFramebuffer(target, objectOrZero(buffer));
713 if (buffer)
714 buffer->setHasEverBeenBound();
715 cleanupAfterGraphicsCall(false);
716 }
717
bindRenderbuffer(GC3Denum target,WebGLRenderbuffer * renderBuffer,ExceptionCode & ec)718 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
719 {
720 UNUSED_PARAM(ec);
721 bool deleted;
722 if (!checkObjectToBeBound(renderBuffer, deleted))
723 return;
724 if (deleted)
725 renderBuffer = 0;
726 if (target != GraphicsContext3D::RENDERBUFFER) {
727 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
728 return;
729 }
730 m_renderbufferBinding = renderBuffer;
731 m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
732 if (renderBuffer)
733 renderBuffer->setHasEverBeenBound();
734 cleanupAfterGraphicsCall(false);
735 }
736
bindTexture(GC3Denum target,WebGLTexture * texture,ExceptionCode & ec)737 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
738 {
739 UNUSED_PARAM(ec);
740 bool deleted;
741 if (!checkObjectToBeBound(texture, deleted))
742 return;
743 if (deleted)
744 texture = 0;
745 if (texture && texture->getTarget() && texture->getTarget() != target) {
746 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
747 return;
748 }
749 GC3Dint maxLevel = 0;
750 if (target == GraphicsContext3D::TEXTURE_2D) {
751 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
752 maxLevel = m_maxTextureLevel;
753 } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
754 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
755 maxLevel = m_maxCubeMapTextureLevel;
756 } else {
757 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
758 return;
759 }
760 m_context->bindTexture(target, objectOrZero(texture));
761 if (texture)
762 texture->setTarget(target, maxLevel);
763
764 // Note: previously we used to automatically set the TEXTURE_WRAP_R
765 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
766 // ES 2.0 doesn't expose this flag (a bug in the specification) and
767 // otherwise the application has no control over the seams in this
768 // dimension. However, it appears that supporting this properly on all
769 // platforms is fairly involved (will require a HashMap from texture ID
770 // in all ports), and we have not had any complaints, so the logic has
771 // been removed.
772
773 cleanupAfterGraphicsCall(false);
774 }
775
blendColor(GC3Dfloat red,GC3Dfloat green,GC3Dfloat blue,GC3Dfloat alpha)776 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
777 {
778 if (isContextLost())
779 return;
780 m_context->blendColor(red, green, blue, alpha);
781 cleanupAfterGraphicsCall(false);
782 }
783
blendEquation(GC3Denum mode)784 void WebGLRenderingContext::blendEquation(GC3Denum mode)
785 {
786 if (isContextLost() || !validateBlendEquation(mode))
787 return;
788 m_context->blendEquation(mode);
789 cleanupAfterGraphicsCall(false);
790 }
791
blendEquationSeparate(GC3Denum modeRGB,GC3Denum modeAlpha)792 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
793 {
794 if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha))
795 return;
796 m_context->blendEquationSeparate(modeRGB, modeAlpha);
797 cleanupAfterGraphicsCall(false);
798 }
799
800
blendFunc(GC3Denum sfactor,GC3Denum dfactor)801 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
802 {
803 if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor))
804 return;
805 m_context->blendFunc(sfactor, dfactor);
806 cleanupAfterGraphicsCall(false);
807 }
808
blendFuncSeparate(GC3Denum srcRGB,GC3Denum dstRGB,GC3Denum srcAlpha,GC3Denum dstAlpha)809 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
810 {
811 if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB))
812 return;
813 m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
814 cleanupAfterGraphicsCall(false);
815 }
816
bufferData(GC3Denum target,GC3Dsizeiptr size,GC3Denum usage,ExceptionCode & ec)817 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
818 {
819 UNUSED_PARAM(ec);
820 if (isContextLost())
821 return;
822 WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
823 if (!buffer)
824 return;
825 if (size < 0) {
826 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
827 return;
828 }
829 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
830 if (!buffer->associateBufferData(size)) {
831 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
832 return;
833 }
834 }
835
836 m_context->bufferData(target, size, usage);
837 cleanupAfterGraphicsCall(false);
838 }
839
bufferData(GC3Denum target,ArrayBuffer * data,GC3Denum usage,ExceptionCode & ec)840 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
841 {
842 UNUSED_PARAM(ec);
843 if (isContextLost())
844 return;
845 WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
846 if (!buffer)
847 return;
848 if (!data) {
849 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
850 return;
851 }
852 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
853 if (!buffer->associateBufferData(data)) {
854 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
855 return;
856 }
857 }
858
859 m_context->bufferData(target, data->byteLength(), data->data(), usage);
860 cleanupAfterGraphicsCall(false);
861 }
862
bufferData(GC3Denum target,ArrayBufferView * data,GC3Denum usage,ExceptionCode & ec)863 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
864 {
865 UNUSED_PARAM(ec);
866 if (isContextLost())
867 return;
868 WebGLBuffer* buffer = validateBufferDataParameters(target, usage);
869 if (!buffer)
870 return;
871 if (!data) {
872 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
873 return;
874 }
875 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
876 if (!buffer->associateBufferData(data)) {
877 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
878 return;
879 }
880 }
881
882 m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
883 cleanupAfterGraphicsCall(false);
884 }
885
bufferSubData(GC3Denum target,GC3Dintptr offset,ArrayBuffer * data,ExceptionCode & ec)886 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
887 {
888 UNUSED_PARAM(ec);
889 if (isContextLost())
890 return;
891 WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
892 if (!buffer)
893 return;
894 if (offset < 0) {
895 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
896 return;
897 }
898 if (!data)
899 return;
900 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
901 if (!buffer->associateBufferSubData(offset, data)) {
902 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
903 return;
904 }
905 }
906
907 m_context->bufferSubData(target, offset, data->byteLength(), data->data());
908 cleanupAfterGraphicsCall(false);
909 }
910
bufferSubData(GC3Denum target,GC3Dintptr offset,ArrayBufferView * data,ExceptionCode & ec)911 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
912 {
913 UNUSED_PARAM(ec);
914 if (isContextLost())
915 return;
916 WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW);
917 if (!buffer)
918 return;
919 if (offset < 0) {
920 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
921 return;
922 }
923 if (!data)
924 return;
925 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
926 if (!buffer->associateBufferSubData(offset, data)) {
927 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
928 return;
929 }
930 }
931
932 m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
933 cleanupAfterGraphicsCall(false);
934 }
935
checkFramebufferStatus(GC3Denum target)936 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
937 {
938 if (isContextLost())
939 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
940 if (target != GraphicsContext3D::FRAMEBUFFER) {
941 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
942 return 0;
943 }
944 if (!m_framebufferBinding || !m_framebufferBinding->object())
945 return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
946 if (m_framebufferBinding->isIncomplete(true))
947 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
948 unsigned long result = m_context->checkFramebufferStatus(target);
949 cleanupAfterGraphicsCall(false);
950 return result;
951 }
952
clear(GC3Dbitfield mask)953 void WebGLRenderingContext::clear(GC3Dbitfield mask)
954 {
955 if (isContextLost())
956 return;
957 if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
958 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
959 return;
960 }
961 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
962 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
963 return;
964 }
965 if (!clearIfComposited(mask))
966 m_context->clear(mask);
967 cleanupAfterGraphicsCall(true);
968 }
969
clearColor(GC3Dfloat r,GC3Dfloat g,GC3Dfloat b,GC3Dfloat a)970 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
971 {
972 if (isContextLost())
973 return;
974 if (isnan(r))
975 r = 0;
976 if (isnan(g))
977 g = 0;
978 if (isnan(b))
979 b = 0;
980 if (isnan(a))
981 a = 1;
982 m_clearColor[0] = r;
983 m_clearColor[1] = g;
984 m_clearColor[2] = b;
985 m_clearColor[3] = a;
986 m_context->clearColor(r, g, b, a);
987 cleanupAfterGraphicsCall(false);
988 }
989
clearDepth(GC3Dfloat depth)990 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
991 {
992 if (isContextLost())
993 return;
994 m_clearDepth = depth;
995 m_context->clearDepth(depth);
996 cleanupAfterGraphicsCall(false);
997 }
998
clearStencil(GC3Dint s)999 void WebGLRenderingContext::clearStencil(GC3Dint s)
1000 {
1001 if (isContextLost())
1002 return;
1003 m_clearStencil = s;
1004 m_context->clearStencil(s);
1005 cleanupAfterGraphicsCall(false);
1006 }
1007
colorMask(GC3Dboolean red,GC3Dboolean green,GC3Dboolean blue,GC3Dboolean alpha)1008 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1009 {
1010 if (isContextLost())
1011 return;
1012 m_colorMask[0] = red;
1013 m_colorMask[1] = green;
1014 m_colorMask[2] = blue;
1015 m_colorMask[3] = alpha;
1016 m_context->colorMask(red, green, blue, alpha);
1017 cleanupAfterGraphicsCall(false);
1018 }
1019
compileShader(WebGLShader * shader,ExceptionCode & ec)1020 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1021 {
1022 UNUSED_PARAM(ec);
1023 if (isContextLost() || !validateWebGLObject(shader))
1024 return;
1025 m_context->compileShader(objectOrZero(shader));
1026 cleanupAfterGraphicsCall(false);
1027 }
1028
copyTexImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Dint border)1029 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1030 {
1031 if (isContextLost())
1032 return;
1033 if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1034 return;
1035 WebGLTexture* tex = validateTextureBinding(target, true);
1036 if (!tex)
1037 return;
1038 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1039 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1040 return;
1041 }
1042 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1043 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1044 return;
1045 }
1046 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1047 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1048 return;
1049 }
1050 clearIfComposited();
1051 if (isResourceSafe())
1052 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1053 else {
1054 GC3Dint clippedX, clippedY;
1055 GC3Dsizei clippedWidth, clippedHeight;
1056 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1057 m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1058 internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1059 if (clippedWidth > 0 && clippedHeight > 0) {
1060 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1061 clippedX, clippedY, clippedWidth, clippedHeight);
1062 }
1063 } else
1064 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1065 }
1066 // FIXME: if the framebuffer is not complete, none of the below should be executed.
1067 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1068 cleanupAfterGraphicsCall(false);
1069 }
1070
copyTexSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)1071 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1072 {
1073 if (isContextLost())
1074 return;
1075 if (!validateTexFuncLevel(target, level))
1076 return;
1077 WebGLTexture* tex = validateTextureBinding(target, true);
1078 if (!tex)
1079 return;
1080 if (!validateSize(xoffset, yoffset) || !validateSize(width, height))
1081 return;
1082 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1083 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1084 return;
1085 }
1086 if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1087 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1088 return;
1089 }
1090 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1091 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1092 return;
1093 }
1094 clearIfComposited();
1095 if (isResourceSafe())
1096 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1097 else {
1098 GC3Dint clippedX, clippedY;
1099 GC3Dsizei clippedWidth, clippedHeight;
1100 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1101 GC3Denum format = tex->getInternalFormat(target, level);
1102 GC3Denum type = tex->getType(target, level);
1103 OwnArrayPtr<unsigned char> zero;
1104 if (width && height) {
1105 unsigned int size;
1106 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1107 if (error != GraphicsContext3D::NO_ERROR) {
1108 m_context->synthesizeGLError(error);
1109 return;
1110 }
1111 zero = adoptArrayPtr(new unsigned char[size]);
1112 if (!zero) {
1113 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1114 return;
1115 }
1116 memset(zero.get(), 0, size);
1117 }
1118 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1119 if (clippedWidth > 0 && clippedHeight > 0) {
1120 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1121 clippedX, clippedY, clippedWidth, clippedHeight);
1122 }
1123 } else
1124 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1125 }
1126 cleanupAfterGraphicsCall(false);
1127 }
1128
createBuffer()1129 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1130 {
1131 if (isContextLost())
1132 return 0;
1133 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1134 addObject(o.get());
1135 return o;
1136 }
1137
createFramebuffer()1138 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1139 {
1140 if (isContextLost())
1141 return 0;
1142 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1143 addObject(o.get());
1144 return o;
1145 }
1146
createTexture()1147 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1148 {
1149 if (isContextLost())
1150 return 0;
1151 RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1152 addObject(o.get());
1153 return o;
1154 }
1155
createProgram()1156 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1157 {
1158 if (isContextLost())
1159 return 0;
1160 RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1161 addObject(o.get());
1162 return o;
1163 }
1164
createRenderbuffer()1165 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1166 {
1167 if (isContextLost())
1168 return 0;
1169 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1170 addObject(o.get());
1171 return o;
1172 }
1173
createShader(GC3Denum type,ExceptionCode & ec)1174 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1175 {
1176 UNUSED_PARAM(ec);
1177 if (isContextLost())
1178 return 0;
1179 if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1180 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1181 return 0;
1182 }
1183
1184 RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1185 addObject(o.get());
1186 return o;
1187 }
1188
cullFace(GC3Denum mode)1189 void WebGLRenderingContext::cullFace(GC3Denum mode)
1190 {
1191 if (isContextLost())
1192 return;
1193 m_context->cullFace(mode);
1194 cleanupAfterGraphicsCall(false);
1195 }
1196
deleteObject(WebGLObject * object)1197 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1198 {
1199 if (isContextLost() || !object)
1200 return false;
1201 if (object->context() != this) {
1202 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1203 return false;
1204 }
1205 if (object->object())
1206 object->deleteObject();
1207 return true;
1208 }
1209
deleteBuffer(WebGLBuffer * buffer)1210 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1211 {
1212 if (!deleteObject(buffer))
1213 return;
1214 if (m_boundArrayBuffer == buffer)
1215 m_boundArrayBuffer = 0;
1216 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1217 if (elementArrayBuffer == buffer)
1218 m_boundVertexArrayObject->setElementArrayBuffer(0);
1219 if (!isGLES2Compliant()) {
1220 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1221 if (buffer == state.bufferBinding) {
1222 state.bufferBinding = m_vertexAttrib0Buffer;
1223 state.bytesPerElement = 0;
1224 state.size = 4;
1225 state.type = GraphicsContext3D::FLOAT;
1226 state.normalized = false;
1227 state.stride = 16;
1228 state.originalStride = 0;
1229 state.offset = 0;
1230 }
1231 }
1232 }
1233
deleteFramebuffer(WebGLFramebuffer * framebuffer)1234 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1235 {
1236 if (!deleteObject(framebuffer))
1237 return;
1238 if (framebuffer == m_framebufferBinding) {
1239 m_framebufferBinding = 0;
1240 // Have to call bindFramebuffer here to bind back to internal fbo.
1241 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1242 }
1243 }
1244
deleteProgram(WebGLProgram * program)1245 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1246 {
1247 deleteObject(program);
1248 // We don't reset m_currentProgram to 0 here because the deletion of the
1249 // current program is delayed.
1250 }
1251
deleteRenderbuffer(WebGLRenderbuffer * renderbuffer)1252 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1253 {
1254 if (!deleteObject(renderbuffer))
1255 return;
1256 if (renderbuffer == m_renderbufferBinding)
1257 m_renderbufferBinding = 0;
1258 if (m_framebufferBinding)
1259 m_framebufferBinding->removeAttachment(renderbuffer);
1260 }
1261
deleteShader(WebGLShader * shader)1262 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1263 {
1264 deleteObject(shader);
1265 }
1266
deleteTexture(WebGLTexture * texture)1267 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1268 {
1269 if (!deleteObject(texture))
1270 return;
1271 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1272 if (texture == m_textureUnits[i].m_texture2DBinding)
1273 m_textureUnits[i].m_texture2DBinding = 0;
1274 if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1275 m_textureUnits[i].m_textureCubeMapBinding = 0;
1276 }
1277 if (m_framebufferBinding)
1278 m_framebufferBinding->removeAttachment(texture);
1279 }
1280
depthFunc(GC3Denum func)1281 void WebGLRenderingContext::depthFunc(GC3Denum func)
1282 {
1283 if (isContextLost())
1284 return;
1285 m_context->depthFunc(func);
1286 cleanupAfterGraphicsCall(false);
1287 }
1288
depthMask(GC3Dboolean flag)1289 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1290 {
1291 if (isContextLost())
1292 return;
1293 m_context->depthMask(flag);
1294 cleanupAfterGraphicsCall(false);
1295 }
1296
depthRange(GC3Dfloat zNear,GC3Dfloat zFar)1297 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1298 {
1299 if (isContextLost())
1300 return;
1301 if (zNear > zFar) {
1302 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1303 return;
1304 }
1305 m_context->depthRange(zNear, zFar);
1306 cleanupAfterGraphicsCall(false);
1307 }
1308
detachShader(WebGLProgram * program,WebGLShader * shader,ExceptionCode & ec)1309 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1310 {
1311 UNUSED_PARAM(ec);
1312 if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader))
1313 return;
1314 if (!program->detachShader(shader)) {
1315 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1316 return;
1317 }
1318 m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1319 shader->onDetached();
1320 cleanupAfterGraphicsCall(false);
1321 }
1322
disable(GC3Denum cap)1323 void WebGLRenderingContext::disable(GC3Denum cap)
1324 {
1325 if (isContextLost() || !validateCapability(cap))
1326 return;
1327 if (cap == GraphicsContext3D::SCISSOR_TEST)
1328 m_scissorEnabled = false;
1329 m_context->disable(cap);
1330 cleanupAfterGraphicsCall(false);
1331 }
1332
disableVertexAttribArray(GC3Duint index,ExceptionCode & ec)1333 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1334 {
1335 UNUSED_PARAM(ec);
1336 if (isContextLost())
1337 return;
1338 if (index >= m_maxVertexAttribs) {
1339 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1340 return;
1341 }
1342
1343 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1344 state.enabled = false;
1345
1346 if (index > 0 || isGLES2Compliant()) {
1347 m_context->disableVertexAttribArray(index);
1348 cleanupAfterGraphicsCall(false);
1349 }
1350 }
1351
validateElementArraySize(GC3Dsizei count,GC3Denum type,GC3Dintptr offset)1352 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1353 {
1354 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1355
1356 if (!elementArrayBuffer)
1357 return false;
1358
1359 if (offset < 0)
1360 return false;
1361
1362 if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1363 // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1364 if (offset % 2)
1365 return false;
1366
1367 // Make uoffset an element offset.
1368 offset /= 2;
1369
1370 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1371 if (offset > n || count > n - offset)
1372 return false;
1373 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1374 GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1375 if (offset > n || count > n - offset)
1376 return false;
1377 }
1378 return true;
1379 }
1380
validateIndexArrayConservative(GC3Denum type,int & numElementsRequired)1381 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1382 {
1383 // Performs conservative validation by caching a maximum index of
1384 // the given type per element array buffer. If all of the bound
1385 // array buffers have enough elements to satisfy that maximum
1386 // index, skips the expensive per-draw-call iteration in
1387 // validateIndexArrayPrecise.
1388
1389 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1390
1391 if (!elementArrayBuffer)
1392 return false;
1393
1394 GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1395 // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1396 if (!numElements)
1397 return false;
1398 const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1399 ASSERT(buffer);
1400
1401 int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1402 if (maxIndex < 0) {
1403 // Compute the maximum index in the entire buffer for the given type of index.
1404 switch (type) {
1405 case GraphicsContext3D::UNSIGNED_BYTE: {
1406 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1407 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1408 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1409 break;
1410 }
1411 case GraphicsContext3D::UNSIGNED_SHORT: {
1412 numElements /= sizeof(GC3Dushort);
1413 const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1414 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1415 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1416 break;
1417 }
1418 default:
1419 return false;
1420 }
1421 elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1422 }
1423
1424 if (maxIndex >= 0) {
1425 // The number of required elements is one more than the maximum
1426 // index that will be accessed.
1427 numElementsRequired = maxIndex + 1;
1428 return true;
1429 }
1430
1431 return false;
1432 }
1433
validateIndexArrayPrecise(GC3Dsizei count,GC3Denum type,GC3Dintptr offset,int & numElementsRequired)1434 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1435 {
1436 ASSERT(count >= 0 && offset >= 0);
1437 int lastIndex = -1;
1438
1439 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1440
1441 if (!elementArrayBuffer)
1442 return false;
1443
1444 if (!count) {
1445 numElementsRequired = 0;
1446 return true;
1447 }
1448
1449 if (!elementArrayBuffer->elementArrayBuffer())
1450 return false;
1451
1452 unsigned long uoffset = offset;
1453 unsigned long n = count;
1454
1455 if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1456 // Make uoffset an element offset.
1457 uoffset /= sizeof(GC3Dushort);
1458 const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1459 while (n-- > 0) {
1460 if (*p > lastIndex)
1461 lastIndex = *p;
1462 ++p;
1463 }
1464 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1465 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1466 while (n-- > 0) {
1467 if (*p > lastIndex)
1468 lastIndex = *p;
1469 ++p;
1470 }
1471 }
1472
1473 // Then set the last index in the index array and make sure it is valid.
1474 numElementsRequired = lastIndex + 1;
1475 return numElementsRequired > 0;
1476 }
1477
validateRenderingState(int numElementsRequired)1478 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1479 {
1480 if (!m_currentProgram)
1481 return false;
1482
1483 // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1484 for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1485 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1486 if (state.enabled
1487 && (!state.bufferBinding || !state.bufferBinding->object()))
1488 return false;
1489 }
1490
1491 if (numElementsRequired <= 0)
1492 return true;
1493
1494 // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1495 int smallestNumElements = INT_MAX;
1496 int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1497 for (int i = 0; i < numActiveAttribLocations; ++i) {
1498 int loc = m_currentProgram->getActiveAttribLocation(i);
1499 if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1500 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1501 if (state.enabled) {
1502 // Avoid off-by-one errors in numElements computation.
1503 // For the last element, we will only touch the data for the
1504 // element and nothing beyond it.
1505 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1506 int numElements = 0;
1507 ASSERT(state.stride > 0);
1508 if (bytesRemaining >= state.bytesPerElement)
1509 numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1510 if (numElements < smallestNumElements)
1511 smallestNumElements = numElements;
1512 }
1513 }
1514 }
1515
1516 if (smallestNumElements == INT_MAX)
1517 smallestNumElements = 0;
1518
1519 return numElementsRequired <= smallestNumElements;
1520 }
1521
validateWebGLObject(WebGLObject * object)1522 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
1523 {
1524 if (!object || !object->object()) {
1525 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1526 return false;
1527 }
1528 if (object->context() != this) {
1529 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1530 return false;
1531 }
1532 return true;
1533 }
1534
drawArrays(GC3Denum mode,GC3Dint first,GC3Dsizei count,ExceptionCode & ec)1535 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1536 {
1537 UNUSED_PARAM(ec);
1538
1539 if (isContextLost() || !validateDrawMode(mode))
1540 return;
1541
1542 if (!validateStencilSettings())
1543 return;
1544
1545 if (first < 0 || count < 0) {
1546 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1547 return;
1548 }
1549
1550 if (!count)
1551 return;
1552
1553 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1554 // Ensure we have a valid rendering state
1555 CheckedInt<GC3Dint> checkedFirst(first);
1556 CheckedInt<GC3Dint> checkedCount(count);
1557 CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1558 if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1559 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1560 return;
1561 }
1562 } else {
1563 if (!validateRenderingState(0)) {
1564 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1565 return;
1566 }
1567 }
1568
1569 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1570 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1571 return;
1572 }
1573
1574 clearIfComposited();
1575
1576 bool vertexAttrib0Simulated = false;
1577 if (!isGLES2Compliant())
1578 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1579 if (!isGLES2NPOTStrict())
1580 handleNPOTTextures(true);
1581 m_context->drawArrays(mode, first, count);
1582 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1583 restoreStatesAfterVertexAttrib0Simulation();
1584 if (!isGLES2NPOTStrict())
1585 handleNPOTTextures(false);
1586 cleanupAfterGraphicsCall(true);
1587 }
1588
drawElements(GC3Denum mode,GC3Dsizei count,GC3Denum type,GC3Dintptr offset,ExceptionCode & ec)1589 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1590 {
1591 UNUSED_PARAM(ec);
1592
1593 if (isContextLost() || !validateDrawMode(mode))
1594 return;
1595
1596 if (!validateStencilSettings())
1597 return;
1598
1599 switch (type) {
1600 case GraphicsContext3D::UNSIGNED_BYTE:
1601 case GraphicsContext3D::UNSIGNED_SHORT:
1602 break;
1603 default:
1604 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1605 return;
1606 }
1607
1608 if (count < 0 || offset < 0) {
1609 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1610 return;
1611 }
1612
1613 if (!count)
1614 return;
1615
1616 if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1617 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1618 return;
1619 }
1620
1621 int numElements = 0;
1622 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1623 // Ensure we have a valid rendering state
1624 if (!validateElementArraySize(count, type, offset)) {
1625 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1626 return;
1627 }
1628 if (!count)
1629 return;
1630 if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1631 if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1632 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1633 return;
1634 }
1635 }
1636 } else {
1637 if (!validateRenderingState(0)) {
1638 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1639 return;
1640 }
1641 }
1642
1643 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
1644 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
1645 return;
1646 }
1647 clearIfComposited();
1648
1649 bool vertexAttrib0Simulated = false;
1650 if (!isGLES2Compliant()) {
1651 if (!numElements)
1652 validateIndexArrayPrecise(count, type, offset, numElements);
1653 vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1654 }
1655 if (!isGLES2NPOTStrict())
1656 handleNPOTTextures(true);
1657 m_context->drawElements(mode, count, type, offset);
1658 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1659 restoreStatesAfterVertexAttrib0Simulation();
1660 if (!isGLES2NPOTStrict())
1661 handleNPOTTextures(false);
1662 cleanupAfterGraphicsCall(true);
1663 }
1664
enable(GC3Denum cap)1665 void WebGLRenderingContext::enable(GC3Denum cap)
1666 {
1667 if (isContextLost() || !validateCapability(cap))
1668 return;
1669 if (cap == GraphicsContext3D::SCISSOR_TEST)
1670 m_scissorEnabled = true;
1671 m_context->enable(cap);
1672 cleanupAfterGraphicsCall(false);
1673 }
1674
enableVertexAttribArray(GC3Duint index,ExceptionCode & ec)1675 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1676 {
1677 UNUSED_PARAM(ec);
1678 if (isContextLost())
1679 return;
1680 if (index >= m_maxVertexAttribs) {
1681 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1682 return;
1683 }
1684
1685 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1686 state.enabled = true;
1687
1688 m_context->enableVertexAttribArray(index);
1689 cleanupAfterGraphicsCall(false);
1690 }
1691
finish()1692 void WebGLRenderingContext::finish()
1693 {
1694 if (isContextLost())
1695 return;
1696 m_context->finish();
1697 cleanupAfterGraphicsCall(false);
1698 }
1699
flush()1700 void WebGLRenderingContext::flush()
1701 {
1702 if (isContextLost())
1703 return;
1704 m_context->flush();
1705 cleanupAfterGraphicsCall(false);
1706 }
1707
framebufferRenderbuffer(GC3Denum target,GC3Denum attachment,GC3Denum renderbuffertarget,WebGLRenderbuffer * buffer,ExceptionCode & ec)1708 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1709 {
1710 UNUSED_PARAM(ec);
1711 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1712 return;
1713 if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1714 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1715 return;
1716 }
1717 if (buffer && buffer->context() != this) {
1718 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1719 return;
1720 }
1721 // Don't allow the default framebuffer to be mutated; all current
1722 // implementations use an FBO internally in place of the default
1723 // FBO.
1724 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1725 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1726 return;
1727 }
1728 Platform3DObject bufferObject = objectOrZero(buffer);
1729 bool reattachDepth = false;
1730 bool reattachStencil = false;
1731 bool reattachDepthStencilDepth = false;
1732 bool reattachDepthStencilStencil = false;
1733 switch (attachment) {
1734 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1735 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1736 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1737 if (!bufferObject) {
1738 reattachDepth = true;
1739 reattachStencil = true;
1740 }
1741 break;
1742 case GraphicsContext3D::DEPTH_ATTACHMENT:
1743 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1744 if (!bufferObject)
1745 reattachDepthStencilDepth = true;
1746 break;
1747 case GraphicsContext3D::STENCIL_ATTACHMENT:
1748 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1749 if (!bufferObject)
1750 reattachDepthStencilStencil = true;
1751 break;
1752 default:
1753 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
1754 }
1755 m_framebufferBinding->setAttachment(attachment, buffer);
1756 if (reattachDepth) {
1757 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
1758 if (object)
1759 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1760 }
1761 if (reattachStencil) {
1762 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
1763 if (object)
1764 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1765 }
1766 if (reattachDepthStencilDepth) {
1767 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1768 if (object)
1769 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
1770 }
1771 if (reattachDepthStencilStencil) {
1772 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
1773 if (object)
1774 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
1775 }
1776 cleanupAfterGraphicsCall(false);
1777 }
1778
framebufferTexture2D(GC3Denum target,GC3Denum attachment,GC3Denum textarget,WebGLTexture * texture,GC3Dint level,ExceptionCode & ec)1779 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
1780 {
1781 UNUSED_PARAM(ec);
1782 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1783 return;
1784 if (level) {
1785 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
1786 return;
1787 }
1788 if (texture && texture->context() != this) {
1789 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1790 return;
1791 }
1792 // Don't allow the default framebuffer to be mutated; all current
1793 // implementations use an FBO internally in place of the default
1794 // FBO.
1795 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1796 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1797 return;
1798 }
1799 m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
1800 m_framebufferBinding->setAttachment(attachment, textarget, texture, level);
1801 cleanupAfterGraphicsCall(false);
1802 }
1803
frontFace(GC3Denum mode)1804 void WebGLRenderingContext::frontFace(GC3Denum mode)
1805 {
1806 if (isContextLost())
1807 return;
1808 m_context->frontFace(mode);
1809 cleanupAfterGraphicsCall(false);
1810 }
1811
generateMipmap(GC3Denum target)1812 void WebGLRenderingContext::generateMipmap(GC3Denum target)
1813 {
1814 if (isContextLost())
1815 return;
1816 WebGLTexture* tex = validateTextureBinding(target, false);
1817 if (!tex)
1818 return;
1819 if (!tex->canGenerateMipmaps()) {
1820 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1821 return;
1822 }
1823 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1824 // on Mac. Remove the hack once this driver bug is fixed.
1825 #if OS(DARWIN)
1826 bool needToResetMinFilter = false;
1827 if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
1828 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
1829 needToResetMinFilter = true;
1830 }
1831 #endif
1832 m_context->generateMipmap(target);
1833 #if OS(DARWIN)
1834 if (needToResetMinFilter)
1835 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
1836 #endif
1837 tex->generateMipmapLevelInfo();
1838 cleanupAfterGraphicsCall(false);
1839 }
1840
getActiveAttrib(WebGLProgram * program,GC3Duint index,ExceptionCode & ec)1841 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1842 {
1843 UNUSED_PARAM(ec);
1844 if (isContextLost() || !validateWebGLObject(program))
1845 return 0;
1846 ActiveInfo info;
1847 if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
1848 return 0;
1849 return WebGLActiveInfo::create(info.name, info.type, info.size);
1850 }
1851
getActiveUniform(WebGLProgram * program,GC3Duint index,ExceptionCode & ec)1852 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
1853 {
1854 UNUSED_PARAM(ec);
1855 if (isContextLost() || !validateWebGLObject(program))
1856 return 0;
1857 ActiveInfo info;
1858 if (!m_context->getActiveUniform(objectOrZero(program), index, info))
1859 return 0;
1860 if (!isGLES2Compliant())
1861 if (info.size > 1 && !info.name.endsWith("[0]"))
1862 info.name.append("[0]");
1863 return WebGLActiveInfo::create(info.name, info.type, info.size);
1864 }
1865
getAttachedShaders(WebGLProgram * program,Vector<WebGLShader * > & shaderObjects,ExceptionCode & ec)1866 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec)
1867 {
1868 UNUSED_PARAM(ec);
1869 shaderObjects.clear();
1870 if (isContextLost() || !validateWebGLObject(program))
1871 return false;
1872 GC3Dint numShaders = 0;
1873 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders);
1874 if (numShaders) {
1875 OwnArrayPtr<Platform3DObject> shaders = adoptArrayPtr(new Platform3DObject[numShaders]);
1876 GC3Dsizei count = 0;
1877 m_context->getAttachedShaders(objectOrZero(program), numShaders, &count, shaders.get());
1878 if (count != numShaders)
1879 return false;
1880 shaderObjects.resize(numShaders);
1881 for (GC3Dint ii = 0; ii < numShaders; ++ii) {
1882 WebGLShader* shader = findShader(shaders[ii]);
1883 if (!shader) {
1884 shaderObjects.clear();
1885 return false;
1886 }
1887 shaderObjects[ii] = shader;
1888 }
1889 }
1890 return true;
1891 }
1892
getAttribLocation(WebGLProgram * program,const String & name)1893 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
1894 {
1895 if (isContextLost())
1896 return -1;
1897 if (!validateString(name))
1898 return -1;
1899 return m_context->getAttribLocation(objectOrZero(program), name);
1900 }
1901
getBufferParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)1902 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
1903 {
1904 UNUSED_PARAM(ec);
1905 if (isContextLost())
1906 return WebGLGetInfo();
1907 if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
1908 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1909 return WebGLGetInfo();
1910 }
1911
1912 if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
1913 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1914 return WebGLGetInfo();
1915 }
1916
1917 WebGLStateRestorer(this, false);
1918 GC3Dint value = 0;
1919 m_context->getBufferParameteriv(target, pname, &value);
1920 if (pname == GraphicsContext3D::BUFFER_SIZE)
1921 return WebGLGetInfo(value);
1922 return WebGLGetInfo(static_cast<unsigned int>(value));
1923 }
1924
getContextAttributes()1925 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
1926 {
1927 if (isContextLost())
1928 return 0;
1929 // We always need to return a new WebGLContextAttributes object to
1930 // prevent the user from mutating any cached version.
1931 return WebGLContextAttributes::create(m_context->getContextAttributes());
1932 }
1933
getError()1934 GC3Denum WebGLRenderingContext::getError()
1935 {
1936 return m_context->getError();
1937 }
1938
getExtension(const String & name)1939 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
1940 {
1941 if (isContextLost())
1942 return 0;
1943
1944 if (equalIgnoringCase(name, "OES_standard_derivatives")
1945 && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
1946 if (!m_oesStandardDerivatives) {
1947 m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
1948 m_oesStandardDerivatives = OESStandardDerivatives::create();
1949 }
1950 return m_oesStandardDerivatives.get();
1951 }
1952 if (equalIgnoringCase(name, "OES_texture_float")
1953 && m_context->getExtensions()->supports("GL_OES_texture_float")) {
1954 if (!m_oesTextureFloat) {
1955 m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
1956 m_oesTextureFloat = OESTextureFloat::create();
1957 }
1958 return m_oesTextureFloat.get();
1959 }
1960 if (equalIgnoringCase(name, "OES_vertex_array_object")
1961 && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
1962 if (!m_oesVertexArrayObject) {
1963 m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
1964 m_oesVertexArrayObject = OESVertexArrayObject::create(this);
1965 }
1966 return m_oesVertexArrayObject.get();
1967 }
1968 if (equalIgnoringCase(name, "WEBKIT_lose_context")) {
1969 if (!m_webkitLoseContext)
1970 m_webkitLoseContext = WebKitLoseContext::create(this);
1971 return m_webkitLoseContext.get();
1972 }
1973
1974 return 0;
1975 }
1976
getFramebufferAttachmentParameter(GC3Denum target,GC3Denum attachment,GC3Denum pname,ExceptionCode & ec)1977 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
1978 {
1979 UNUSED_PARAM(ec);
1980 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment))
1981 return WebGLGetInfo();
1982 switch (pname) {
1983 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
1984 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
1985 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
1986 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
1987 break;
1988 default:
1989 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
1990 return WebGLGetInfo();
1991 }
1992
1993 if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) {
1994 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
1995 return WebGLGetInfo();
1996 }
1997
1998 if (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
1999 WebGLStateRestorer(this, false);
2000 GC3Dint value = 0;
2001 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2002 if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2003 return WebGLGetInfo(static_cast<unsigned int>(value));
2004 return WebGLGetInfo(value);
2005 }
2006
2007 WebGLStateRestorer(this, false);
2008 GC3Dint type = 0;
2009 m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
2010 if (!type)
2011 return WebGLGetInfo();
2012 GC3Dint value = 0;
2013 m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &value);
2014 switch (type) {
2015 case GraphicsContext3D::RENDERBUFFER:
2016 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(findRenderbuffer(static_cast<Platform3DObject>(value))));
2017 case GraphicsContext3D::TEXTURE:
2018 return WebGLGetInfo(PassRefPtr<WebGLTexture>(findTexture(static_cast<Platform3DObject>(value))));
2019 default:
2020 // FIXME: raise exception?
2021 return WebGLGetInfo();
2022 }
2023 }
2024
getParameter(GC3Denum pname,ExceptionCode & ec)2025 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2026 {
2027 UNUSED_PARAM(ec);
2028 if (isContextLost())
2029 return WebGLGetInfo();
2030 WebGLStateRestorer(this, false);
2031 switch (pname) {
2032 case GraphicsContext3D::ACTIVE_TEXTURE:
2033 return getUnsignedIntParameter(pname);
2034 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2035 return getWebGLFloatArrayParameter(pname);
2036 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2037 return getWebGLFloatArrayParameter(pname);
2038 case GraphicsContext3D::ALPHA_BITS:
2039 return getIntParameter(pname);
2040 case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2041 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2042 case GraphicsContext3D::BLEND:
2043 return getBooleanParameter(pname);
2044 case GraphicsContext3D::BLEND_COLOR:
2045 return getWebGLFloatArrayParameter(pname);
2046 case GraphicsContext3D::BLEND_DST_ALPHA:
2047 return getUnsignedIntParameter(pname);
2048 case GraphicsContext3D::BLEND_DST_RGB:
2049 return getUnsignedIntParameter(pname);
2050 case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2051 return getUnsignedIntParameter(pname);
2052 case GraphicsContext3D::BLEND_EQUATION_RGB:
2053 return getUnsignedIntParameter(pname);
2054 case GraphicsContext3D::BLEND_SRC_ALPHA:
2055 return getUnsignedIntParameter(pname);
2056 case GraphicsContext3D::BLEND_SRC_RGB:
2057 return getUnsignedIntParameter(pname);
2058 case GraphicsContext3D::BLUE_BITS:
2059 return getIntParameter(pname);
2060 case GraphicsContext3D::COLOR_CLEAR_VALUE:
2061 return getWebGLFloatArrayParameter(pname);
2062 case GraphicsContext3D::COLOR_WRITEMASK:
2063 return getBooleanArrayParameter(pname);
2064 case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2065 // Defined as null in the spec
2066 return WebGLGetInfo();
2067 case GraphicsContext3D::CULL_FACE:
2068 return getBooleanParameter(pname);
2069 case GraphicsContext3D::CULL_FACE_MODE:
2070 return getUnsignedIntParameter(pname);
2071 case GraphicsContext3D::CURRENT_PROGRAM:
2072 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2073 case GraphicsContext3D::DEPTH_BITS:
2074 return getIntParameter(pname);
2075 case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2076 return getFloatParameter(pname);
2077 case GraphicsContext3D::DEPTH_FUNC:
2078 return getUnsignedIntParameter(pname);
2079 case GraphicsContext3D::DEPTH_RANGE:
2080 return getWebGLFloatArrayParameter(pname);
2081 case GraphicsContext3D::DEPTH_TEST:
2082 return getBooleanParameter(pname);
2083 case GraphicsContext3D::DEPTH_WRITEMASK:
2084 return getBooleanParameter(pname);
2085 case GraphicsContext3D::DITHER:
2086 return getBooleanParameter(pname);
2087 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2088 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2089 case GraphicsContext3D::FRAMEBUFFER_BINDING:
2090 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2091 case GraphicsContext3D::FRONT_FACE:
2092 return getUnsignedIntParameter(pname);
2093 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2094 return getUnsignedIntParameter(pname);
2095 case GraphicsContext3D::GREEN_BITS:
2096 return getIntParameter(pname);
2097 case GraphicsContext3D::LINE_WIDTH:
2098 return getFloatParameter(pname);
2099 case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2100 return getIntParameter(pname);
2101 case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2102 return getIntParameter(pname);
2103 case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2104 return getIntParameter(pname);
2105 case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2106 return getIntParameter(pname);
2107 case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2108 return getIntParameter(pname);
2109 case GraphicsContext3D::MAX_TEXTURE_SIZE:
2110 return getIntParameter(pname);
2111 case GraphicsContext3D::MAX_VARYING_VECTORS:
2112 return getIntParameter(pname);
2113 case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2114 return getIntParameter(pname);
2115 case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2116 return getIntParameter(pname);
2117 case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2118 return getIntParameter(pname);
2119 case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2120 return getWebGLIntArrayParameter(pname);
2121 case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS:
2122 // WebGL 1.0 specifies that there are no compressed texture formats.
2123 return WebGLGetInfo(static_cast<int>(0));
2124 case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2125 // FIXME: should we always return 0 for this?
2126 return getIntParameter(pname);
2127 case GraphicsContext3D::PACK_ALIGNMENT:
2128 return getIntParameter(pname);
2129 case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2130 return getFloatParameter(pname);
2131 case GraphicsContext3D::POLYGON_OFFSET_FILL:
2132 return getBooleanParameter(pname);
2133 case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2134 return getFloatParameter(pname);
2135 case GraphicsContext3D::RED_BITS:
2136 return getIntParameter(pname);
2137 case GraphicsContext3D::RENDERBUFFER_BINDING:
2138 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2139 case GraphicsContext3D::RENDERER:
2140 return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2141 case GraphicsContext3D::SAMPLE_BUFFERS:
2142 return getIntParameter(pname);
2143 case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2144 return getBooleanParameter(pname);
2145 case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2146 return getFloatParameter(pname);
2147 case GraphicsContext3D::SAMPLES:
2148 return getIntParameter(pname);
2149 case GraphicsContext3D::SCISSOR_BOX:
2150 return getWebGLIntArrayParameter(pname);
2151 case GraphicsContext3D::SCISSOR_TEST:
2152 return getBooleanParameter(pname);
2153 case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2154 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2155 case GraphicsContext3D::STENCIL_BACK_FAIL:
2156 return getUnsignedIntParameter(pname);
2157 case GraphicsContext3D::STENCIL_BACK_FUNC:
2158 return getUnsignedIntParameter(pname);
2159 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2160 return getUnsignedIntParameter(pname);
2161 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2162 return getUnsignedIntParameter(pname);
2163 case GraphicsContext3D::STENCIL_BACK_REF:
2164 return getIntParameter(pname);
2165 case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2166 return getUnsignedIntParameter(pname);
2167 case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2168 return getUnsignedIntParameter(pname);
2169 case GraphicsContext3D::STENCIL_BITS:
2170 return getIntParameter(pname);
2171 case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2172 return getIntParameter(pname);
2173 case GraphicsContext3D::STENCIL_FAIL:
2174 return getUnsignedIntParameter(pname);
2175 case GraphicsContext3D::STENCIL_FUNC:
2176 return getUnsignedIntParameter(pname);
2177 case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2178 return getUnsignedIntParameter(pname);
2179 case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2180 return getUnsignedIntParameter(pname);
2181 case GraphicsContext3D::STENCIL_REF:
2182 return getIntParameter(pname);
2183 case GraphicsContext3D::STENCIL_TEST:
2184 return getBooleanParameter(pname);
2185 case GraphicsContext3D::STENCIL_VALUE_MASK:
2186 return getUnsignedIntParameter(pname);
2187 case GraphicsContext3D::STENCIL_WRITEMASK:
2188 return getUnsignedIntParameter(pname);
2189 case GraphicsContext3D::SUBPIXEL_BITS:
2190 return getIntParameter(pname);
2191 case GraphicsContext3D::TEXTURE_BINDING_2D:
2192 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2193 case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2194 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2195 case GraphicsContext3D::UNPACK_ALIGNMENT:
2196 return getIntParameter(pname);
2197 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2198 return WebGLGetInfo(m_unpackFlipY);
2199 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2200 return WebGLGetInfo(m_unpackPremultiplyAlpha);
2201 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2202 return WebGLGetInfo(m_unpackColorspaceConversion);
2203 case GraphicsContext3D::VENDOR:
2204 return WebGLGetInfo("Webkit (" + m_context->getString(GraphicsContext3D::VENDOR) + ")");
2205 case GraphicsContext3D::VERSION:
2206 return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2207 case GraphicsContext3D::VIEWPORT:
2208 return getWebGLIntArrayParameter(pname);
2209 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2210 if (m_oesStandardDerivatives)
2211 return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2212 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2213 return WebGLGetInfo();
2214 case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2215 if (m_oesVertexArrayObject) {
2216 if (!m_boundVertexArrayObject->isDefaultObject())
2217 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2218 return WebGLGetInfo();
2219 }
2220 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2221 return WebGLGetInfo();
2222 default:
2223 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2224 return WebGLGetInfo();
2225 }
2226 }
2227
getProgramParameter(WebGLProgram * program,GC3Denum pname,ExceptionCode & ec)2228 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2229 {
2230 UNUSED_PARAM(ec);
2231 if (isContextLost() || !validateWebGLObject(program))
2232 return WebGLGetInfo();
2233
2234 WebGLStateRestorer(this, false);
2235 GC3Dint value = 0;
2236 switch (pname) {
2237 case GraphicsContext3D::DELETE_STATUS:
2238 return WebGLGetInfo(program->isDeleted());
2239 case GraphicsContext3D::VALIDATE_STATUS:
2240 m_context->getProgramiv(objectOrZero(program), pname, &value);
2241 return WebGLGetInfo(static_cast<bool>(value));
2242 case GraphicsContext3D::LINK_STATUS:
2243 return WebGLGetInfo(program->getLinkStatus());
2244 case GraphicsContext3D::ATTACHED_SHADERS:
2245 case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2246 case GraphicsContext3D::ACTIVE_UNIFORMS:
2247 m_context->getProgramiv(objectOrZero(program), pname, &value);
2248 return WebGLGetInfo(value);
2249 default:
2250 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2251 return WebGLGetInfo();
2252 }
2253 }
2254
getProgramInfoLog(WebGLProgram * program,ExceptionCode & ec)2255 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2256 {
2257 UNUSED_PARAM(ec);
2258 if (isContextLost())
2259 return String();
2260 if (!validateWebGLObject(program))
2261 return "";
2262 WebGLStateRestorer(this, false);
2263 return m_context->getProgramInfoLog(objectOrZero(program));
2264 }
2265
getRenderbufferParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)2266 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2267 {
2268 UNUSED_PARAM(ec);
2269 if (isContextLost())
2270 return WebGLGetInfo();
2271 if (target != GraphicsContext3D::RENDERBUFFER) {
2272 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2273 return WebGLGetInfo();
2274 }
2275 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2276 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2277 return WebGLGetInfo();
2278 }
2279
2280 if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2281 && !m_renderbufferBinding->isValid()) {
2282 ASSERT(!isDepthStencilSupported());
2283 int value = 0;
2284 switch (pname) {
2285 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2286 value = m_renderbufferBinding->getWidth();
2287 break;
2288 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2289 value = m_renderbufferBinding->getHeight();
2290 break;
2291 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2292 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2293 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2294 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2295 value = 0;
2296 break;
2297 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2298 value = 24;
2299 break;
2300 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2301 value = 8;
2302 break;
2303 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2304 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2305 default:
2306 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2307 return WebGLGetInfo();
2308 }
2309 return WebGLGetInfo(value);
2310 }
2311
2312 WebGLStateRestorer(this, false);
2313 GC3Dint value = 0;
2314 switch (pname) {
2315 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2316 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2317 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2318 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2319 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2320 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2321 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2322 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2323 m_context->getRenderbufferParameteriv(target, pname, &value);
2324 return WebGLGetInfo(value);
2325 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2326 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2327 default:
2328 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2329 return WebGLGetInfo();
2330 }
2331 }
2332
getShaderParameter(WebGLShader * shader,GC3Denum pname,ExceptionCode & ec)2333 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2334 {
2335 UNUSED_PARAM(ec);
2336 if (isContextLost() || !validateWebGLObject(shader))
2337 return WebGLGetInfo();
2338 WebGLStateRestorer(this, false);
2339 GC3Dint value = 0;
2340 switch (pname) {
2341 case GraphicsContext3D::DELETE_STATUS:
2342 return WebGLGetInfo(shader->isDeleted());
2343 case GraphicsContext3D::COMPILE_STATUS:
2344 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2345 return WebGLGetInfo(static_cast<bool>(value));
2346 case GraphicsContext3D::SHADER_TYPE:
2347 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2348 return WebGLGetInfo(static_cast<unsigned int>(value));
2349 default:
2350 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2351 return WebGLGetInfo();
2352 }
2353 }
2354
getShaderInfoLog(WebGLShader * shader,ExceptionCode & ec)2355 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2356 {
2357 UNUSED_PARAM(ec);
2358 if (isContextLost())
2359 return String();
2360 if (!validateWebGLObject(shader))
2361 return "";
2362 WebGLStateRestorer(this, false);
2363 return m_context->getShaderInfoLog(objectOrZero(shader));
2364 }
2365
getShaderSource(WebGLShader * shader,ExceptionCode & ec)2366 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2367 {
2368 UNUSED_PARAM(ec);
2369 if (isContextLost())
2370 return String();
2371 if (!validateWebGLObject(shader))
2372 return "";
2373 return shader->getSource();
2374 }
2375
getSupportedExtensions()2376 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2377 {
2378 Vector<String> result;
2379 if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2380 result.append("OES_texture_float");
2381 if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2382 result.append("OES_standard_derivatives");
2383 if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2384 result.append("OES_vertex_array_object");
2385 result.append("WEBKIT_lose_context");
2386 return result;
2387 }
2388
getTexParameter(GC3Denum target,GC3Denum pname,ExceptionCode & ec)2389 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2390 {
2391 UNUSED_PARAM(ec);
2392 if (isContextLost())
2393 return WebGLGetInfo();
2394 WebGLTexture* tex = validateTextureBinding(target, false);
2395 if (!tex)
2396 return WebGLGetInfo();
2397 WebGLStateRestorer(this, false);
2398 GC3Dint value = 0;
2399 switch (pname) {
2400 case GraphicsContext3D::TEXTURE_MAG_FILTER:
2401 case GraphicsContext3D::TEXTURE_MIN_FILTER:
2402 case GraphicsContext3D::TEXTURE_WRAP_S:
2403 case GraphicsContext3D::TEXTURE_WRAP_T:
2404 m_context->getTexParameteriv(target, pname, &value);
2405 return WebGLGetInfo(static_cast<unsigned int>(value));
2406 default:
2407 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2408 return WebGLGetInfo();
2409 }
2410 }
2411
getUniform(WebGLProgram * program,const WebGLUniformLocation * uniformLocation,ExceptionCode & ec)2412 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2413 {
2414 UNUSED_PARAM(ec);
2415 if (isContextLost() || !validateWebGLObject(program))
2416 return WebGLGetInfo();
2417 if (!uniformLocation || uniformLocation->program() != program) {
2418 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2419 return WebGLGetInfo();
2420 }
2421 GC3Dint location = uniformLocation->location();
2422
2423 WebGLStateRestorer(this, false);
2424 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2425 GC3Dint activeUniforms = 0;
2426 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2427 for (GC3Dint i = 0; i < activeUniforms; i++) {
2428 ActiveInfo info;
2429 if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2430 return WebGLGetInfo();
2431 // Strip "[0]" from the name if it's an array.
2432 if (info.size > 1)
2433 info.name = info.name.left(info.name.length() - 3);
2434 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2435 for (GC3Dint index = 0; index < info.size; ++index) {
2436 String name = info.name;
2437 if (info.size > 1 && index >= 1) {
2438 name.append('[');
2439 name.append(String::number(index));
2440 name.append(']');
2441 }
2442 // Now need to look this up by name again to find its location
2443 GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2444 if (loc == location) {
2445 // Found it. Use the type in the ActiveInfo to determine the return type.
2446 GC3Denum baseType;
2447 unsigned int length;
2448 switch (info.type) {
2449 case GraphicsContext3D::BOOL:
2450 baseType = GraphicsContext3D::BOOL;
2451 length = 1;
2452 break;
2453 case GraphicsContext3D::BOOL_VEC2:
2454 baseType = GraphicsContext3D::BOOL;
2455 length = 2;
2456 break;
2457 case GraphicsContext3D::BOOL_VEC3:
2458 baseType = GraphicsContext3D::BOOL;
2459 length = 3;
2460 break;
2461 case GraphicsContext3D::BOOL_VEC4:
2462 baseType = GraphicsContext3D::BOOL;
2463 length = 4;
2464 break;
2465 case GraphicsContext3D::INT:
2466 baseType = GraphicsContext3D::INT;
2467 length = 1;
2468 break;
2469 case GraphicsContext3D::INT_VEC2:
2470 baseType = GraphicsContext3D::INT;
2471 length = 2;
2472 break;
2473 case GraphicsContext3D::INT_VEC3:
2474 baseType = GraphicsContext3D::INT;
2475 length = 3;
2476 break;
2477 case GraphicsContext3D::INT_VEC4:
2478 baseType = GraphicsContext3D::INT;
2479 length = 4;
2480 break;
2481 case GraphicsContext3D::FLOAT:
2482 baseType = GraphicsContext3D::FLOAT;
2483 length = 1;
2484 break;
2485 case GraphicsContext3D::FLOAT_VEC2:
2486 baseType = GraphicsContext3D::FLOAT;
2487 length = 2;
2488 break;
2489 case GraphicsContext3D::FLOAT_VEC3:
2490 baseType = GraphicsContext3D::FLOAT;
2491 length = 3;
2492 break;
2493 case GraphicsContext3D::FLOAT_VEC4:
2494 baseType = GraphicsContext3D::FLOAT;
2495 length = 4;
2496 break;
2497 case GraphicsContext3D::FLOAT_MAT2:
2498 baseType = GraphicsContext3D::FLOAT;
2499 length = 4;
2500 break;
2501 case GraphicsContext3D::FLOAT_MAT3:
2502 baseType = GraphicsContext3D::FLOAT;
2503 length = 9;
2504 break;
2505 case GraphicsContext3D::FLOAT_MAT4:
2506 baseType = GraphicsContext3D::FLOAT;
2507 length = 16;
2508 break;
2509 case GraphicsContext3D::SAMPLER_2D:
2510 case GraphicsContext3D::SAMPLER_CUBE:
2511 baseType = GraphicsContext3D::INT;
2512 length = 1;
2513 break;
2514 default:
2515 // Can't handle this type
2516 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2517 return WebGLGetInfo();
2518 }
2519 switch (baseType) {
2520 case GraphicsContext3D::FLOAT: {
2521 GC3Dfloat value[16] = {0};
2522 m_context->getUniformfv(objectOrZero(program), location, value);
2523 if (length == 1)
2524 return WebGLGetInfo(value[0]);
2525 return WebGLGetInfo(Float32Array::create(value, length));
2526 }
2527 case GraphicsContext3D::INT: {
2528 GC3Dint value[4] = {0};
2529 m_context->getUniformiv(objectOrZero(program), location, value);
2530 if (length == 1)
2531 return WebGLGetInfo(value[0]);
2532 return WebGLGetInfo(Int32Array::create(value, length));
2533 }
2534 case GraphicsContext3D::BOOL: {
2535 GC3Dint value[4] = {0};
2536 m_context->getUniformiv(objectOrZero(program), location, value);
2537 if (length > 1) {
2538 bool boolValue[16] = {0};
2539 for (unsigned j = 0; j < length; j++)
2540 boolValue[j] = static_cast<bool>(value[j]);
2541 return WebGLGetInfo(boolValue, length);
2542 }
2543 return WebGLGetInfo(static_cast<bool>(value[0]));
2544 }
2545 default:
2546 notImplemented();
2547 }
2548 }
2549 }
2550 }
2551 // If we get here, something went wrong in our unfortunately complex logic above
2552 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2553 return WebGLGetInfo();
2554 }
2555
getUniformLocation(WebGLProgram * program,const String & name,ExceptionCode & ec)2556 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2557 {
2558 UNUSED_PARAM(ec);
2559 if (isContextLost() || !validateWebGLObject(program))
2560 return 0;
2561 if (!validateString(name))
2562 return 0;
2563 WebGLStateRestorer(this, false);
2564 GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2565 if (uniformLocation == -1)
2566 return 0;
2567 return WebGLUniformLocation::create(program, uniformLocation);
2568 }
2569
getVertexAttrib(GC3Duint index,GC3Denum pname,ExceptionCode & ec)2570 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2571 {
2572 UNUSED_PARAM(ec);
2573 if (isContextLost())
2574 return WebGLGetInfo();
2575 WebGLStateRestorer(this, false);
2576 if (index >= m_maxVertexAttribs) {
2577 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2578 return WebGLGetInfo();
2579 }
2580 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2581 switch (pname) {
2582 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2583 if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2584 || !state.bufferBinding
2585 || !state.bufferBinding->object())
2586 return WebGLGetInfo();
2587 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2588 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2589 return WebGLGetInfo(state.enabled);
2590 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2591 return WebGLGetInfo(state.normalized);
2592 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2593 return WebGLGetInfo(state.size);
2594 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2595 return WebGLGetInfo(state.originalStride);
2596 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2597 return WebGLGetInfo(state.type);
2598 case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2599 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2600 default:
2601 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2602 return WebGLGetInfo();
2603 }
2604 }
2605
getVertexAttribOffset(GC3Duint index,GC3Denum pname)2606 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2607 {
2608 if (isContextLost())
2609 return 0;
2610 GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2611 cleanupAfterGraphicsCall(false);
2612 return result;
2613 }
2614
hint(GC3Denum target,GC3Denum mode)2615 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
2616 {
2617 if (isContextLost())
2618 return;
2619 bool isValid = false;
2620 switch (target) {
2621 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2622 isValid = true;
2623 break;
2624 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2625 if (m_oesStandardDerivatives)
2626 isValid = true;
2627 break;
2628 }
2629 if (!isValid) {
2630 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2631 return;
2632 }
2633 m_context->hint(target, mode);
2634 cleanupAfterGraphicsCall(false);
2635 }
2636
isBuffer(WebGLBuffer * buffer)2637 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
2638 {
2639 if (!buffer || isContextLost())
2640 return 0;
2641
2642 if (!buffer->hasEverBeenBound())
2643 return 0;
2644
2645 return m_context->isBuffer(buffer->object());
2646 }
2647
isContextLost()2648 bool WebGLRenderingContext::isContextLost()
2649 {
2650 if (m_restoreTimer.isActive())
2651 return true;
2652
2653 bool newContextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR;
2654
2655 if (newContextLost != m_contextLost)
2656 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
2657
2658 return m_contextLost;
2659 }
2660
isEnabled(GC3Denum cap)2661 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
2662 {
2663 if (!validateCapability(cap) || isContextLost())
2664 return 0;
2665 return m_context->isEnabled(cap);
2666 }
2667
isFramebuffer(WebGLFramebuffer * framebuffer)2668 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
2669 {
2670 if (!framebuffer || isContextLost())
2671 return 0;
2672
2673 if (!framebuffer->hasEverBeenBound())
2674 return 0;
2675
2676 return m_context->isFramebuffer(framebuffer->object());
2677 }
2678
isProgram(WebGLProgram * program)2679 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
2680 {
2681 if (!program || isContextLost())
2682 return 0;
2683
2684 return m_context->isProgram(program->object());
2685 }
2686
isRenderbuffer(WebGLRenderbuffer * renderbuffer)2687 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2688 {
2689 if (!renderbuffer || isContextLost())
2690 return 0;
2691
2692 if (!renderbuffer->hasEverBeenBound())
2693 return 0;
2694
2695 return m_context->isRenderbuffer(renderbuffer->object());
2696 }
2697
isShader(WebGLShader * shader)2698 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
2699 {
2700 if (!shader || isContextLost())
2701 return 0;
2702
2703 return m_context->isShader(shader->object());
2704 }
2705
isTexture(WebGLTexture * texture)2706 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
2707 {
2708 if (!texture || isContextLost())
2709 return 0;
2710
2711 if (!texture->hasEverBeenBound())
2712 return 0;
2713
2714 return m_context->isTexture(texture->object());
2715 }
2716
lineWidth(GC3Dfloat width)2717 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
2718 {
2719 if (isContextLost())
2720 return;
2721 m_context->lineWidth(width);
2722 cleanupAfterGraphicsCall(false);
2723 }
2724
linkProgram(WebGLProgram * program,ExceptionCode & ec)2725 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2726 {
2727 UNUSED_PARAM(ec);
2728 if (isContextLost() || !validateWebGLObject(program))
2729 return;
2730 if (!isGLES2Compliant()) {
2731 if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
2732 program->setLinkStatus(false);
2733 return;
2734 }
2735 }
2736
2737 m_context->linkProgram(objectOrZero(program));
2738 program->increaseLinkCount();
2739 // cache link status
2740 GC3Dint value = 0;
2741 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value);
2742 program->setLinkStatus(static_cast<bool>(value));
2743 // Need to cache link status before caching active attribute locations.
2744 program->cacheActiveAttribLocations();
2745 cleanupAfterGraphicsCall(false);
2746 }
2747
pixelStorei(GC3Denum pname,GC3Dint param)2748 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
2749 {
2750 if (isContextLost())
2751 return;
2752 switch (pname) {
2753 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2754 m_unpackFlipY = param;
2755 break;
2756 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2757 m_unpackPremultiplyAlpha = param;
2758 break;
2759 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2760 if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2761 m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2762 else {
2763 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2764 return;
2765 }
2766 break;
2767 case GraphicsContext3D::PACK_ALIGNMENT:
2768 case GraphicsContext3D::UNPACK_ALIGNMENT:
2769 if (param == 1 || param == 2 || param == 4 || param == 8) {
2770 if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2771 m_packAlignment = param;
2772 else // GraphicsContext3D::UNPACK_ALIGNMENT:
2773 m_unpackAlignment = param;
2774 m_context->pixelStorei(pname, param);
2775 cleanupAfterGraphicsCall(false);
2776 } else {
2777 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2778 return;
2779 }
2780 break;
2781 default:
2782 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2783 return;
2784 }
2785 }
2786
polygonOffset(GC3Dfloat factor,GC3Dfloat units)2787 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2788 {
2789 if (isContextLost())
2790 return;
2791 m_context->polygonOffset(factor, units);
2792 cleanupAfterGraphicsCall(false);
2793 }
2794
readPixels(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)2795 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
2796 {
2797 if (isContextLost())
2798 return;
2799 if (!canvas()->originClean()) {
2800 ec = SECURITY_ERR;
2801 return;
2802 }
2803 // Validate input parameters.
2804 if (!pixels) {
2805 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
2806 return;
2807 }
2808 switch (format) {
2809 case GraphicsContext3D::ALPHA:
2810 case GraphicsContext3D::RGB:
2811 case GraphicsContext3D::RGBA:
2812 break;
2813 default:
2814 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2815 return;
2816 }
2817 switch (type) {
2818 case GraphicsContext3D::UNSIGNED_BYTE:
2819 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
2820 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
2821 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
2822 break;
2823 default:
2824 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2825 return;
2826 }
2827 if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2828 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2829 return;
2830 }
2831 // Validate array type against pixel type.
2832 if (!pixels->isUnsignedByteArray()) {
2833 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2834 return;
2835 }
2836 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) {
2837 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION);
2838 return;
2839 }
2840 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2841 unsigned int totalBytesRequired;
2842 unsigned int padding;
2843 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2844 if (error != GraphicsContext3D::NO_ERROR) {
2845 m_context->synthesizeGLError(error);
2846 return;
2847 }
2848 if (pixels->byteLength() < totalBytesRequired) {
2849 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2850 return;
2851 }
2852 clearIfComposited();
2853 void* data = pixels->baseAddress();
2854 m_context->readPixels(x, y, width, height, format, type, data);
2855 #if OS(DARWIN)
2856 // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
2857 // when alpha is off, readPixels should set alpha to 255 instead of 0.
2858 if (!m_context->getContextAttributes().alpha) {
2859 unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2860 for (GC3Dsizei iy = 0; iy < height; ++iy) {
2861 for (GC3Dsizei ix = 0; ix < width; ++ix) {
2862 pixels[3] = 255;
2863 pixels += 4;
2864 }
2865 pixels += padding;
2866 }
2867 }
2868 #endif
2869 cleanupAfterGraphicsCall(false);
2870 }
2871
releaseShaderCompiler()2872 void WebGLRenderingContext::releaseShaderCompiler()
2873 {
2874 if (isContextLost())
2875 return;
2876 m_context->releaseShaderCompiler();
2877 cleanupAfterGraphicsCall(false);
2878 }
2879
renderbufferStorage(GC3Denum target,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height)2880 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
2881 {
2882 if (isContextLost())
2883 return;
2884 if (target != GraphicsContext3D::RENDERBUFFER) {
2885 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2886 return;
2887 }
2888 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2889 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
2890 return;
2891 }
2892 if (!validateSize(width, height))
2893 return;
2894 switch (internalformat) {
2895 case GraphicsContext3D::DEPTH_COMPONENT16:
2896 case GraphicsContext3D::RGBA4:
2897 case GraphicsContext3D::RGB5_A1:
2898 case GraphicsContext3D::RGB565:
2899 case GraphicsContext3D::STENCIL_INDEX8:
2900 m_context->renderbufferStorage(target, internalformat, width, height);
2901 m_renderbufferBinding->setInternalFormat(internalformat);
2902 m_renderbufferBinding->setIsValid(true);
2903 m_renderbufferBinding->setSize(width, height);
2904 cleanupAfterGraphicsCall(false);
2905 break;
2906 case GraphicsContext3D::DEPTH_STENCIL:
2907 if (isDepthStencilSupported()) {
2908 m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height);
2909 cleanupAfterGraphicsCall(false);
2910 }
2911 m_renderbufferBinding->setSize(width, height);
2912 m_renderbufferBinding->setIsValid(isDepthStencilSupported());
2913 m_renderbufferBinding->setInternalFormat(internalformat);
2914 break;
2915 default:
2916 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2917 }
2918 }
2919
sampleCoverage(GC3Dfloat value,GC3Dboolean invert)2920 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
2921 {
2922 if (isContextLost())
2923 return;
2924 m_context->sampleCoverage(value, invert);
2925 cleanupAfterGraphicsCall(false);
2926 }
2927
scissor(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)2928 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
2929 {
2930 if (isContextLost())
2931 return;
2932 if (!validateSize(width, height))
2933 return;
2934 m_context->scissor(x, y, width, height);
2935 cleanupAfterGraphicsCall(false);
2936 }
2937
shaderSource(WebGLShader * shader,const String & string,ExceptionCode & ec)2938 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
2939 {
2940 UNUSED_PARAM(ec);
2941 if (isContextLost() || !validateWebGLObject(shader))
2942 return;
2943 String stringWithoutComments = StripComments(string).result();
2944 if (!validateString(stringWithoutComments))
2945 return;
2946 shader->setSource(string);
2947 m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
2948 cleanupAfterGraphicsCall(false);
2949 }
2950
stencilFunc(GC3Denum func,GC3Dint ref,GC3Duint mask)2951 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
2952 {
2953 if (isContextLost())
2954 return;
2955 if (!validateStencilFunc(func))
2956 return;
2957 m_stencilFuncRef = ref;
2958 m_stencilFuncRefBack = ref;
2959 m_stencilFuncMask = mask;
2960 m_stencilFuncMaskBack = mask;
2961 m_context->stencilFunc(func, ref, mask);
2962 cleanupAfterGraphicsCall(false);
2963 }
2964
stencilFuncSeparate(GC3Denum face,GC3Denum func,GC3Dint ref,GC3Duint mask)2965 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
2966 {
2967 if (isContextLost())
2968 return;
2969 if (!validateStencilFunc(func))
2970 return;
2971 switch (face) {
2972 case GraphicsContext3D::FRONT_AND_BACK:
2973 m_stencilFuncRef = ref;
2974 m_stencilFuncRefBack = ref;
2975 m_stencilFuncMask = mask;
2976 m_stencilFuncMaskBack = mask;
2977 break;
2978 case GraphicsContext3D::FRONT:
2979 m_stencilFuncRef = ref;
2980 m_stencilFuncMask = mask;
2981 break;
2982 case GraphicsContext3D::BACK:
2983 m_stencilFuncRefBack = ref;
2984 m_stencilFuncMaskBack = mask;
2985 break;
2986 default:
2987 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
2988 return;
2989 }
2990 m_context->stencilFuncSeparate(face, func, ref, mask);
2991 cleanupAfterGraphicsCall(false);
2992 }
2993
stencilMask(GC3Duint mask)2994 void WebGLRenderingContext::stencilMask(GC3Duint mask)
2995 {
2996 if (isContextLost())
2997 return;
2998 m_stencilMask = mask;
2999 m_stencilMaskBack = mask;
3000 m_context->stencilMask(mask);
3001 cleanupAfterGraphicsCall(false);
3002 }
3003
stencilMaskSeparate(GC3Denum face,GC3Duint mask)3004 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
3005 {
3006 if (isContextLost())
3007 return;
3008 switch (face) {
3009 case GraphicsContext3D::FRONT_AND_BACK:
3010 m_stencilMask = mask;
3011 m_stencilMaskBack = mask;
3012 break;
3013 case GraphicsContext3D::FRONT:
3014 m_stencilMask = mask;
3015 break;
3016 case GraphicsContext3D::BACK:
3017 m_stencilMaskBack = mask;
3018 break;
3019 default:
3020 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3021 return;
3022 }
3023 m_context->stencilMaskSeparate(face, mask);
3024 cleanupAfterGraphicsCall(false);
3025 }
3026
stencilOp(GC3Denum fail,GC3Denum zfail,GC3Denum zpass)3027 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3028 {
3029 if (isContextLost())
3030 return;
3031 m_context->stencilOp(fail, zfail, zpass);
3032 cleanupAfterGraphicsCall(false);
3033 }
3034
stencilOpSeparate(GC3Denum face,GC3Denum fail,GC3Denum zfail,GC3Denum zpass)3035 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
3036 {
3037 if (isContextLost())
3038 return;
3039 m_context->stencilOpSeparate(face, fail, zfail, zpass);
3040 cleanupAfterGraphicsCall(false);
3041 }
3042
texImage2DBase(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type,void * pixels,ExceptionCode & ec)3043 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3044 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3045 GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3046 {
3047 // FIXME: For now we ignore any errors returned
3048 ec = 0;
3049 if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type))
3050 return;
3051 WebGLTexture* tex = validateTextureBinding(target, true);
3052 if (!tex)
3053 return;
3054 if (!isGLES2NPOTStrict()) {
3055 if (level && WebGLTexture::isNPOT(width, height)) {
3056 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3057 return;
3058 }
3059 }
3060 if (!pixels && !isResourceSafe()) {
3061 bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3062 border, format, type, m_unpackAlignment);
3063 if (!succeed)
3064 return;
3065 } else {
3066 m_context->texImage2D(target, level, internalformat, width, height,
3067 border, format, type, pixels);
3068 }
3069 tex->setLevelInfo(target, level, internalformat, width, height, type);
3070 cleanupAfterGraphicsCall(false);
3071 }
3072
texImage2DImpl(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,Image * image,bool flipY,bool premultiplyAlpha,ExceptionCode & ec)3073 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3074 GC3Denum format, GC3Denum type, Image* image,
3075 bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3076 {
3077 ec = 0;
3078 Vector<uint8_t> data;
3079 if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3080 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3081 return;
3082 }
3083 if (m_unpackAlignment != 1)
3084 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3085 texImage2DBase(target, level, internalformat, image->width(), image->height(), 0,
3086 format, type, data.data(), ec);
3087 if (m_unpackAlignment != 1)
3088 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3089 }
3090
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)3091 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3092 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3093 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3094 {
3095 if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3096 return;
3097 void* data = pixels ? pixels->baseAddress() : 0;
3098 Vector<uint8_t> tempData;
3099 bool changeUnpackAlignment = false;
3100 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3101 if (!m_context->extractTextureData(width, height, format, type,
3102 m_unpackAlignment,
3103 m_unpackFlipY, m_unpackPremultiplyAlpha,
3104 data,
3105 tempData))
3106 return;
3107 data = tempData.data();
3108 changeUnpackAlignment = true;
3109 }
3110 if (changeUnpackAlignment)
3111 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3112 texImage2DBase(target, level, internalformat, width, height, border,
3113 format, type, data, ec);
3114 if (changeUnpackAlignment)
3115 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3116 }
3117
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,ImageData * pixels,ExceptionCode & ec)3118 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3119 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3120 {
3121 ec = 0;
3122 if (isContextLost())
3123 return;
3124 Vector<uint8_t> data;
3125 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3126 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3127 return;
3128 }
3129 if (m_unpackAlignment != 1)
3130 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3131 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0,
3132 format, type, data.data(), ec);
3133 if (m_unpackAlignment != 1)
3134 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3135 }
3136
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLImageElement * image,ExceptionCode & ec)3137 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3138 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3139 {
3140 ec = 0;
3141 if (isContextLost())
3142 return;
3143 if (!validateHTMLImageElement(image))
3144 return;
3145 checkOrigin(image);
3146 texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(),
3147 m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3148 }
3149
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLCanvasElement * canvas,ExceptionCode & ec)3150 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3151 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3152 {
3153 ec = 0;
3154 if (isContextLost())
3155 return;
3156 if (!canvas || !canvas->buffer()) {
3157 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3158 return;
3159 }
3160 checkOrigin(canvas);
3161 RefPtr<ImageData> imageData = canvas->getImageData();
3162 if (imageData)
3163 texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3164 else
3165 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(),
3166 m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3167 }
3168
3169 #if ENABLE(VIDEO)
videoFrameToImage(HTMLVideoElement * video)3170 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video)
3171 {
3172 if (!video || !video->videoWidth() || !video->videoHeight()) {
3173 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3174 return 0;
3175 }
3176 IntSize size(video->videoWidth(), video->videoHeight());
3177 ImageBuffer* buf = m_videoCache.imageBuffer(size);
3178 if (!buf) {
3179 m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY);
3180 return 0;
3181 }
3182 checkOrigin(video);
3183 IntRect destRect(0, 0, size.width(), size.height());
3184 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3185 video->paintCurrentFrameInContext(buf->context(), destRect);
3186 return buf->copyImage();
3187 }
3188
texImage2D(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Denum format,GC3Denum type,HTMLVideoElement * video,ExceptionCode & ec)3189 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3190 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3191 {
3192 ec = 0;
3193 if (isContextLost())
3194 return;
3195 RefPtr<Image> image = videoFrameToImage(video);
3196 if (!video)
3197 return;
3198 texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3199 }
3200 #endif
3201
texParameter(GC3Denum target,GC3Denum pname,GC3Dfloat paramf,GC3Dint parami,bool isFloat)3202 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat)
3203 {
3204 if (isContextLost())
3205 return;
3206 WebGLTexture* tex = validateTextureBinding(target, false);
3207 if (!tex)
3208 return;
3209 switch (pname) {
3210 case GraphicsContext3D::TEXTURE_MIN_FILTER:
3211 case GraphicsContext3D::TEXTURE_MAG_FILTER:
3212 break;
3213 case GraphicsContext3D::TEXTURE_WRAP_S:
3214 case GraphicsContext3D::TEXTURE_WRAP_T:
3215 if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT)
3216 || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) {
3217 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3218 return;
3219 }
3220 break;
3221 default:
3222 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3223 return;
3224 }
3225 if (isFloat) {
3226 tex->setParameterf(pname, paramf);
3227 m_context->texParameterf(target, pname, paramf);
3228 } else {
3229 tex->setParameteri(pname, parami);
3230 m_context->texParameteri(target, pname, parami);
3231 }
3232 cleanupAfterGraphicsCall(false);
3233 }
3234
texParameterf(GC3Denum target,GC3Denum pname,GC3Dfloat param)3235 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param)
3236 {
3237 texParameter(target, pname, param, 0, true);
3238 }
3239
texParameteri(GC3Denum target,GC3Denum pname,GC3Dint param)3240 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param)
3241 {
3242 texParameter(target, pname, 0, param, false);
3243 }
3244
texSubImage2DBase(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,void * pixels,ExceptionCode & ec)3245 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3246 GC3Dsizei width, GC3Dsizei height,
3247 GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec)
3248 {
3249 // FIXME: For now we ignore any errors returned
3250 ec = 0;
3251 if (isContextLost())
3252 return;
3253 if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type))
3254 return;
3255 if (!validateSize(xoffset, yoffset))
3256 return;
3257 WebGLTexture* tex = validateTextureBinding(target, true);
3258 if (!tex)
3259 return;
3260 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
3261 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3262 return;
3263 }
3264 if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) {
3265 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3266 return;
3267 }
3268 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3269 cleanupAfterGraphicsCall(false);
3270 }
3271
texSubImage2DImpl(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,Image * image,bool flipY,bool premultiplyAlpha,ExceptionCode & ec)3272 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3273 GC3Denum format, GC3Denum type,
3274 Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3275 {
3276 ec = 0;
3277 if (isContextLost())
3278 return;
3279 Vector<uint8_t> data;
3280 if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) {
3281 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3282 return;
3283 }
3284 texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(),
3285 format, type, data.data(), ec);
3286 }
3287
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels,ExceptionCode & ec)3288 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3289 GC3Dsizei width, GC3Dsizei height,
3290 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3291 {
3292 if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels))
3293 return;
3294 void* data = pixels ? pixels->baseAddress() : 0;
3295 Vector<uint8_t> tempData;
3296 bool changeUnpackAlignment = false;
3297 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3298 if (!m_context->extractTextureData(width, height, format, type,
3299 m_unpackAlignment,
3300 m_unpackFlipY, m_unpackPremultiplyAlpha,
3301 data,
3302 tempData))
3303 return;
3304 data = tempData.data();
3305 changeUnpackAlignment = true;
3306 }
3307 if (changeUnpackAlignment)
3308 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3309 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec);
3310 if (changeUnpackAlignment)
3311 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3312 }
3313
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,ImageData * pixels,ExceptionCode & ec)3314 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3315 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3316 {
3317 ec = 0;
3318 if (isContextLost())
3319 return;
3320 Vector<uint8_t> data;
3321 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3322 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3323 return;
3324 }
3325 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(),
3326 format, type, data.data(), ec);
3327 }
3328
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLImageElement * image,ExceptionCode & ec)3329 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3330 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3331 {
3332 ec = 0;
3333 if (isContextLost())
3334 return;
3335 if (!validateHTMLImageElement(image))
3336 return;
3337 checkOrigin(image);
3338 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(),
3339 m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3340 }
3341
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLCanvasElement * canvas,ExceptionCode & ec)3342 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3343 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3344 {
3345 ec = 0;
3346 if (isContextLost())
3347 return;
3348 if (!canvas || !canvas->buffer()) {
3349 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3350 return;
3351 }
3352 checkOrigin(canvas);
3353 RefPtr<ImageData> imageData = canvas->getImageData();
3354 if (imageData)
3355 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec);
3356 else
3357 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(),
3358 m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3359 }
3360
3361 #if ENABLE(VIDEO)
texSubImage2D(GC3Denum target,GC3Dint level,GC3Dint xoffset,GC3Dint yoffset,GC3Denum format,GC3Denum type,HTMLVideoElement * video,ExceptionCode & ec)3362 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
3363 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec)
3364 {
3365 ec = 0;
3366 if (isContextLost())
3367 return;
3368 RefPtr<Image> image = videoFrameToImage(video);
3369 if (!video)
3370 return;
3371 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3372 }
3373 #endif
3374
uniform1f(const WebGLUniformLocation * location,GC3Dfloat x,ExceptionCode & ec)3375 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec)
3376 {
3377 UNUSED_PARAM(ec);
3378 if (isContextLost() || !location)
3379 return;
3380
3381 if (location->program() != m_currentProgram) {
3382 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3383 return;
3384 }
3385
3386 m_context->uniform1f(location->location(), x);
3387 cleanupAfterGraphicsCall(false);
3388 }
3389
uniform1fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3390 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3391 {
3392 UNUSED_PARAM(ec);
3393 if (isContextLost() || !validateUniformParameters(location, v, 1))
3394 return;
3395
3396 m_context->uniform1fv(location->location(), v->data(), v->length());
3397 cleanupAfterGraphicsCall(false);
3398 }
3399
uniform1fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3400 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3401 {
3402 UNUSED_PARAM(ec);
3403 if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3404 return;
3405
3406 m_context->uniform1fv(location->location(), v, size);
3407 cleanupAfterGraphicsCall(false);
3408 }
3409
uniform1i(const WebGLUniformLocation * location,GC3Dint x,ExceptionCode & ec)3410 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec)
3411 {
3412 UNUSED_PARAM(ec);
3413 if (isContextLost() || !location)
3414 return;
3415
3416 if (location->program() != m_currentProgram) {
3417 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3418 return;
3419 }
3420
3421 m_context->uniform1i(location->location(), x);
3422 cleanupAfterGraphicsCall(false);
3423 }
3424
uniform1iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3425 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3426 {
3427 UNUSED_PARAM(ec);
3428 if (isContextLost() || !validateUniformParameters(location, v, 1))
3429 return;
3430
3431 m_context->uniform1iv(location->location(), v->data(), v->length());
3432 cleanupAfterGraphicsCall(false);
3433 }
3434
uniform1iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3435 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3436 {
3437 UNUSED_PARAM(ec);
3438 if (isContextLost() || !validateUniformParameters(location, v, size, 1))
3439 return;
3440
3441 m_context->uniform1iv(location->location(), v, size);
3442 cleanupAfterGraphicsCall(false);
3443 }
3444
uniform2f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,ExceptionCode & ec)3445 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec)
3446 {
3447 UNUSED_PARAM(ec);
3448 if (isContextLost() || !location)
3449 return;
3450
3451 if (location->program() != m_currentProgram) {
3452 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3453 return;
3454 }
3455
3456 m_context->uniform2f(location->location(), x, y);
3457 cleanupAfterGraphicsCall(false);
3458 }
3459
uniform2fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3460 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3461 {
3462 UNUSED_PARAM(ec);
3463 if (isContextLost() || !validateUniformParameters(location, v, 2))
3464 return;
3465
3466 m_context->uniform2fv(location->location(), v->data(), v->length() / 2);
3467 cleanupAfterGraphicsCall(false);
3468 }
3469
uniform2fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3470 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3471 {
3472 UNUSED_PARAM(ec);
3473 if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3474 return;
3475
3476 m_context->uniform2fv(location->location(), v, size / 2);
3477 cleanupAfterGraphicsCall(false);
3478 }
3479
uniform2i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,ExceptionCode & ec)3480 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec)
3481 {
3482 UNUSED_PARAM(ec);
3483 if (isContextLost() || !location)
3484 return;
3485
3486 if (location->program() != m_currentProgram) {
3487 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3488 return;
3489 }
3490
3491 m_context->uniform2i(location->location(), x, y);
3492 cleanupAfterGraphicsCall(false);
3493 }
3494
uniform2iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3495 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3496 {
3497 UNUSED_PARAM(ec);
3498 if (isContextLost() || !validateUniformParameters(location, v, 2))
3499 return;
3500
3501 m_context->uniform2iv(location->location(), v->data(), v->length() / 2);
3502 cleanupAfterGraphicsCall(false);
3503 }
3504
uniform2iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3505 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3506 {
3507 UNUSED_PARAM(ec);
3508 if (isContextLost() || !validateUniformParameters(location, v, size, 2))
3509 return;
3510
3511 m_context->uniform2iv(location->location(), v, size / 2);
3512 cleanupAfterGraphicsCall(false);
3513 }
3514
uniform3f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,GC3Dfloat z,ExceptionCode & ec)3515 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec)
3516 {
3517 UNUSED_PARAM(ec);
3518 if (isContextLost() || !location)
3519 return;
3520
3521 if (location->program() != m_currentProgram) {
3522 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3523 return;
3524 }
3525
3526 m_context->uniform3f(location->location(), x, y, z);
3527 cleanupAfterGraphicsCall(false);
3528 }
3529
uniform3fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3530 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3531 {
3532 UNUSED_PARAM(ec);
3533 if (isContextLost() || !validateUniformParameters(location, v, 3))
3534 return;
3535
3536 m_context->uniform3fv(location->location(), v->data(), v->length() / 3);
3537 cleanupAfterGraphicsCall(false);
3538 }
3539
uniform3fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3540 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3541 {
3542 UNUSED_PARAM(ec);
3543 if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3544 return;
3545
3546 m_context->uniform3fv(location->location(), v, size / 3);
3547 cleanupAfterGraphicsCall(false);
3548 }
3549
uniform3i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,GC3Dint z,ExceptionCode & ec)3550 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec)
3551 {
3552 UNUSED_PARAM(ec);
3553 if (isContextLost() || !location)
3554 return;
3555
3556 if (location->program() != m_currentProgram) {
3557 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3558 return;
3559 }
3560
3561 m_context->uniform3i(location->location(), x, y, z);
3562 cleanupAfterGraphicsCall(false);
3563 }
3564
uniform3iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3565 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3566 {
3567 UNUSED_PARAM(ec);
3568 if (isContextLost() || !validateUniformParameters(location, v, 3))
3569 return;
3570
3571 m_context->uniform3iv(location->location(), v->data(), v->length() / 3);
3572 cleanupAfterGraphicsCall(false);
3573 }
3574
uniform3iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3575 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3576 {
3577 UNUSED_PARAM(ec);
3578 if (isContextLost() || !validateUniformParameters(location, v, size, 3))
3579 return;
3580
3581 m_context->uniform3iv(location->location(), v, size / 3);
3582 cleanupAfterGraphicsCall(false);
3583 }
3584
uniform4f(const WebGLUniformLocation * location,GC3Dfloat x,GC3Dfloat y,GC3Dfloat z,GC3Dfloat w,ExceptionCode & ec)3585 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec)
3586 {
3587 UNUSED_PARAM(ec);
3588 if (isContextLost() || !location)
3589 return;
3590
3591 if (location->program() != m_currentProgram) {
3592 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3593 return;
3594 }
3595
3596 m_context->uniform4f(location->location(), x, y, z, w);
3597 cleanupAfterGraphicsCall(false);
3598 }
3599
uniform4fv(const WebGLUniformLocation * location,Float32Array * v,ExceptionCode & ec)3600 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec)
3601 {
3602 UNUSED_PARAM(ec);
3603 if (isContextLost() || !validateUniformParameters(location, v, 4))
3604 return;
3605
3606 m_context->uniform4fv(location->location(), v->data(), v->length() / 4);
3607 cleanupAfterGraphicsCall(false);
3608 }
3609
uniform4fv(const WebGLUniformLocation * location,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3610 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3611 {
3612 UNUSED_PARAM(ec);
3613 if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3614 return;
3615
3616 m_context->uniform4fv(location->location(), v, size / 4);
3617 cleanupAfterGraphicsCall(false);
3618 }
3619
uniform4i(const WebGLUniformLocation * location,GC3Dint x,GC3Dint y,GC3Dint z,GC3Dint w,ExceptionCode & ec)3620 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec)
3621 {
3622 UNUSED_PARAM(ec);
3623 if (isContextLost() || !location)
3624 return;
3625
3626 if (location->program() != m_currentProgram) {
3627 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3628 return;
3629 }
3630
3631 m_context->uniform4i(location->location(), x, y, z, w);
3632 cleanupAfterGraphicsCall(false);
3633 }
3634
uniform4iv(const WebGLUniformLocation * location,Int32Array * v,ExceptionCode & ec)3635 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec)
3636 {
3637 UNUSED_PARAM(ec);
3638 if (isContextLost() || !validateUniformParameters(location, v, 4))
3639 return;
3640
3641 m_context->uniform4iv(location->location(), v->data(), v->length() / 4);
3642 cleanupAfterGraphicsCall(false);
3643 }
3644
uniform4iv(const WebGLUniformLocation * location,GC3Dint * v,GC3Dsizei size,ExceptionCode & ec)3645 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec)
3646 {
3647 UNUSED_PARAM(ec);
3648 if (isContextLost() || !validateUniformParameters(location, v, size, 4))
3649 return;
3650
3651 m_context->uniform4iv(location->location(), v, size / 4);
3652 cleanupAfterGraphicsCall(false);
3653 }
3654
uniformMatrix2fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3655 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3656 {
3657 UNUSED_PARAM(ec);
3658 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4))
3659 return;
3660 m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4);
3661 cleanupAfterGraphicsCall(false);
3662 }
3663
uniformMatrix2fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3664 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3665 {
3666 UNUSED_PARAM(ec);
3667 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4))
3668 return;
3669 m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4);
3670 cleanupAfterGraphicsCall(false);
3671 }
3672
uniformMatrix3fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3673 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3674 {
3675 UNUSED_PARAM(ec);
3676 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9))
3677 return;
3678 m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9);
3679 cleanupAfterGraphicsCall(false);
3680 }
3681
uniformMatrix3fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3682 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3683 {
3684 UNUSED_PARAM(ec);
3685 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9))
3686 return;
3687 m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9);
3688 cleanupAfterGraphicsCall(false);
3689 }
3690
uniformMatrix4fv(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,ExceptionCode & ec)3691 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec)
3692 {
3693 UNUSED_PARAM(ec);
3694 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16))
3695 return;
3696 m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16);
3697 cleanupAfterGraphicsCall(false);
3698 }
3699
uniformMatrix4fv(const WebGLUniformLocation * location,GC3Dboolean transpose,GC3Dfloat * v,GC3Dsizei size,ExceptionCode & ec)3700 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec)
3701 {
3702 UNUSED_PARAM(ec);
3703 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16))
3704 return;
3705 m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16);
3706 cleanupAfterGraphicsCall(false);
3707 }
3708
useProgram(WebGLProgram * program,ExceptionCode & ec)3709 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
3710 {
3711 UNUSED_PARAM(ec);
3712 bool deleted;
3713 if (!checkObjectToBeBound(program, deleted))
3714 return;
3715 if (deleted)
3716 program = 0;
3717 if (program && !program->getLinkStatus()) {
3718 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3719 cleanupAfterGraphicsCall(false);
3720 return;
3721 }
3722 if (m_currentProgram != program) {
3723 if (m_currentProgram)
3724 m_currentProgram->onDetached();
3725 m_currentProgram = program;
3726 m_context->useProgram(objectOrZero(program));
3727 if (program)
3728 program->onAttached();
3729 }
3730 cleanupAfterGraphicsCall(false);
3731 }
3732
validateProgram(WebGLProgram * program,ExceptionCode & ec)3733 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec)
3734 {
3735 UNUSED_PARAM(ec);
3736 if (isContextLost() || !validateWebGLObject(program))
3737 return;
3738 m_context->validateProgram(objectOrZero(program));
3739 cleanupAfterGraphicsCall(false);
3740 }
3741
vertexAttrib1f(GC3Duint index,GC3Dfloat v0)3742 void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
3743 {
3744 vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f);
3745 }
3746
vertexAttrib1fv(GC3Duint index,Float32Array * v)3747 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v)
3748 {
3749 vertexAttribfvImpl(index, v, 1);
3750 }
3751
vertexAttrib1fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3752 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3753 {
3754 vertexAttribfvImpl(index, v, size, 1);
3755 }
3756
vertexAttrib2f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1)3757 void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
3758 {
3759 vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f);
3760 }
3761
vertexAttrib2fv(GC3Duint index,Float32Array * v)3762 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v)
3763 {
3764 vertexAttribfvImpl(index, v, 2);
3765 }
3766
vertexAttrib2fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3767 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3768 {
3769 vertexAttribfvImpl(index, v, size, 2);
3770 }
3771
vertexAttrib3f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2)3772 void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
3773 {
3774 vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f);
3775 }
3776
vertexAttrib3fv(GC3Duint index,Float32Array * v)3777 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v)
3778 {
3779 vertexAttribfvImpl(index, v, 3);
3780 }
3781
vertexAttrib3fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3782 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3783 {
3784 vertexAttribfvImpl(index, v, size, 3);
3785 }
3786
vertexAttrib4f(GC3Duint index,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2,GC3Dfloat v3)3787 void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
3788 {
3789 vertexAttribfImpl(index, 4, v0, v1, v2, v3);
3790 }
3791
vertexAttrib4fv(GC3Duint index,Float32Array * v)3792 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v)
3793 {
3794 vertexAttribfvImpl(index, v, 4);
3795 }
3796
vertexAttrib4fv(GC3Duint index,GC3Dfloat * v,GC3Dsizei size)3797 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size)
3798 {
3799 vertexAttribfvImpl(index, v, size, 4);
3800 }
3801
vertexAttribPointer(GC3Duint index,GC3Dint size,GC3Denum type,GC3Dboolean normalized,GC3Dsizei stride,GC3Dintptr offset,ExceptionCode & ec)3802 void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec)
3803 {
3804 UNUSED_PARAM(ec);
3805 if (isContextLost())
3806 return;
3807 switch (type) {
3808 case GraphicsContext3D::BYTE:
3809 case GraphicsContext3D::UNSIGNED_BYTE:
3810 case GraphicsContext3D::SHORT:
3811 case GraphicsContext3D::UNSIGNED_SHORT:
3812 case GraphicsContext3D::FLOAT:
3813 break;
3814 default:
3815 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3816 return;
3817 }
3818 if (index >= m_maxVertexAttribs) {
3819 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3820 return;
3821 }
3822 if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) {
3823 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
3824 return;
3825 }
3826 if (!m_boundArrayBuffer) {
3827 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3828 return;
3829 }
3830 // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
3831 unsigned int typeSize = sizeInBytes(type);
3832 if (!typeSize) {
3833 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
3834 return;
3835 }
3836 if ((stride % typeSize) || (offset % typeSize)) {
3837 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3838 return;
3839 }
3840 GC3Dsizei bytesPerElement = size * typeSize;
3841
3842 GC3Dsizei validatedStride = stride ? stride : bytesPerElement;
3843
3844 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
3845 state.bufferBinding = m_boundArrayBuffer;
3846 state.bytesPerElement = bytesPerElement;
3847 state.size = size;
3848 state.type = type;
3849 state.normalized = normalized;
3850 state.stride = validatedStride;
3851 state.originalStride = stride;
3852 state.offset = offset;
3853 m_context->vertexAttribPointer(index, size, type, normalized, stride, offset);
3854 cleanupAfterGraphicsCall(false);
3855 }
3856
viewport(GC3Dint x,GC3Dint y,GC3Dsizei width,GC3Dsizei height)3857 void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
3858 {
3859 if (isContextLost())
3860 return;
3861 if (isnan(x))
3862 x = 0;
3863 if (isnan(y))
3864 y = 0;
3865 if (isnan(width))
3866 width = 100;
3867 if (isnan(height))
3868 height = 100;
3869 if (!validateSize(width, height))
3870 return;
3871 m_context->viewport(x, y, width, height);
3872 cleanupAfterGraphicsCall(false);
3873 }
3874
forceLostContext()3875 void WebGLRenderingContext::forceLostContext()
3876 {
3877 if (isContextLost()) {
3878 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
3879 return;
3880 }
3881
3882 m_restoreTimer.startOneShot(0);
3883 }
3884
onLostContext()3885 void WebGLRenderingContext::onLostContext()
3886 {
3887 m_contextLost = true;
3888
3889 detachAndRemoveAllObjects();
3890
3891 // There is no direct way to clear errors from a GL implementation and
3892 // looping until getError() becomes NO_ERROR might cause an infinite loop if
3893 // the driver or context implementation had a bug. So, loop a reasonably
3894 // large number of times to clear any existing errors.
3895 for (int i = 0; i < 100; ++i) {
3896 if (m_context->getError() == GraphicsContext3D::NO_ERROR)
3897 break;
3898 }
3899 m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL);
3900
3901 canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""));
3902 }
3903
restoreContext()3904 void WebGLRenderingContext::restoreContext()
3905 {
3906 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow()));
3907 if (!context)
3908 return;
3909
3910 m_context = context;
3911 m_contextLost = false;
3912 initializeNewContext();
3913 canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, ""));
3914 }
3915
removeObject(WebGLObject * object)3916 void WebGLRenderingContext::removeObject(WebGLObject* object)
3917 {
3918 m_canvasObjects.remove(object);
3919 }
3920
addObject(WebGLObject * object)3921 void WebGLRenderingContext::addObject(WebGLObject* object)
3922 {
3923 ASSERT(!isContextLost());
3924 removeObject(object);
3925 m_canvasObjects.add(object);
3926 }
3927
detachAndRemoveAllObjects()3928 void WebGLRenderingContext::detachAndRemoveAllObjects()
3929 {
3930 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3931 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it)
3932 (*it)->detachContext();
3933
3934 m_canvasObjects.clear();
3935 }
3936
findTexture(Platform3DObject obj)3937 WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj)
3938 {
3939 if (!obj)
3940 return 0;
3941 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3942 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3943 if ((*it)->isTexture() && (*it)->object() == obj)
3944 return reinterpret_cast<WebGLTexture*>((*it).get());
3945 }
3946 return 0;
3947 }
3948
findRenderbuffer(Platform3DObject obj)3949 WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj)
3950 {
3951 if (!obj)
3952 return 0;
3953 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3954 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3955 if ((*it)->isRenderbuffer() && (*it)->object() == obj)
3956 return reinterpret_cast<WebGLRenderbuffer*>((*it).get());
3957 }
3958 return 0;
3959 }
3960
findBuffer(Platform3DObject obj)3961 WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj)
3962 {
3963 if (!obj)
3964 return 0;
3965 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3966 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3967 if ((*it)->isBuffer() && (*it)->object() == obj)
3968 return reinterpret_cast<WebGLBuffer*>((*it).get());
3969 }
3970 return 0;
3971 }
3972
findShader(Platform3DObject obj)3973 WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj)
3974 {
3975 if (!obj)
3976 return 0;
3977 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end();
3978 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) {
3979 if ((*it)->isShader() && (*it)->object() == obj)
3980 return reinterpret_cast<WebGLShader*>((*it).get());
3981 }
3982 return 0;
3983 }
3984
getBooleanParameter(GC3Denum pname)3985 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
3986 {
3987 GC3Dboolean value = 0;
3988 m_context->getBooleanv(pname, &value);
3989 return WebGLGetInfo(static_cast<bool>(value));
3990 }
3991
getBooleanArrayParameter(GC3Denum pname)3992 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname)
3993 {
3994 if (pname != GraphicsContext3D::COLOR_WRITEMASK) {
3995 notImplemented();
3996 return WebGLGetInfo(0, 0);
3997 }
3998 GC3Dboolean value[4] = {0};
3999 m_context->getBooleanv(pname, value);
4000 bool boolValue[4];
4001 for (int ii = 0; ii < 4; ++ii)
4002 boolValue[ii] = static_cast<bool>(value[ii]);
4003 return WebGLGetInfo(boolValue, 4);
4004 }
4005
getFloatParameter(GC3Denum pname)4006 WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname)
4007 {
4008 GC3Dfloat value = 0;
4009 m_context->getFloatv(pname, &value);
4010 return WebGLGetInfo(value);
4011 }
4012
getIntParameter(GC3Denum pname)4013 WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname)
4014 {
4015 GC3Dint value = 0;
4016 m_context->getIntegerv(pname, &value);
4017 return WebGLGetInfo(value);
4018 }
4019
getUnsignedIntParameter(GC3Denum pname)4020 WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname)
4021 {
4022 GC3Dint value = 0;
4023 m_context->getIntegerv(pname, &value);
4024 return WebGLGetInfo(static_cast<unsigned int>(value));
4025 }
4026
getWebGLFloatArrayParameter(GC3Denum pname)4027 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname)
4028 {
4029 GC3Dfloat value[4] = {0};
4030 m_context->getFloatv(pname, value);
4031 unsigned length = 0;
4032 switch (pname) {
4033 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
4034 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
4035 case GraphicsContext3D::DEPTH_RANGE:
4036 length = 2;
4037 break;
4038 case GraphicsContext3D::BLEND_COLOR:
4039 case GraphicsContext3D::COLOR_CLEAR_VALUE:
4040 length = 4;
4041 break;
4042 default:
4043 notImplemented();
4044 }
4045 return WebGLGetInfo(Float32Array::create(value, length));
4046 }
4047
getWebGLIntArrayParameter(GC3Denum pname)4048 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname)
4049 {
4050 GC3Dint value[4] = {0};
4051 m_context->getIntegerv(pname, value);
4052 unsigned length = 0;
4053 switch (pname) {
4054 case GraphicsContext3D::MAX_VIEWPORT_DIMS:
4055 length = 2;
4056 break;
4057 case GraphicsContext3D::SCISSOR_BOX:
4058 case GraphicsContext3D::VIEWPORT:
4059 length = 4;
4060 break;
4061 default:
4062 notImplemented();
4063 }
4064 return WebGLGetInfo(Int32Array::create(value, length));
4065 }
4066
handleNPOTTextures(bool prepareToDraw)4067 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw)
4068 {
4069 bool resetActiveUnit = false;
4070 for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) {
4071 if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4072 || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) {
4073 if (ii != m_activeTextureUnit) {
4074 m_context->activeTexture(ii);
4075 resetActiveUnit = true;
4076 } else if (resetActiveUnit) {
4077 m_context->activeTexture(ii);
4078 resetActiveUnit = false;
4079 }
4080 WebGLTexture* tex2D;
4081 WebGLTexture* texCubeMap;
4082 if (prepareToDraw) {
4083 tex2D = m_blackTexture2D.get();
4084 texCubeMap = m_blackTextureCubeMap.get();
4085 } else {
4086 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4087 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4088 }
4089 if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture())
4090 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D));
4091 if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())
4092 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4093 }
4094 }
4095 if (resetActiveUnit)
4096 m_context->activeTexture(m_activeTextureUnit);
4097 }
4098
createFallbackBlackTextures1x1()4099 void WebGLRenderingContext::createFallbackBlackTextures1x1()
4100 {
4101 unsigned char black[] = {0, 0, 0, 255};
4102 m_blackTexture2D = createTexture();
4103 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object());
4104 m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1,
4105 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4106 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
4107 m_blackTextureCubeMap = createTexture();
4108 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4109 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4110 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4111 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1,
4112 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4113 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4114 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4115 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1,
4116 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4117 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4118 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4119 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1,
4120 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black);
4121 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0);
4122 }
4123
isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,GC3Denum colorBufferFormat)4124 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat,
4125 GC3Denum colorBufferFormat)
4126 {
4127 switch (colorBufferFormat) {
4128 case GraphicsContext3D::ALPHA:
4129 if (texInternalFormat == GraphicsContext3D::ALPHA)
4130 return true;
4131 break;
4132 case GraphicsContext3D::RGB:
4133 if (texInternalFormat == GraphicsContext3D::LUMINANCE
4134 || texInternalFormat == GraphicsContext3D::RGB)
4135 return true;
4136 break;
4137 case GraphicsContext3D::RGBA:
4138 return true;
4139 }
4140 return false;
4141 }
4142
getBoundFramebufferColorFormat()4143 GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat()
4144 {
4145 if (m_framebufferBinding && m_framebufferBinding->object())
4146 return m_framebufferBinding->getColorBufferFormat();
4147 if (m_attributes.alpha)
4148 return GraphicsContext3D::RGBA;
4149 return GraphicsContext3D::RGB;
4150 }
4151
getBoundFramebufferWidth()4152 int WebGLRenderingContext::getBoundFramebufferWidth()
4153 {
4154 if (m_framebufferBinding && m_framebufferBinding->object())
4155 return m_framebufferBinding->getWidth();
4156 return m_context->getInternalFramebufferSize().width();
4157 }
4158
getBoundFramebufferHeight()4159 int WebGLRenderingContext::getBoundFramebufferHeight()
4160 {
4161 if (m_framebufferBinding && m_framebufferBinding->object())
4162 return m_framebufferBinding->getHeight();
4163 return m_context->getInternalFramebufferSize().height();
4164 }
4165
validateTextureBinding(GC3Denum target,bool useSixEnumsForCubeMap)4166 WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, bool useSixEnumsForCubeMap)
4167 {
4168 WebGLTexture* tex = 0;
4169 switch (target) {
4170 case GraphicsContext3D::TEXTURE_2D:
4171 tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4172 break;
4173 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4174 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4175 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4176 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4177 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4178 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4179 if (!useSixEnumsForCubeMap) {
4180 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4181 return 0;
4182 }
4183 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4184 break;
4185 case GraphicsContext3D::TEXTURE_CUBE_MAP:
4186 if (useSixEnumsForCubeMap) {
4187 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4188 return 0;
4189 }
4190 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4191 break;
4192 default:
4193 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4194 return 0;
4195 }
4196 if (!tex)
4197 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4198 return tex;
4199 }
4200
validateSize(GC3Dint x,GC3Dint y)4201 bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y)
4202 {
4203 if (x < 0 || y < 0) {
4204 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4205 return false;
4206 }
4207 return true;
4208 }
4209
validateString(const String & string)4210 bool WebGLRenderingContext::validateString(const String& string)
4211 {
4212 for (size_t i = 0; i < string.length(); ++i) {
4213 if (!validateCharacter(string[i])) {
4214 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4215 return false;
4216 }
4217 }
4218 return true;
4219 }
4220
validateTexFuncFormatAndType(GC3Denum format,GC3Denum type)4221 bool WebGLRenderingContext::validateTexFuncFormatAndType(GC3Denum format, GC3Denum type)
4222 {
4223 switch (format) {
4224 case GraphicsContext3D::ALPHA:
4225 case GraphicsContext3D::LUMINANCE:
4226 case GraphicsContext3D::LUMINANCE_ALPHA:
4227 case GraphicsContext3D::RGB:
4228 case GraphicsContext3D::RGBA:
4229 break;
4230 default:
4231 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4232 return false;
4233 }
4234
4235 switch (type) {
4236 case GraphicsContext3D::UNSIGNED_BYTE:
4237 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4238 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4239 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4240 break;
4241 case GraphicsContext3D::FLOAT:
4242 if (m_oesTextureFloat)
4243 break;
4244 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4245 return false;
4246 default:
4247 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4248 return false;
4249 }
4250
4251 // Verify that the combination of format and type is supported.
4252 switch (format) {
4253 case GraphicsContext3D::ALPHA:
4254 case GraphicsContext3D::LUMINANCE:
4255 case GraphicsContext3D::LUMINANCE_ALPHA:
4256 if (type != GraphicsContext3D::UNSIGNED_BYTE
4257 && type != GraphicsContext3D::FLOAT) {
4258 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4259 return false;
4260 }
4261 break;
4262 case GraphicsContext3D::RGB:
4263 if (type != GraphicsContext3D::UNSIGNED_BYTE
4264 && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5
4265 && type != GraphicsContext3D::FLOAT) {
4266 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4267 return false;
4268 }
4269 break;
4270 case GraphicsContext3D::RGBA:
4271 if (type != GraphicsContext3D::UNSIGNED_BYTE
4272 && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4
4273 && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1
4274 && type != GraphicsContext3D::FLOAT) {
4275 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4276 return false;
4277 }
4278 break;
4279 default:
4280 ASSERT_NOT_REACHED();
4281 }
4282
4283 return true;
4284 }
4285
validateTexFuncLevel(GC3Denum target,GC3Dint level)4286 bool WebGLRenderingContext::validateTexFuncLevel(GC3Denum target, GC3Dint level)
4287 {
4288 if (level < 0) {
4289 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4290 return false;
4291 }
4292 switch (target) {
4293 case GraphicsContext3D::TEXTURE_2D:
4294 if (level > m_maxTextureLevel) {
4295 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4296 return false;
4297 }
4298 break;
4299 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4300 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4301 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4302 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4303 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4304 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4305 if (level > m_maxCubeMapTextureLevel) {
4306 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4307 return false;
4308 }
4309 break;
4310 }
4311 // This function only checks if level is legal, so we return true and don't
4312 // generate INVALID_ENUM if target is illegal.
4313 return true;
4314 }
4315
validateTexFuncParameters(GC3Denum target,GC3Dint level,GC3Denum internalformat,GC3Dsizei width,GC3Dsizei height,GC3Dint border,GC3Denum format,GC3Denum type)4316 bool WebGLRenderingContext::validateTexFuncParameters(GC3Denum target, GC3Dint level,
4317 GC3Denum internalformat,
4318 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
4319 GC3Denum format, GC3Denum type)
4320 {
4321 // We absolutely have to validate the format and type combination.
4322 // The texImage2D entry points taking HTMLImage, etc. will produce
4323 // temporary data based on this combination, so it must be legal.
4324 if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level))
4325 return false;
4326
4327 if (width < 0 || height < 0) {
4328 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4329 return false;
4330 }
4331
4332 switch (target) {
4333 case GraphicsContext3D::TEXTURE_2D:
4334 if (width > m_maxTextureSize || height > m_maxTextureSize) {
4335 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4336 return false;
4337 }
4338 break;
4339 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X:
4340 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X:
4341 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y:
4342 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y:
4343 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z:
4344 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z:
4345 if (width != height || width > m_maxCubeMapTextureSize) {
4346 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4347 return false;
4348 }
4349 break;
4350 default:
4351 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4352 return false;
4353 }
4354
4355 if (format != internalformat) {
4356 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4357 return false;
4358 }
4359
4360 if (border) {
4361 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4362 return false;
4363 }
4364
4365 return true;
4366 }
4367
validateTexFuncData(GC3Dsizei width,GC3Dsizei height,GC3Denum format,GC3Denum type,ArrayBufferView * pixels)4368 bool WebGLRenderingContext::validateTexFuncData(GC3Dsizei width, GC3Dsizei height,
4369 GC3Denum format, GC3Denum type,
4370 ArrayBufferView* pixels)
4371 {
4372 if (!pixels)
4373 return true;
4374
4375 if (!validateTexFuncFormatAndType(format, type))
4376 return false;
4377
4378 switch (type) {
4379 case GraphicsContext3D::UNSIGNED_BYTE:
4380 if (!pixels->isUnsignedByteArray()) {
4381 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4382 return false;
4383 }
4384 break;
4385 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
4386 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
4387 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
4388 if (!pixels->isUnsignedShortArray()) {
4389 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4390 return false;
4391 }
4392 break;
4393 case GraphicsContext3D::FLOAT: // OES_texture_float
4394 if (!pixels->isFloatArray()) {
4395 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4396 return false;
4397 }
4398 break;
4399 default:
4400 ASSERT_NOT_REACHED();
4401 }
4402
4403 unsigned int totalBytesRequired;
4404 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4405 if (error != GraphicsContext3D::NO_ERROR) {
4406 m_context->synthesizeGLError(error);
4407 return false;
4408 }
4409 if (pixels->byteLength() < totalBytesRequired) {
4410 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4411 return false;
4412 }
4413 return true;
4414 }
4415
validateDrawMode(GC3Denum mode)4416 bool WebGLRenderingContext::validateDrawMode(GC3Denum mode)
4417 {
4418 switch (mode) {
4419 case GraphicsContext3D::POINTS:
4420 case GraphicsContext3D::LINE_STRIP:
4421 case GraphicsContext3D::LINE_LOOP:
4422 case GraphicsContext3D::LINES:
4423 case GraphicsContext3D::TRIANGLE_STRIP:
4424 case GraphicsContext3D::TRIANGLE_FAN:
4425 case GraphicsContext3D::TRIANGLES:
4426 return true;
4427 default:
4428 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4429 return false;
4430 }
4431 }
4432
validateStencilSettings()4433 bool WebGLRenderingContext::validateStencilSettings()
4434 {
4435 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
4436 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4437 return false;
4438 }
4439 return true;
4440 }
4441
validateStencilFunc(GC3Denum func)4442 bool WebGLRenderingContext::validateStencilFunc(GC3Denum func)
4443 {
4444 switch (func) {
4445 case GraphicsContext3D::NEVER:
4446 case GraphicsContext3D::LESS:
4447 case GraphicsContext3D::LEQUAL:
4448 case GraphicsContext3D::GREATER:
4449 case GraphicsContext3D::GEQUAL:
4450 case GraphicsContext3D::EQUAL:
4451 case GraphicsContext3D::NOTEQUAL:
4452 case GraphicsContext3D::ALWAYS:
4453 return true;
4454 default:
4455 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4456 return false;
4457 }
4458 }
4459
printWarningToConsole(const String & message)4460 void WebGLRenderingContext::printWarningToConsole(const String& message)
4461 {
4462 canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel,
4463 message, 0, canvas()->document()->url().string());
4464 }
4465
validateFramebufferFuncParameters(GC3Denum target,GC3Denum attachment)4466 bool WebGLRenderingContext::validateFramebufferFuncParameters(GC3Denum target, GC3Denum attachment)
4467 {
4468 if (target != GraphicsContext3D::FRAMEBUFFER) {
4469 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4470 return false;
4471 }
4472 switch (attachment) {
4473 case GraphicsContext3D::COLOR_ATTACHMENT0:
4474 case GraphicsContext3D::DEPTH_ATTACHMENT:
4475 case GraphicsContext3D::STENCIL_ATTACHMENT:
4476 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
4477 break;
4478 default:
4479 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4480 return false;
4481 }
4482 return true;
4483 }
4484
validateBlendEquation(GC3Denum mode)4485 bool WebGLRenderingContext::validateBlendEquation(GC3Denum mode)
4486 {
4487 switch (mode) {
4488 case GraphicsContext3D::FUNC_ADD:
4489 case GraphicsContext3D::FUNC_SUBTRACT:
4490 case GraphicsContext3D::FUNC_REVERSE_SUBTRACT:
4491 return true;
4492 default:
4493 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4494 return false;
4495 }
4496 }
4497
validateBlendFuncFactors(GC3Denum src,GC3Denum dst)4498 bool WebGLRenderingContext::validateBlendFuncFactors(GC3Denum src, GC3Denum dst)
4499 {
4500 if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4501 && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))
4502 || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR)
4503 && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) {
4504 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4505 return false;
4506 }
4507 return true;
4508 }
4509
validateCapability(GC3Denum cap)4510 bool WebGLRenderingContext::validateCapability(GC3Denum cap)
4511 {
4512 switch (cap) {
4513 case GraphicsContext3D::BLEND:
4514 case GraphicsContext3D::CULL_FACE:
4515 case GraphicsContext3D::DEPTH_TEST:
4516 case GraphicsContext3D::DITHER:
4517 case GraphicsContext3D::POLYGON_OFFSET_FILL:
4518 case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE:
4519 case GraphicsContext3D::SAMPLE_COVERAGE:
4520 case GraphicsContext3D::SCISSOR_TEST:
4521 case GraphicsContext3D::STENCIL_TEST:
4522 return true;
4523 default:
4524 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4525 return false;
4526 }
4527 }
4528
validateUniformParameters(const WebGLUniformLocation * location,Float32Array * v,GC3Dsizei requiredMinSize)4529 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize)
4530 {
4531 if (!v) {
4532 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4533 return false;
4534 }
4535 return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4536 }
4537
validateUniformParameters(const WebGLUniformLocation * location,Int32Array * v,GC3Dsizei requiredMinSize)4538 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize)
4539 {
4540 if (!v) {
4541 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4542 return false;
4543 }
4544 return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize);
4545 }
4546
validateUniformParameters(const WebGLUniformLocation * location,void * v,GC3Dsizei size,GC3Dsizei requiredMinSize)4547 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4548 {
4549 return validateUniformMatrixParameters(location, false, v, size, requiredMinSize);
4550 }
4551
validateUniformMatrixParameters(const WebGLUniformLocation * location,GC3Dboolean transpose,Float32Array * v,GC3Dsizei requiredMinSize)4552 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize)
4553 {
4554 if (!v) {
4555 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4556 return false;
4557 }
4558 return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize);
4559 }
4560
validateUniformMatrixParameters(const WebGLUniformLocation * location,GC3Dboolean transpose,void * v,GC3Dsizei size,GC3Dsizei requiredMinSize)4561 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize)
4562 {
4563 if (!location)
4564 return false;
4565 if (location->program() != m_currentProgram) {
4566 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4567 return false;
4568 }
4569 if (!v) {
4570 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4571 return false;
4572 }
4573 if (transpose) {
4574 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4575 return false;
4576 }
4577 if (size < requiredMinSize || (size % requiredMinSize)) {
4578 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4579 return false;
4580 }
4581 return true;
4582 }
4583
validateBufferDataParameters(GC3Denum target,GC3Denum usage)4584 WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target, GC3Denum usage)
4585 {
4586 WebGLBuffer* buffer = 0;
4587 switch (target) {
4588 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER:
4589 buffer = m_boundVertexArrayObject->getElementArrayBuffer().get();
4590 break;
4591 case GraphicsContext3D::ARRAY_BUFFER:
4592 buffer = m_boundArrayBuffer.get();
4593 break;
4594 default:
4595 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4596 return 0;
4597 }
4598 if (!buffer) {
4599 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
4600 return 0;
4601 }
4602 switch (usage) {
4603 case GraphicsContext3D::STREAM_DRAW:
4604 case GraphicsContext3D::STATIC_DRAW:
4605 case GraphicsContext3D::DYNAMIC_DRAW:
4606 return buffer;
4607 }
4608 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM);
4609 return 0;
4610 }
4611
validateHTMLImageElement(HTMLImageElement * image)4612 bool WebGLRenderingContext::validateHTMLImageElement(HTMLImageElement* image)
4613 {
4614 if (!image || !image->cachedImage()) {
4615 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4616 return false;
4617 }
4618 const KURL& url = image->cachedImage()->response().url();
4619 if (url.isNull() || url.isEmpty() || !url.isValid()) {
4620 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4621 return false;
4622 }
4623 return true;
4624 }
4625
vertexAttribfImpl(GC3Duint index,GC3Dsizei expectedSize,GC3Dfloat v0,GC3Dfloat v1,GC3Dfloat v2,GC3Dfloat v3)4626 void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
4627 {
4628 if (isContextLost())
4629 return;
4630 if (index >= m_maxVertexAttribs) {
4631 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4632 return;
4633 }
4634 // In GL, we skip setting vertexAttrib0 values.
4635 if (index || isGLES2Compliant()) {
4636 switch (expectedSize) {
4637 case 1:
4638 m_context->vertexAttrib1f(index, v0);
4639 break;
4640 case 2:
4641 m_context->vertexAttrib2f(index, v0, v1);
4642 break;
4643 case 3:
4644 m_context->vertexAttrib3f(index, v0, v1, v2);
4645 break;
4646 case 4:
4647 m_context->vertexAttrib4f(index, v0, v1, v2, v3);
4648 break;
4649 }
4650 cleanupAfterGraphicsCall(false);
4651 }
4652 VertexAttribValue& attribValue = m_vertexAttribValue[index];
4653 attribValue.value[0] = v0;
4654 attribValue.value[1] = v1;
4655 attribValue.value[2] = v2;
4656 attribValue.value[3] = v3;
4657 }
4658
vertexAttribfvImpl(GC3Duint index,Float32Array * v,GC3Dsizei expectedSize)4659 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize)
4660 {
4661 if (isContextLost())
4662 return;
4663 if (!v) {
4664 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4665 return;
4666 }
4667 vertexAttribfvImpl(index, v->data(), v->length(), expectedSize);
4668 }
4669
vertexAttribfvImpl(GC3Duint index,GC3Dfloat * v,GC3Dsizei size,GC3Dsizei expectedSize)4670 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize)
4671 {
4672 if (isContextLost())
4673 return;
4674 if (!v) {
4675 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4676 return;
4677 }
4678 if (size < expectedSize) {
4679 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4680 return;
4681 }
4682 if (index >= m_maxVertexAttribs) {
4683 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
4684 return;
4685 }
4686 // In GL, we skip setting vertexAttrib0 values.
4687 if (index || isGLES2Compliant()) {
4688 switch (expectedSize) {
4689 case 1:
4690 m_context->vertexAttrib1fv(index, v);
4691 break;
4692 case 2:
4693 m_context->vertexAttrib2fv(index, v);
4694 break;
4695 case 3:
4696 m_context->vertexAttrib3fv(index, v);
4697 break;
4698 case 4:
4699 m_context->vertexAttrib4fv(index, v);
4700 break;
4701 }
4702 cleanupAfterGraphicsCall(false);
4703 }
4704 VertexAttribValue& attribValue = m_vertexAttribValue[index];
4705 attribValue.initValue();
4706 for (int ii = 0; ii < expectedSize; ++ii)
4707 attribValue.value[ii] = v[ii];
4708 }
4709
initVertexAttrib0()4710 void WebGLRenderingContext::initVertexAttrib0()
4711 {
4712 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4713
4714 m_vertexAttrib0Buffer = createBuffer();
4715 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4716 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW);
4717 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0);
4718 state.bufferBinding = m_vertexAttrib0Buffer;
4719 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0);
4720 m_context->enableVertexAttribArray(0);
4721 m_vertexAttrib0BufferSize = 0;
4722 m_vertexAttrib0BufferValue[0] = 0.0f;
4723 m_vertexAttrib0BufferValue[1] = 0.0f;
4724 m_vertexAttrib0BufferValue[2] = 0.0f;
4725 m_vertexAttrib0BufferValue[3] = 1.0f;
4726 m_forceAttrib0BufferRefill = false;
4727 m_vertexAttrib0UsedBefore = false;
4728 }
4729
simulateVertexAttrib0(GC3Dsizei numVertex)4730 bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex)
4731 {
4732 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4733 const VertexAttribValue& attribValue = m_vertexAttribValue[0];
4734 if (!m_currentProgram)
4735 return false;
4736 bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0();
4737 if (usingVertexAttrib0)
4738 m_vertexAttrib0UsedBefore = true;
4739 if (state.enabled && usingVertexAttrib0)
4740 return false;
4741 if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore)
4742 return false;
4743 m_vertexAttrib0UsedBefore = true;
4744 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object());
4745 GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat);
4746 if (bufferDataSize > m_vertexAttrib0BufferSize) {
4747 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW);
4748 m_vertexAttrib0BufferSize = bufferDataSize;
4749 m_forceAttrib0BufferRefill = true;
4750 }
4751 if (usingVertexAttrib0
4752 && (m_forceAttrib0BufferRefill
4753 || attribValue.value[0] != m_vertexAttrib0BufferValue[0]
4754 || attribValue.value[1] != m_vertexAttrib0BufferValue[1]
4755 || attribValue.value[2] != m_vertexAttrib0BufferValue[2]
4756 || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) {
4757 OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]);
4758 for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) {
4759 bufferData[ii * 4] = attribValue.value[0];
4760 bufferData[ii * 4 + 1] = attribValue.value[1];
4761 bufferData[ii * 4 + 2] = attribValue.value[2];
4762 bufferData[ii * 4 + 3] = attribValue.value[3];
4763 }
4764 m_vertexAttrib0BufferValue[0] = attribValue.value[0];
4765 m_vertexAttrib0BufferValue[1] = attribValue.value[1];
4766 m_vertexAttrib0BufferValue[2] = attribValue.value[2];
4767 m_vertexAttrib0BufferValue[3] = attribValue.value[3];
4768 m_forceAttrib0BufferRefill = false;
4769 m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get());
4770 }
4771 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0);
4772 return true;
4773 }
4774
restoreStatesAfterVertexAttrib0Simulation()4775 void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation()
4776 {
4777 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
4778 if (state.bufferBinding != m_vertexAttrib0Buffer) {
4779 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get()));
4780 m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset);
4781 }
4782 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get()));
4783 }
4784
getNumberOfExtensions()4785 int WebGLRenderingContext::getNumberOfExtensions()
4786 {
4787 return (m_oesVertexArrayObject ? 1 : 0) + (m_oesStandardDerivatives ? 1 : 0) + (m_webkitLoseContext ? 1 : 0) + (m_oesTextureFloat ? 1 : 0);
4788 }
4789
getExtensionNumber(int i)4790 WebGLExtension* WebGLRenderingContext::getExtensionNumber(int i)
4791 {
4792 if (m_oesVertexArrayObject) {
4793 if (!i)
4794 return m_oesVertexArrayObject.get();
4795 --i;
4796 }
4797 if (m_oesStandardDerivatives) {
4798 if (!i)
4799 return m_oesStandardDerivatives.get();
4800 --i;
4801 }
4802 if (m_webkitLoseContext) {
4803 if (!i)
4804 return m_webkitLoseContext.get();
4805 --i;
4806 }
4807 if (m_oesTextureFloat) {
4808 if (!i)
4809 return m_oesTextureFloat.get();
4810 --i;
4811 }
4812 // Similar tests for other extensions would go here.
4813 return 0;
4814 }
4815
LRUImageBufferCache(int capacity)4816 WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity)
4817 : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
4818 , m_capacity(capacity)
4819 {
4820 }
4821
imageBuffer(const IntSize & size)4822 ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size)
4823 {
4824 int i;
4825 for (i = 0; i < m_capacity; ++i) {
4826 ImageBuffer* buf = m_buffers[i].get();
4827 if (!buf)
4828 break;
4829 if (buf->size() != size)
4830 continue;
4831 bubbleToFront(i);
4832 return buf;
4833 }
4834
4835 OwnPtr<ImageBuffer> temp = ImageBuffer::create(size);
4836 if (!temp)
4837 return 0;
4838 i = std::min(m_capacity - 1, i);
4839 m_buffers[i] = temp.release();
4840
4841 ImageBuffer* buf = m_buffers[i].get();
4842 bubbleToFront(i);
4843 return buf;
4844 }
4845
bubbleToFront(int idx)4846 void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx)
4847 {
4848 for (int i = idx; i > 0; --i)
4849 m_buffers[i].swap(m_buffers[i-1]);
4850 }
4851
4852 } // namespace WebCore
4853
4854 #endif // ENABLE(WEBGL)
4855