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