2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "WebGLRenderingContext.h"
32 #include "CachedImage.h"
33 #include "CanvasPixelArray.h"
34 #include "CheckedInt.h"
36 #include "DOMWindow.h"
37 #include "EXTTextureFilterAnisotropic.h"
38 #include "ExceptionCode.h"
39 #include "Extensions3D.h"
41 #include "FrameView.h"
42 #include "HTMLCanvasElement.h"
43 #include "HTMLImageElement.h"
44 #include "HTMLVideoElement.h"
45 #include "ImageBuffer.h"
46 #include "ImageData.h"
48 #include "NotImplemented.h"
49 #include "OESStandardDerivatives.h"
50 #include "OESTextureFloat.h"
51 #include "OESVertexArrayObject.h"
53 #include "RenderBox.h"
55 #include "WebGLActiveInfo.h"
56 #include "WebGLBuffer.h"
57 #include "WebGLCompressedTextureS3TC.h"
58 #include "WebGLContextAttributes.h"
59 #include "WebGLContextEvent.h"
60 #include "WebGLContextGroup.h"
61 #include "WebGLDebugRendererInfo.h"
62 #include "WebGLDebugShaders.h"
63 #include "WebGLFramebuffer.h"
64 #include "WebGLLoseContext.h"
65 #include "WebGLProgram.h"
66 #include "WebGLRenderbuffer.h"
67 #include "WebGLShader.h"
68 #include "WebGLShaderPrecisionFormat.h"
69 #include "WebGLTexture.h"
70 #include "WebGLUniformLocation.h"
72 #include <wtf/ByteArray.h>
73 #include <wtf/OwnArrayPtr.h>
74 #include <wtf/PassOwnArrayPtr.h>
75 #include <wtf/Uint16Array.h>
76 #include <wtf/Uint32Array.h>
77 #include <wtf/text/StringBuilder.h>
85 const double secondsBetweenRestoreAttempts = 1.0;
86 const int maxGLErrorsAllowedToConsole = 10;
90 class ScopedDrawingBufferBinder {
92 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
93 : m_drawingBuffer(drawingBuffer)
94 , m_framebufferBinding(framebufferBinding)
96 // Commit DrawingBuffer if needed (e.g., for multisampling)
97 if (!m_framebufferBinding && m_drawingBuffer)
98 m_drawingBuffer->commit();
101 ~ScopedDrawingBufferBinder()
103 // Restore DrawingBuffer if needed
104 if (!m_framebufferBinding && m_drawingBuffer)
105 m_drawingBuffer->bind();
109 DrawingBuffer* m_drawingBuffer;
110 WebGLFramebuffer* m_framebufferBinding;
113 Platform3DObject objectOrZero(WebGLObject* object)
115 return object ? object->object() : 0;
118 void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange)
120 ASSERT(clippedStart && clippedRange);
125 GC3Dint end = start + range;
126 if (end > sourceRange)
127 range -= end - sourceRange;
128 *clippedStart = start;
129 *clippedRange = range;
132 // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same.
133 bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height,
134 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight,
135 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight)
137 ASSERT(clippedX && clippedY && clippedWidth && clippedHeight);
138 clip1D(x, width, sourceWidth, clippedX, clippedWidth);
139 clip1D(y, height, sourceHeight, clippedY, clippedHeight);
140 return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height);
143 GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
152 // Return true if a character belongs to the ASCII subset as defined in
153 // GLSL ES 1.0 spec section 3.1.
154 bool validateCharacter(unsigned char c)
156 // Printing characters are valid except " $ ` @ \ ' DEL.
157 if (c >= 32 && c <= 126
158 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
160 // Horizontal tab, line feed, vertical tab, form feed, carriage return
162 if (c >= 9 && c <= 13)
167 bool isPrefixReserved(const String& name)
169 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
174 // Strips comments from shader text. This allows non-ASCII characters
175 // to be used in comments without potentially breaking OpenGL
176 // implementations not expecting characters outside the GLSL ES set.
177 class StripComments {
179 StripComments(const String& str)
180 : m_parseState(BeginningOfLine)
181 , m_sourceString(str)
182 , m_length(str.length())
190 return m_builder.toString();
194 bool hasMoreCharacters()
196 return (m_position < m_length);
201 while (hasMoreCharacters()) {
203 // process() might advance the position.
204 if (hasMoreCharacters())
211 bool peek(UChar& character)
213 if (m_position + 1 >= m_length)
215 character = m_sourceString[m_position + 1];
221 ASSERT(m_position < m_length);
222 return m_sourceString[m_position];
230 bool isNewline(UChar character)
232 // Don't attempt to canonicalize newline related characters.
233 return (character == '\n' || character == '\r');
236 void emit(UChar character)
238 m_builder.append(character);
242 // Have not seen an ASCII non-whitespace character yet on
243 // this line. Possible that we might see a preprocessor
247 // Have seen at least one ASCII non-whitespace character
251 // Handling a preprocessor directive. Passes through all
252 // characters up to the end of the line. Disables comment
254 InPreprocessorDirective,
256 // Handling a single-line comment. The comment text is
257 // replaced with a single space.
260 // Handling a multi-line comment. Newlines are passed
261 // through to preserve line numbers.
265 ParseState m_parseState;
266 String m_sourceString;
269 StringBuilder m_builder;
272 void StripComments::process(UChar c)
275 // No matter what state we are in, pass through newlines
276 // so we preserve line numbers.
279 if (m_parseState != InMultiLineComment)
280 m_parseState = BeginningOfLine;
286 switch (m_parseState) {
287 case BeginningOfLine:
288 if (WTF::isASCIISpace(c)) {
294 m_parseState = InPreprocessorDirective;
299 // Transition to normal state and re-handle character.
300 m_parseState = MiddleOfLine;
305 if (c == '/' && peek(temp)) {
307 m_parseState = InSingleLineComment;
314 m_parseState = InMultiLineComment;
315 // Emit the comment start in case the user has
316 // an unclosed comment and we want to later
328 case InPreprocessorDirective:
329 // No matter what the character is, just pass it
330 // through. Do not parse comments in this state. This
331 // might not be the right thing to do long term, but it
332 // should handle the #error preprocessor directive.
336 case InSingleLineComment:
337 // The newline code at the top of this function takes care
338 // of resetting our state when we get out of the
339 // single-line comment. Swallow all other characters.
342 case InMultiLineComment:
343 if (c == '*' && peek(temp) && temp == '/') {
346 m_parseState = MiddleOfLine;
351 // Swallow all other characters. Unclear whether we may
352 // want or need to just emit a space per character to try
353 // to preserve column numbers for debugging purposes.
357 } // namespace anonymous
359 class WebGLStateRestorer {
361 WebGLStateRestorer(WebGLRenderingContext* context,
368 ~WebGLStateRestorer()
370 m_context->cleanupAfterGraphicsCall(m_changed);
374 WebGLRenderingContext* m_context;
378 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
380 explicit WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_context(cb) { }
381 virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
382 virtual ~WebGLRenderingContextLostCallback() {}
384 WebGLRenderingContext* m_context;
387 class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
389 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContext* cb) : m_context(cb) { }
390 virtual void onErrorMessage(const String& message, GC3Dint) { m_context->printGLErrorToConsole(message); }
391 virtual ~WebGLRenderingContextErrorMessageCallback() { }
393 WebGLRenderingContext* m_context;
396 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs)
398 HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow();
399 GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
401 if (attributes.antialias) {
402 Page* p = canvas->document()->page();
403 if (p && !p->settings()->openGLMultisamplingEnabled())
404 attributes.antialias = false;
407 attributes.noExtensions = true;
408 #if PLATFORM(CHROMIUM)
409 attributes.shareResources = true;
411 attributes.shareResources = false;
413 attributes.preferDiscreteGPU = true;
416 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
418 if (!context || !context->makeContextCurrent()) {
419 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
423 return adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
426 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
427 GraphicsContext3D::Attributes attributes)
428 : CanvasRenderingContext(passedCanvas)
431 , m_dispatchContextLostEventTimer(this, &WebGLRenderingContext::dispatchContextLostEvent)
432 , m_restoreAllowed(false)
433 , m_restoreTimer(this, &WebGLRenderingContext::maybeRestoreContext)
435 , m_contextLost(false)
436 , m_contextLostMode(SyntheticLostContext)
437 , m_attributes(attributes)
438 , m_synthesizedErrorsToConsole(false)
439 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
442 m_contextGroup = WebGLContextGroup::create();
443 m_contextGroup->addContext(this);
445 #if PLATFORM(CHROMIUM)
446 // Create the DrawingBuffer and initialize the platform layer.
447 DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
448 DrawingBuffer::AlphaRequirement alpha = m_attributes.alpha ? DrawingBuffer::Alpha : DrawingBuffer::Opaque;
449 m_drawingBuffer = DrawingBuffer::create(m_context.get(), IntSize(canvas()->size()), preserve, alpha);
453 m_drawingBuffer->bind();
456 initializeNewContext();
459 void WebGLRenderingContext::initializeNewContext()
461 ASSERT(!m_contextLost);
462 m_needsUpdate = true;
463 m_markedCanvasDirty = false;
464 m_activeTextureUnit = 0;
466 m_unpackAlignment = 4;
467 m_unpackFlipY = false;
468 m_unpackPremultiplyAlpha = false;
469 m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
470 m_boundArrayBuffer = 0;
471 m_currentProgram = 0;
472 m_framebufferBinding = 0;
473 m_renderbufferBinding = 0;
475 m_stencilMask = 0xFFFFFFFF;
476 m_stencilMaskBack = 0xFFFFFFFF;
477 m_stencilFuncRef = 0;
478 m_stencilFuncRefBack = 0;
479 m_stencilFuncMask = 0xFFFFFFFF;
480 m_stencilFuncMaskBack = 0xFFFFFFFF;
481 m_layerCleared = false;
482 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
484 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
485 m_scissorEnabled = false;
488 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
490 GC3Dint numCombinedTextureImageUnits = 0;
491 m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
492 m_textureUnits.clear();
493 m_textureUnits.resize(numCombinedTextureImageUnits);
495 GC3Dint numVertexAttribs = 0;
496 m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
497 m_maxVertexAttribs = numVertexAttribs;
499 m_maxTextureSize = 0;
500 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
501 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
502 m_maxCubeMapTextureSize = 0;
503 m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
504 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
505 m_maxRenderbufferSize = 0;
506 m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
507 m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
508 m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
510 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
511 addContextObject(m_defaultVertexArrayObject.get());
512 m_boundVertexArrayObject = m_defaultVertexArrayObject;
514 m_vertexAttribValue.resize(m_maxVertexAttribs);
516 if (!isGLES2NPOTStrict())
517 createFallbackBlackTextures1x1();
518 if (!isGLES2Compliant())
522 m_drawingBuffer->reset(IntSize(canvas()->width(), canvas()->height()));
524 m_context->reshape(canvas()->width(), canvas()->height());
525 m_context->viewport(0, 0, canvas()->width(), canvas()->height());
527 m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this)));
528 m_context->setErrorMessageCallback(adoptPtr(new WebGLRenderingContextErrorMessageCallback(this)));
531 void WebGLRenderingContext::setupFlags()
535 Page* p = canvas()->document()->page();
536 if (p && p->settings()->webGLErrorsToConsoleEnabled())
537 m_synthesizedErrorsToConsole = true;
539 m_isGLES2Compliant = m_context->isGLES2Compliant();
540 m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
541 m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
542 if (m_isGLES2Compliant) {
543 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
544 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
546 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
547 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
551 bool WebGLRenderingContext::allowPrivilegedExtensions() const
553 Page* p = canvas()->document()->page();
554 if (p && p->settings())
555 return p->settings()->privilegedWebGLExtensionsEnabled();
559 void WebGLRenderingContext::addCompressedTextureFormat(GC3Denum format)
561 if (!m_compressedTextureFormats.contains(format))
562 m_compressedTextureFormats.append(format);
565 WebGLRenderingContext::~WebGLRenderingContext()
567 // Remove all references to WebGLObjects so if they are the last reference
568 // they will be freed before the last context is removed from the context group.
569 m_boundArrayBuffer = 0;
570 m_defaultVertexArrayObject = 0;
571 m_boundVertexArrayObject = 0;
572 m_vertexAttrib0Buffer = 0;
573 m_currentProgram = 0;
574 m_framebufferBinding = 0;
575 m_renderbufferBinding = 0;
577 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
578 m_textureUnits[i].m_texture2DBinding = 0;
579 m_textureUnits[i].m_textureCubeMapBinding = 0;
582 m_blackTexture2D = 0;
583 m_blackTextureCubeMap = 0;
585 detachAndRemoveAllObjects();
586 m_context->setContextLostCallback(nullptr);
587 m_context->setErrorMessageCallback(nullptr);
588 m_contextGroup->removeContext(this);
591 void WebGLRenderingContext::markContextChanged()
593 if (m_framebufferBinding)
596 m_context->markContextChanged();
598 m_layerCleared = false;
599 #if USE(ACCELERATED_COMPOSITING)
600 RenderBox* renderBox = canvas()->renderBox();
601 if (renderBox && renderBox->hasAcceleratedCompositing()) {
602 m_markedCanvasDirty = true;
603 renderBox->contentChanged(CanvasChanged);
606 if (!m_markedCanvasDirty) {
607 m_markedCanvasDirty = true;
608 canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height()));
610 #if USE(ACCELERATED_COMPOSITING)
615 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask)
620 if (!m_context->layerComposited() || m_layerCleared
621 || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
624 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
626 // Determine if it's possible to combine the clear the user asked for and this clear.
627 bool combinedClear = mask && !m_scissorEnabled;
629 m_context->disable(GraphicsContext3D::SCISSOR_TEST);
630 if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
631 m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
632 m_colorMask[1] ? m_clearColor[1] : 0,
633 m_colorMask[2] ? m_clearColor[2] : 0,
634 m_colorMask[3] ? m_clearColor[3] : 0);
636 m_context->clearColor(0, 0, 0, 0);
637 m_context->colorMask(true, true, true, true);
638 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
639 if (contextAttributes->depth()) {
640 if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
641 m_context->clearDepth(1.0f);
642 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
643 m_context->depthMask(true);
645 if (contextAttributes->stencil()) {
646 if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
647 m_context->clearStencil(m_clearStencil & m_stencilMask);
649 m_context->clearStencil(0);
650 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
651 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
654 m_drawingBuffer->clearFramebuffers(clearMask);
656 if (m_framebufferBinding)
657 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
658 m_context->clear(clearMask);
661 restoreStateAfterClear();
662 if (m_framebufferBinding)
663 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
664 m_layerCleared = true;
666 return combinedClear;
669 void WebGLRenderingContext::restoreStateAfterClear()
671 // Restore the state that the context set.
672 if (m_scissorEnabled)
673 m_context->enable(GraphicsContext3D::SCISSOR_TEST);
674 m_context->clearColor(m_clearColor[0], m_clearColor[1],
675 m_clearColor[2], m_clearColor[3]);
676 m_context->colorMask(m_colorMask[0], m_colorMask[1],
677 m_colorMask[2], m_colorMask[3]);
678 m_context->clearDepth(m_clearDepth);
679 m_context->clearStencil(m_clearStencil);
680 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
681 m_context->depthMask(m_depthMask);
684 void WebGLRenderingContext::markLayerComposited()
686 m_context->markLayerComposited();
689 void WebGLRenderingContext::paintRenderingResultsToCanvas()
691 // Until the canvas is written to by the application, the clear that
692 // happened after it was composited should be ignored by the compositor.
693 if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
694 m_context->paintCompositedResultsToCanvas(this);
696 #if USE(ACCELERATED_COMPOSITING) && PLATFORM(CHROMIUM)
698 m_drawingBuffer->paintCompositedResultsToCanvas(this);
701 canvas()->makePresentationCopy();
703 canvas()->clearPresentationCopy();
706 if (!m_markedCanvasDirty && !m_layerCleared)
709 canvas()->clearCopiedImage();
710 m_markedCanvasDirty = false;
713 m_drawingBuffer->commit();
714 m_context->paintRenderingResultsToCanvas(this, m_drawingBuffer.get());
716 if (m_drawingBuffer) {
717 if (m_framebufferBinding)
718 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
720 m_drawingBuffer->bind();
724 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData()
728 m_drawingBuffer->commit();
729 RefPtr<ImageData> imageData = m_context->paintRenderingResultsToImageData(m_drawingBuffer.get());
731 if (m_drawingBuffer) {
732 if (m_framebufferBinding)
733 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
735 m_drawingBuffer->bind();
741 void WebGLRenderingContext::reshape(int width, int height)
743 // This is an approximation because at WebGLRenderingContext level we don't
744 // know if the underlying FBO uses textures or renderbuffers.
745 GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
746 // Limit drawing buffer size to 4k to avoid memory exhaustion.
747 const int sizeUpperLimit = 4096;
748 maxSize = std::min(maxSize, sizeUpperLimit);
749 GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
750 GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
751 width = clamp(width, 1, maxWidth);
752 height = clamp(height, 1, maxHeight);
755 #if USE(ACCELERATED_COMPOSITING)
756 RenderBox* renderBox = canvas()->renderBox();
757 if (renderBox && renderBox->hasAcceleratedCompositing())
758 renderBox->contentChanged(CanvasChanged);
760 m_needsUpdate = false;
763 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
764 // clear (and this matches what reshape will do).
765 if (m_drawingBuffer) {
766 m_drawingBuffer->reset(IntSize(width, height));
767 restoreStateAfterClear();
769 m_context->reshape(width, height);
771 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
772 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
773 if (m_framebufferBinding)
774 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
777 int WebGLRenderingContext::drawingBufferWidth() const
780 return m_drawingBuffer->size().width();
782 return m_context->getInternalFramebufferSize().width();
785 int WebGLRenderingContext::drawingBufferHeight() const
788 return m_drawingBuffer->size().height();
790 return m_context->getInternalFramebufferSize().height();
793 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type)
796 case GraphicsContext3D::BYTE:
797 return sizeof(GC3Dbyte);
798 case GraphicsContext3D::UNSIGNED_BYTE:
799 return sizeof(GC3Dubyte);
800 case GraphicsContext3D::SHORT:
801 return sizeof(GC3Dshort);
802 case GraphicsContext3D::UNSIGNED_SHORT:
803 return sizeof(GC3Dushort);
804 case GraphicsContext3D::INT:
805 return sizeof(GC3Dint);
806 case GraphicsContext3D::UNSIGNED_INT:
807 return sizeof(GC3Duint);
808 case GraphicsContext3D::FLOAT:
809 return sizeof(GC3Dfloat);
811 ASSERT_NOT_REACHED();
815 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec)
820 if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
821 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
824 m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
825 m_context->activeTexture(texture);
828 m_drawingBuffer->setActiveTextureUnit(texture);
830 cleanupAfterGraphicsCall(false);
833 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
836 if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
838 if (!program->attachShader(shader)) {
839 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
842 m_context->attachShader(objectOrZero(program), objectOrZero(shader));
843 shader->onAttached();
844 cleanupAfterGraphicsCall(false);
847 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
850 if (isContextLost() || !validateWebGLObject("bindAttribLocation", program))
852 if (!validateLocationLength("bindAttribLocation", name))
854 if (!validateString("bindAttribLocation", name))
856 if (isPrefixReserved(name)) {
857 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
860 if (index >= m_maxVertexAttribs) {
861 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
864 m_context->bindAttribLocation(objectOrZero(program), index, name);
865 cleanupAfterGraphicsCall(false);
868 bool WebGLRenderingContext::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
874 if (!object->validate(contextGroup(), this)) {
875 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
878 deleted = !object->object();
883 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
887 if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
891 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
892 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
895 if (target == GraphicsContext3D::ARRAY_BUFFER)
896 m_boundArrayBuffer = buffer;
897 else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
898 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
900 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
904 m_context->bindBuffer(target, objectOrZero(buffer));
906 buffer->setTarget(target);
907 cleanupAfterGraphicsCall(false);
910 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
914 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
918 if (target != GraphicsContext3D::FRAMEBUFFER) {
919 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
922 m_framebufferBinding = buffer;
923 if (!m_framebufferBinding && m_drawingBuffer) {
924 // Instead of binding fb 0, bind the drawing buffer.
925 m_drawingBuffer->bind();
927 m_context->bindFramebuffer(target, objectOrZero(buffer));
929 buffer->setHasEverBeenBound();
930 cleanupAfterGraphicsCall(false);
933 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
937 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
941 if (target != GraphicsContext3D::RENDERBUFFER) {
942 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
945 m_renderbufferBinding = renderBuffer;
946 m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
948 renderBuffer->setHasEverBeenBound();
949 cleanupAfterGraphicsCall(false);
952 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
956 if (!checkObjectToBeBound("bindTexture", texture, deleted))
960 if (texture && texture->getTarget() && texture->getTarget() != target) {
961 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
964 GC3Dint maxLevel = 0;
965 if (target == GraphicsContext3D::TEXTURE_2D) {
966 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
967 maxLevel = m_maxTextureLevel;
969 if (m_drawingBuffer && !m_activeTextureUnit)
970 m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
972 } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
973 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
974 maxLevel = m_maxCubeMapTextureLevel;
976 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
979 m_context->bindTexture(target, objectOrZero(texture));
981 texture->setTarget(target, maxLevel);
983 // Note: previously we used to automatically set the TEXTURE_WRAP_R
984 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
985 // ES 2.0 doesn't expose this flag (a bug in the specification) and
986 // otherwise the application has no control over the seams in this
987 // dimension. However, it appears that supporting this properly on all
988 // platforms is fairly involved (will require a HashMap from texture ID
989 // in all ports), and we have not had any complaints, so the logic has
992 cleanupAfterGraphicsCall(false);
995 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
999 m_context->blendColor(red, green, blue, alpha);
1000 cleanupAfterGraphicsCall(false);
1003 void WebGLRenderingContext::blendEquation(GC3Denum mode)
1005 if (isContextLost() || !validateBlendEquation("blendEquation", mode))
1007 m_context->blendEquation(mode);
1008 cleanupAfterGraphicsCall(false);
1011 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
1013 if (isContextLost() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
1015 m_context->blendEquationSeparate(modeRGB, modeAlpha);
1016 cleanupAfterGraphicsCall(false);
1020 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
1022 if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1024 m_context->blendFunc(sfactor, dfactor);
1025 cleanupAfterGraphicsCall(false);
1028 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1030 // Note: Alpha does not have the same restrictions as RGB.
1031 if (isContextLost() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1033 m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1034 cleanupAfterGraphicsCall(false);
1037 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec)
1040 if (isContextLost())
1042 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1046 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1049 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1050 if (!buffer->associateBufferData(size)) {
1051 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1056 m_context->bufferData(target, size, usage);
1057 cleanupAfterGraphicsCall(false);
1060 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
1063 if (isContextLost())
1065 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1069 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1072 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1073 if (!buffer->associateBufferData(data)) {
1074 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1079 m_context->bufferData(target, data->byteLength(), data->data(), usage);
1080 cleanupAfterGraphicsCall(false);
1083 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1086 if (isContextLost())
1088 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1092 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1095 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1096 if (!buffer->associateBufferData(data)) {
1097 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1102 m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1103 cleanupAfterGraphicsCall(false);
1106 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec)
1109 if (isContextLost())
1111 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1115 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1120 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1121 if (!buffer->associateBufferSubData(offset, data)) {
1122 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1127 m_context->bufferSubData(target, offset, data->byteLength(), data->data());
1128 cleanupAfterGraphicsCall(false);
1131 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec)
1134 if (isContextLost())
1136 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1140 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1145 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1146 if (!buffer->associateBufferSubData(offset, data)) {
1147 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1152 m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress());
1153 cleanupAfterGraphicsCall(false);
1156 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target)
1158 if (isContextLost())
1159 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1160 if (target != GraphicsContext3D::FRAMEBUFFER) {
1161 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1164 if (!m_framebufferBinding || !m_framebufferBinding->object())
1165 return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1166 GC3Denum result = m_framebufferBinding->checkStatus();
1167 if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
1169 result = m_context->checkFramebufferStatus(target);
1170 cleanupAfterGraphicsCall(false);
1174 void WebGLRenderingContext::clear(GC3Dbitfield mask)
1176 if (isContextLost())
1178 if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1179 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "clear", "invalid mask");
1182 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1183 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "clear", "can not render to framebuffer");
1186 if (!clearIfComposited(mask))
1187 m_context->clear(mask);
1188 cleanupAfterGraphicsCall(true);
1191 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1193 if (isContextLost())
1203 m_clearColor[0] = r;
1204 m_clearColor[1] = g;
1205 m_clearColor[2] = b;
1206 m_clearColor[3] = a;
1207 m_context->clearColor(r, g, b, a);
1208 cleanupAfterGraphicsCall(false);
1211 void WebGLRenderingContext::clearDepth(GC3Dfloat depth)
1213 if (isContextLost())
1215 m_clearDepth = depth;
1216 m_context->clearDepth(depth);
1217 cleanupAfterGraphicsCall(false);
1220 void WebGLRenderingContext::clearStencil(GC3Dint s)
1222 if (isContextLost())
1225 m_context->clearStencil(s);
1226 cleanupAfterGraphicsCall(false);
1229 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1231 if (isContextLost())
1233 m_colorMask[0] = red;
1234 m_colorMask[1] = green;
1235 m_colorMask[2] = blue;
1236 m_colorMask[3] = alpha;
1237 m_context->colorMask(red, green, blue, alpha);
1238 cleanupAfterGraphicsCall(false);
1241 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec)
1244 if (isContextLost() || !validateWebGLObject("compileShader", shader))
1246 m_context->compileShader(objectOrZero(shader));
1247 cleanupAfterGraphicsCall(false);
1250 void WebGLRenderingContext::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
1251 GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
1253 if (isContextLost())
1255 if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1258 if (!validateCompressedTexFormat(internalformat)) {
1259 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1263 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1266 if (!validateCompressedTexDimensions("compressedTexImage2D", level, width, height, internalformat))
1268 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1271 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1274 if (!isGLES2NPOTStrict()) {
1275 if (level && WebGLTexture::isNPOT(width, height)) {
1276 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1280 graphicsContext3D()->compressedTexImage2D(target, level, internalformat, width, height,
1281 border, data->byteLength(), data->baseAddress());
1282 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1283 cleanupAfterGraphicsCall(false);
1286 void WebGLRenderingContext::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
1287 GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
1289 if (isContextLost())
1291 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1293 if (!validateCompressedTexFormat(format)) {
1294 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1297 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1300 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1304 if (format != tex->getInternalFormat(target, level)) {
1305 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1309 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1312 graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1313 width, height, format, data->byteLength(), data->baseAddress());
1314 cleanupAfterGraphicsCall(false);
1317 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
1319 if (isContextLost())
1321 if (!validateTexFuncParameters("copyTexImage2D", target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE))
1323 WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1326 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1327 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1330 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1331 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1334 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1335 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", "framebuffer not readable");
1338 clearIfComposited();
1339 if (isResourceSafe()) {
1340 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1341 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1343 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1344 GC3Dint clippedX, clippedY;
1345 GC3Dsizei clippedWidth, clippedHeight;
1346 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1347 m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border,
1348 internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment);
1349 if (clippedWidth > 0 && clippedHeight > 0) {
1350 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y,
1351 clippedX, clippedY, clippedWidth, clippedHeight);
1354 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1356 // FIXME: if the framebuffer is not complete, none of the below should be executed.
1357 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1358 cleanupAfterGraphicsCall(false);
1361 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1363 if (isContextLost())
1365 if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1367 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1370 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1372 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1373 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1376 if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) {
1377 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1380 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1381 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", "framebuffer not readable");
1384 clearIfComposited();
1385 if (isResourceSafe()) {
1386 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1387 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1389 GC3Dint clippedX, clippedY;
1390 GC3Dsizei clippedWidth, clippedHeight;
1391 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1392 GC3Denum format = tex->getInternalFormat(target, level);
1393 GC3Denum type = tex->getType(target, level);
1394 OwnArrayPtr<unsigned char> zero;
1395 if (width && height) {
1397 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1398 if (error != GraphicsContext3D::NO_ERROR) {
1399 synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1402 zero = adoptArrayPtr(new unsigned char[size]);
1404 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1407 memset(zero.get(), 0, size);
1409 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1410 if (clippedWidth > 0 && clippedHeight > 0) {
1411 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1412 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1413 clippedX, clippedY, clippedWidth, clippedHeight);
1416 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1417 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1420 cleanupAfterGraphicsCall(false);
1423 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer()
1425 if (isContextLost())
1427 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1428 addSharedObject(o.get());
1432 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer()
1434 if (isContextLost())
1436 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1437 addContextObject(o.get());
1441 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture()
1443 if (isContextLost())
1445 RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1446 addSharedObject(o.get());
1450 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram()
1452 if (isContextLost())
1454 RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1455 addSharedObject(o.get());
1459 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer()
1461 if (isContextLost())
1463 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1464 addSharedObject(o.get());
1468 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec)
1471 if (isContextLost())
1473 if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1474 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1478 RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1479 addSharedObject(o.get());
1483 void WebGLRenderingContext::cullFace(GC3Denum mode)
1485 if (isContextLost())
1487 m_context->cullFace(mode);
1488 cleanupAfterGraphicsCall(false);
1491 bool WebGLRenderingContext::deleteObject(WebGLObject* object)
1493 if (isContextLost() || !object)
1495 if (!object->validate(contextGroup(), this)) {
1496 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1499 if (object->object())
1500 // We need to pass in context here because we want
1501 // things in this context unbound.
1502 object->deleteObject(graphicsContext3D());
1506 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer)
1508 if (!deleteObject(buffer))
1510 if (m_boundArrayBuffer == buffer)
1511 m_boundArrayBuffer = 0;
1512 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1513 if (elementArrayBuffer == buffer)
1514 m_boundVertexArrayObject->setElementArrayBuffer(0);
1515 if (!isGLES2Compliant()) {
1516 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0);
1517 if (buffer == state.bufferBinding) {
1518 state.bufferBinding = m_vertexAttrib0Buffer;
1519 state.bytesPerElement = 0;
1521 state.type = GraphicsContext3D::FLOAT;
1522 state.normalized = false;
1524 state.originalStride = 0;
1530 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1532 if (!deleteObject(framebuffer))
1534 if (framebuffer == m_framebufferBinding) {
1535 m_framebufferBinding = 0;
1536 // Have to call bindFramebuffer here to bind back to internal fbo.
1537 if (m_drawingBuffer)
1538 m_drawingBuffer->bind();
1540 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1544 void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
1546 deleteObject(program);
1547 // We don't reset m_currentProgram to 0 here because the deletion of the
1548 // current program is delayed.
1551 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1553 if (!deleteObject(renderbuffer))
1555 if (renderbuffer == m_renderbufferBinding)
1556 m_renderbufferBinding = 0;
1557 if (m_framebufferBinding)
1558 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1561 void WebGLRenderingContext::deleteShader(WebGLShader* shader)
1563 deleteObject(shader);
1566 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture)
1568 if (!deleteObject(texture))
1570 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1571 if (texture == m_textureUnits[i].m_texture2DBinding)
1572 m_textureUnits[i].m_texture2DBinding = 0;
1573 if (texture == m_textureUnits[i].m_textureCubeMapBinding)
1574 m_textureUnits[i].m_textureCubeMapBinding = 0;
1576 if (m_framebufferBinding)
1577 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1580 void WebGLRenderingContext::depthFunc(GC3Denum func)
1582 if (isContextLost())
1584 m_context->depthFunc(func);
1585 cleanupAfterGraphicsCall(false);
1588 void WebGLRenderingContext::depthMask(GC3Dboolean flag)
1590 if (isContextLost())
1593 m_context->depthMask(flag);
1594 cleanupAfterGraphicsCall(false);
1597 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1599 if (isContextLost())
1602 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1605 m_context->depthRange(zNear, zFar);
1606 cleanupAfterGraphicsCall(false);
1609 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1612 if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1614 if (!program->detachShader(shader)) {
1615 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1618 m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1619 shader->onDetached(graphicsContext3D());
1620 cleanupAfterGraphicsCall(false);
1623 void WebGLRenderingContext::disable(GC3Denum cap)
1625 if (isContextLost() || !validateCapability("disable", cap))
1627 if (cap == GraphicsContext3D::SCISSOR_TEST) {
1628 m_scissorEnabled = false;
1629 if (m_drawingBuffer)
1630 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1632 m_context->disable(cap);
1633 cleanupAfterGraphicsCall(false);
1636 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1639 if (isContextLost())
1641 if (index >= m_maxVertexAttribs) {
1642 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1646 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1647 state.enabled = false;
1649 if (index > 0 || isGLES2Compliant()) {
1650 m_context->disableVertexAttribArray(index);
1651 cleanupAfterGraphicsCall(false);
1655 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1657 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1659 if (!elementArrayBuffer)
1665 if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1666 // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1670 // Make uoffset an element offset.
1673 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1674 if (offset > n || count > n - offset)
1676 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1677 GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1678 if (offset > n || count > n - offset)
1684 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired)
1686 // Performs conservative validation by caching a maximum index of
1687 // the given type per element array buffer. If all of the bound
1688 // array buffers have enough elements to satisfy that maximum
1689 // index, skips the expensive per-draw-call iteration in
1690 // validateIndexArrayPrecise.
1692 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1694 if (!elementArrayBuffer)
1697 GC3Dsizeiptr numElements = elementArrayBuffer->byteLength();
1698 // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative.
1701 const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer();
1704 int maxIndex = elementArrayBuffer->getCachedMaxIndex(type);
1706 // Compute the maximum index in the entire buffer for the given type of index.
1708 case GraphicsContext3D::UNSIGNED_BYTE: {
1709 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data());
1710 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1711 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1714 case GraphicsContext3D::UNSIGNED_SHORT: {
1715 numElements /= sizeof(GC3Dushort);
1716 const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data());
1717 for (GC3Dsizeiptr i = 0; i < numElements; i++)
1718 maxIndex = max(maxIndex, static_cast<int>(p[i]));
1724 elementArrayBuffer->setCachedMaxIndex(type, maxIndex);
1727 if (maxIndex >= 0) {
1728 // The number of required elements is one more than the maximum
1729 // index that will be accessed.
1730 numElementsRequired = maxIndex + 1;
1737 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired)
1739 ASSERT(count >= 0 && offset >= 0);
1742 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1744 if (!elementArrayBuffer)
1748 numElementsRequired = 0;
1752 if (!elementArrayBuffer->elementArrayBuffer())
1755 unsigned long uoffset = offset;
1756 unsigned long n = count;
1758 if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1759 // Make uoffset an element offset.
1760 uoffset /= sizeof(GC3Dushort);
1761 const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1767 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1768 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1776 // Then set the last index in the index array and make sure it is valid.
1777 numElementsRequired = lastIndex + 1;
1778 return numElementsRequired > 0;
1781 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired)
1783 if (!m_currentProgram)
1786 // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1787 for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1788 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1790 && (!state.bufferBinding || !state.bufferBinding->object()))
1794 if (numElementsRequired <= 0)
1797 // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size
1798 int smallestNumElements = INT_MAX;
1799 int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1800 for (int i = 0; i < numActiveAttribLocations; ++i) {
1801 int loc = m_currentProgram->getActiveAttribLocation(i);
1802 if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1803 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1804 if (state.enabled) {
1805 // Avoid off-by-one errors in numElements computation.
1806 // For the last element, we will only touch the data for the
1807 // element and nothing beyond it.
1808 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1809 int numElements = 0;
1810 ASSERT(state.stride > 0);
1811 if (bytesRemaining >= state.bytesPerElement)
1812 numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1813 if (numElements < smallestNumElements)
1814 smallestNumElements = numElements;
1819 if (smallestNumElements == INT_MAX)
1820 smallestNumElements = 0;
1822 return numElementsRequired <= smallestNumElements;
1825 bool WebGLRenderingContext::validateWebGLObject(const char* functionName, WebGLObject* object)
1827 if (!object || !object->object()) {
1828 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1831 if (!object->validate(contextGroup(), this)) {
1832 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1838 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1842 if (isContextLost() || !validateDrawMode("drawArrays", mode))
1845 if (!validateStencilSettings("drawArrays"))
1848 if (first < 0 || count < 0) {
1849 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawArrays", "first or count < 0");
1856 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1857 // Ensure we have a valid rendering state
1858 CheckedInt<GC3Dint> checkedFirst(first);
1859 CheckedInt<GC3Dint> checkedCount(count);
1860 CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount;
1861 if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) {
1862 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attempt to access out of bounds arrays");
1866 if (!validateRenderingState(0)) {
1867 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawArrays", "attribs not setup correctly");
1872 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1873 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawArrays", "framebuffer can not be rendered to");
1877 clearIfComposited();
1879 bool vertexAttrib0Simulated = false;
1880 if (!isGLES2Compliant())
1881 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1882 if (!isGLES2NPOTStrict())
1883 handleNPOTTextures(true);
1884 m_context->drawArrays(mode, first, count);
1885 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1886 restoreStatesAfterVertexAttrib0Simulation();
1887 if (!isGLES2NPOTStrict())
1888 handleNPOTTextures(false);
1889 cleanupAfterGraphicsCall(true);
1892 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec)
1896 if (isContextLost() || !validateDrawMode("drawElements", mode))
1899 if (!validateStencilSettings("drawElements"))
1903 case GraphicsContext3D::UNSIGNED_BYTE:
1904 case GraphicsContext3D::UNSIGNED_SHORT:
1907 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "drawElements", "invalid type");
1911 if (count < 0 || offset < 0) {
1912 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "drawElements", "count or offset < 0");
1919 if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1920 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "no ELEMENT_ARRAY_BUFFER bound");
1924 int numElements = 0;
1925 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1926 // Ensure we have a valid rendering state
1927 if (!validateElementArraySize(count, type, offset)) {
1928 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1933 if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) {
1934 if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) {
1935 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attempt to access out of bounds arrays");
1940 if (!validateRenderingState(0)) {
1941 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "drawElements", "attribs not setup correctly");
1946 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
1947 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "drawElements", "framebuffer can not be rendered to");
1950 clearIfComposited();
1952 bool vertexAttrib0Simulated = false;
1953 if (!isGLES2Compliant()) {
1955 validateIndexArrayPrecise(count, type, offset, numElements);
1956 vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1958 if (!isGLES2NPOTStrict())
1959 handleNPOTTextures(true);
1960 m_context->drawElements(mode, count, type, offset);
1961 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1962 restoreStatesAfterVertexAttrib0Simulation();
1963 if (!isGLES2NPOTStrict())
1964 handleNPOTTextures(false);
1965 cleanupAfterGraphicsCall(true);
1968 void WebGLRenderingContext::enable(GC3Denum cap)
1970 if (isContextLost() || !validateCapability("enable", cap))
1972 if (cap == GraphicsContext3D::SCISSOR_TEST) {
1973 m_scissorEnabled = true;
1974 if (m_drawingBuffer)
1975 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1977 m_context->enable(cap);
1978 cleanupAfterGraphicsCall(false);
1981 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1984 if (isContextLost())
1986 if (index >= m_maxVertexAttribs) {
1987 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1991 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1992 state.enabled = true;
1994 m_context->enableVertexAttribArray(index);
1995 cleanupAfterGraphicsCall(false);
1998 void WebGLRenderingContext::finish()
2000 if (isContextLost())
2002 m_context->finish();
2003 cleanupAfterGraphicsCall(false);
2006 void WebGLRenderingContext::flush()
2008 if (isContextLost())
2011 cleanupAfterGraphicsCall(false);
2014 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
2017 if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
2019 if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
2020 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
2023 if (buffer && !buffer->validate(contextGroup(), this)) {
2024 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
2027 // Don't allow the default framebuffer to be mutated; all current
2028 // implementations use an FBO internally in place of the default
2030 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2031 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
2034 Platform3DObject bufferObject = objectOrZero(buffer);
2035 bool reattachDepth = false;
2036 bool reattachStencil = false;
2037 bool reattachDepthStencilDepth = false;
2038 bool reattachDepthStencilStencil = false;
2039 switch (attachment) {
2040 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2041 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
2042 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
2043 if (!bufferObject) {
2044 reattachDepth = true;
2045 reattachStencil = true;
2048 case GraphicsContext3D::DEPTH_ATTACHMENT:
2049 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2051 reattachDepthStencilDepth = true;
2053 case GraphicsContext3D::STENCIL_ATTACHMENT:
2054 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2056 reattachDepthStencilStencil = true;
2059 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer));
2061 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2062 if (reattachDepth) {
2063 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT));
2065 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
2067 if (reattachStencil) {
2068 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT));
2070 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
2072 if (reattachDepthStencilDepth) {
2073 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
2075 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object);
2077 if (reattachDepthStencilStencil) {
2078 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT));
2080 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object);
2082 cleanupAfterGraphicsCall(false);
2085 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2088 if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2091 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2094 if (texture && !texture->validate(contextGroup(), this)) {
2095 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2098 // Don't allow the default framebuffer to be mutated; all current
2099 // implementations use an FBO internally in place of the default
2101 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2102 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2105 m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level);
2106 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2107 cleanupAfterGraphicsCall(false);
2110 void WebGLRenderingContext::frontFace(GC3Denum mode)
2112 if (isContextLost())
2114 m_context->frontFace(mode);
2115 cleanupAfterGraphicsCall(false);
2118 void WebGLRenderingContext::generateMipmap(GC3Denum target)
2120 if (isContextLost())
2122 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2125 if (!tex->canGenerateMipmaps()) {
2126 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2129 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2130 // on Mac. Remove the hack once this driver bug is fixed.
2132 bool needToResetMinFilter = false;
2133 if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2134 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2135 needToResetMinFilter = true;
2138 m_context->generateMipmap(target);
2140 if (needToResetMinFilter)
2141 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2143 tex->generateMipmapLevelInfo();
2144 cleanupAfterGraphicsCall(false);
2147 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2150 if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2153 if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2155 return WebGLActiveInfo::create(info.name, info.type, info.size);
2158 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2161 if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2164 if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2166 if (!isGLES2Compliant())
2167 if (info.size > 1 && !info.name.endsWith("[0]"))
2168 info.name.append("[0]");
2169 return WebGLActiveInfo::create(info.name, info.type, info.size);
2172 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects, ExceptionCode& ec)
2175 shaderObjects.clear();
2176 if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2179 const GC3Denum shaderType[] = {
2180 GraphicsContext3D::VERTEX_SHADER,
2181 GraphicsContext3D::FRAGMENT_SHADER
2183 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2184 WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2186 shaderObjects.append(shader);
2191 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name)
2193 if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2195 if (!validateLocationLength("getAttribLocation", name))
2197 if (!validateString("getAttribLocation", name))
2199 if (isPrefixReserved(name))
2201 if (!program->getLinkStatus()) {
2202 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2205 return m_context->getAttribLocation(objectOrZero(program), name);
2208 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2211 if (isContextLost())
2212 return WebGLGetInfo();
2213 if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2214 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2215 return WebGLGetInfo();
2218 if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2219 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2220 return WebGLGetInfo();
2223 WebGLStateRestorer(this, false);
2225 m_context->getBufferParameteriv(target, pname, &value);
2226 if (pname == GraphicsContext3D::BUFFER_SIZE)
2227 return WebGLGetInfo(value);
2228 return WebGLGetInfo(static_cast<unsigned int>(value));
2231 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes()
2233 if (isContextLost())
2235 // We always need to return a new WebGLContextAttributes object to
2236 // prevent the user from mutating any cached version.
2237 return WebGLContextAttributes::create(m_context->getContextAttributes());
2240 GC3Denum WebGLRenderingContext::getError()
2242 return m_context->getError();
2245 WebGLExtension* WebGLRenderingContext::getExtension(const String& name)
2247 if (isContextLost())
2250 if (equalIgnoringCase(name, "WEBKIT_EXT_texture_filter_anisotropic")
2251 && m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic")) {
2252 if (!m_extTextureFilterAnisotropic) {
2253 m_context->getExtensions()->ensureEnabled("GL_EXT_texture_filter_anisotropic");
2254 m_extTextureFilterAnisotropic = EXTTextureFilterAnisotropic::create(this);
2256 return m_extTextureFilterAnisotropic.get();
2258 if (equalIgnoringCase(name, "OES_standard_derivatives")
2259 && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) {
2260 if (!m_oesStandardDerivatives) {
2261 m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives");
2262 m_oesStandardDerivatives = OESStandardDerivatives::create(this);
2264 return m_oesStandardDerivatives.get();
2266 if (equalIgnoringCase(name, "OES_texture_float")
2267 && m_context->getExtensions()->supports("GL_OES_texture_float")) {
2268 if (!m_oesTextureFloat) {
2269 m_context->getExtensions()->ensureEnabled("GL_OES_texture_float");
2270 m_oesTextureFloat = OESTextureFloat::create(this);
2272 return m_oesTextureFloat.get();
2274 if (equalIgnoringCase(name, "OES_vertex_array_object")
2275 && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) {
2276 if (!m_oesVertexArrayObject) {
2277 m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object");
2278 m_oesVertexArrayObject = OESVertexArrayObject::create(this);
2280 return m_oesVertexArrayObject.get();
2282 if (equalIgnoringCase(name, "WEBKIT_WEBGL_lose_context")
2283 // FIXME: remove this after a certain grace period.
2284 || equalIgnoringCase(name, "WEBKIT_lose_context")) {
2285 if (!m_webglLoseContext)
2286 m_webglLoseContext = WebGLLoseContext::create(this);
2287 return m_webglLoseContext.get();
2289 if (equalIgnoringCase(name, "WEBKIT_WEBGL_compressed_texture_s3tc")) {
2290 // Use WEBKIT_ prefix until extension is official.
2291 if (!m_webglCompressedTextureS3TC)
2292 m_webglCompressedTextureS3TC = WebGLCompressedTextureS3TC::create(this);
2293 return m_webglCompressedTextureS3TC.get();
2296 if (allowPrivilegedExtensions()) {
2297 if (equalIgnoringCase(name, "WEBGL_debug_renderer_info")) {
2298 if (!m_webglDebugRendererInfo)
2299 m_webglDebugRendererInfo = WebGLDebugRendererInfo::create(this);
2300 return m_webglDebugRendererInfo.get();
2302 if (equalIgnoringCase(name, "WEBGL_debug_shaders")
2303 && m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source")) {
2304 if (!m_webglDebugShaders)
2305 m_webglDebugShaders = WebGLDebugShaders::create(this);
2306 return m_webglDebugShaders.get();
2313 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec)
2316 if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2317 return WebGLGetInfo();
2319 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2320 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2321 return WebGLGetInfo();
2324 WebGLSharedObject* object = m_framebufferBinding->getAttachment(attachment);
2326 if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2327 return WebGLGetInfo(GraphicsContext3D::NONE);
2328 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2329 // specifies INVALID_OPERATION.
2330 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2331 return WebGLGetInfo();
2334 ASSERT(object->isTexture() || object->isRenderbuffer());
2335 if (object->isTexture()) {
2337 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2338 return WebGLGetInfo(GraphicsContext3D::TEXTURE);
2339 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2340 return WebGLGetInfo(PassRefPtr<WebGLTexture>(reinterpret_cast<WebGLTexture*>(object)));
2341 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2342 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2344 WebGLStateRestorer(this, false);
2346 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2347 return WebGLGetInfo(value);
2350 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2351 return WebGLGetInfo();
2355 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2356 return WebGLGetInfo(GraphicsContext3D::RENDERBUFFER);
2357 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2358 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(reinterpret_cast<WebGLRenderbuffer*>(object)));
2360 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2361 return WebGLGetInfo();
2366 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec)
2369 if (isContextLost())
2370 return WebGLGetInfo();
2371 WebGLStateRestorer(this, false);
2373 case GraphicsContext3D::ACTIVE_TEXTURE:
2374 return getUnsignedIntParameter(pname);
2375 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE:
2376 return getWebGLFloatArrayParameter(pname);
2377 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE:
2378 return getWebGLFloatArrayParameter(pname);
2379 case GraphicsContext3D::ALPHA_BITS:
2380 return getIntParameter(pname);
2381 case GraphicsContext3D::ARRAY_BUFFER_BINDING:
2382 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2383 case GraphicsContext3D::BLEND:
2384 return getBooleanParameter(pname);
2385 case GraphicsContext3D::BLEND_COLOR:
2386 return getWebGLFloatArrayParameter(pname);
2387 case GraphicsContext3D::BLEND_DST_ALPHA:
2388 return getUnsignedIntParameter(pname);
2389 case GraphicsContext3D::BLEND_DST_RGB:
2390 return getUnsignedIntParameter(pname);
2391 case GraphicsContext3D::BLEND_EQUATION_ALPHA:
2392 return getUnsignedIntParameter(pname);
2393 case GraphicsContext3D::BLEND_EQUATION_RGB:
2394 return getUnsignedIntParameter(pname);
2395 case GraphicsContext3D::BLEND_SRC_ALPHA:
2396 return getUnsignedIntParameter(pname);
2397 case GraphicsContext3D::BLEND_SRC_RGB:
2398 return getUnsignedIntParameter(pname);
2399 case GraphicsContext3D::BLUE_BITS:
2400 return getIntParameter(pname);
2401 case GraphicsContext3D::COLOR_CLEAR_VALUE:
2402 return getWebGLFloatArrayParameter(pname);
2403 case GraphicsContext3D::COLOR_WRITEMASK:
2404 return getBooleanArrayParameter(pname);
2405 case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS:
2406 return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2407 case GraphicsContext3D::CULL_FACE:
2408 return getBooleanParameter(pname);
2409 case GraphicsContext3D::CULL_FACE_MODE:
2410 return getUnsignedIntParameter(pname);
2411 case GraphicsContext3D::CURRENT_PROGRAM:
2412 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2413 case GraphicsContext3D::DEPTH_BITS:
2414 return getIntParameter(pname);
2415 case GraphicsContext3D::DEPTH_CLEAR_VALUE:
2416 return getFloatParameter(pname);
2417 case GraphicsContext3D::DEPTH_FUNC:
2418 return getUnsignedIntParameter(pname);
2419 case GraphicsContext3D::DEPTH_RANGE:
2420 return getWebGLFloatArrayParameter(pname);
2421 case GraphicsContext3D::DEPTH_TEST:
2422 return getBooleanParameter(pname);
2423 case GraphicsContext3D::DEPTH_WRITEMASK:
2424 return getBooleanParameter(pname);
2425 case GraphicsContext3D::DITHER:
2426 return getBooleanParameter(pname);
2427 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING:
2428 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer()));
2429 case GraphicsContext3D::FRAMEBUFFER_BINDING:
2430 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2431 case GraphicsContext3D::FRONT_FACE:
2432 return getUnsignedIntParameter(pname);
2433 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
2434 return getUnsignedIntParameter(pname);
2435 case GraphicsContext3D::GREEN_BITS:
2436 return getIntParameter(pname);
2437 case GraphicsContext3D::LINE_WIDTH:
2438 return getFloatParameter(pname);
2439 case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2440 return getIntParameter(pname);
2441 case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE:
2442 return getIntParameter(pname);
2443 case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS:
2444 return getIntParameter(pname);
2445 case GraphicsContext3D::MAX_RENDERBUFFER_SIZE:
2446 return getIntParameter(pname);
2447 case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS:
2448 return getIntParameter(pname);
2449 case GraphicsContext3D::MAX_TEXTURE_SIZE:
2450 return getIntParameter(pname);
2451 case GraphicsContext3D::MAX_VARYING_VECTORS:
2452 return getIntParameter(pname);
2453 case GraphicsContext3D::MAX_VERTEX_ATTRIBS:
2454 return getIntParameter(pname);
2455 case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2456 return getIntParameter(pname);
2457 case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS:
2458 return getIntParameter(pname);
2459 case GraphicsContext3D::MAX_VIEWPORT_DIMS:
2460 return getWebGLIntArrayParameter(pname);
2461 case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS:
2462 // FIXME: should we always return 0 for this?
2463 return getIntParameter(pname);
2464 case GraphicsContext3D::PACK_ALIGNMENT:
2465 return getIntParameter(pname);
2466 case GraphicsContext3D::POLYGON_OFFSET_FACTOR:
2467 return getFloatParameter(pname);
2468 case GraphicsContext3D::POLYGON_OFFSET_FILL:
2469 return getBooleanParameter(pname);
2470 case GraphicsContext3D::POLYGON_OFFSET_UNITS:
2471 return getFloatParameter(pname);
2472 case GraphicsContext3D::RED_BITS:
2473 return getIntParameter(pname);
2474 case GraphicsContext3D::RENDERBUFFER_BINDING:
2475 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2476 case GraphicsContext3D::RENDERER:
2477 return WebGLGetInfo(String("WebKit WebGL"));
2478 case GraphicsContext3D::SAMPLE_BUFFERS:
2479 return getIntParameter(pname);
2480 case GraphicsContext3D::SAMPLE_COVERAGE_INVERT:
2481 return getBooleanParameter(pname);
2482 case GraphicsContext3D::SAMPLE_COVERAGE_VALUE:
2483 return getFloatParameter(pname);
2484 case GraphicsContext3D::SAMPLES:
2485 return getIntParameter(pname);
2486 case GraphicsContext3D::SCISSOR_BOX:
2487 return getWebGLIntArrayParameter(pname);
2488 case GraphicsContext3D::SCISSOR_TEST:
2489 return getBooleanParameter(pname);
2490 case GraphicsContext3D::SHADING_LANGUAGE_VERSION:
2491 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")");
2492 case GraphicsContext3D::STENCIL_BACK_FAIL:
2493 return getUnsignedIntParameter(pname);
2494 case GraphicsContext3D::STENCIL_BACK_FUNC:
2495 return getUnsignedIntParameter(pname);
2496 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL:
2497 return getUnsignedIntParameter(pname);
2498 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS:
2499 return getUnsignedIntParameter(pname);
2500 case GraphicsContext3D::STENCIL_BACK_REF:
2501 return getIntParameter(pname);
2502 case GraphicsContext3D::STENCIL_BACK_VALUE_MASK:
2503 return getUnsignedIntParameter(pname);
2504 case GraphicsContext3D::STENCIL_BACK_WRITEMASK:
2505 return getUnsignedIntParameter(pname);
2506 case GraphicsContext3D::STENCIL_BITS:
2507 return getIntParameter(pname);
2508 case GraphicsContext3D::STENCIL_CLEAR_VALUE:
2509 return getIntParameter(pname);
2510 case GraphicsContext3D::STENCIL_FAIL:
2511 return getUnsignedIntParameter(pname);
2512 case GraphicsContext3D::STENCIL_FUNC:
2513 return getUnsignedIntParameter(pname);
2514 case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL:
2515 return getUnsignedIntParameter(pname);
2516 case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS:
2517 return getUnsignedIntParameter(pname);
2518 case GraphicsContext3D::STENCIL_REF:
2519 return getIntParameter(pname);
2520 case GraphicsContext3D::STENCIL_TEST:
2521 return getBooleanParameter(pname);
2522 case GraphicsContext3D::STENCIL_VALUE_MASK:
2523 return getUnsignedIntParameter(pname);
2524 case GraphicsContext3D::STENCIL_WRITEMASK:
2525 return getUnsignedIntParameter(pname);
2526 case GraphicsContext3D::SUBPIXEL_BITS:
2527 return getIntParameter(pname);
2528 case GraphicsContext3D::TEXTURE_BINDING_2D:
2529 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2530 case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP:
2531 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2532 case GraphicsContext3D::UNPACK_ALIGNMENT:
2533 return getIntParameter(pname);
2534 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2535 return WebGLGetInfo(m_unpackFlipY);
2536 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2537 return WebGLGetInfo(m_unpackPremultiplyAlpha);
2538 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2539 return WebGLGetInfo(m_unpackColorspaceConversion);
2540 case GraphicsContext3D::VENDOR:
2541 return WebGLGetInfo(String("WebKit"));
2542 case GraphicsContext3D::VERSION:
2543 return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")");
2544 case GraphicsContext3D::VIEWPORT:
2545 return getWebGLIntArrayParameter(pname);
2546 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2547 if (m_oesStandardDerivatives)
2548 return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2549 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2550 return WebGLGetInfo();
2551 case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2552 if (m_webglDebugRendererInfo)
2553 return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER));
2554 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2555 return WebGLGetInfo();
2556 case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2557 if (m_webglDebugRendererInfo)
2558 return WebGLGetInfo(m_context->getString(GraphicsContext3D::VENDOR));
2559 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2560 return WebGLGetInfo();
2561 case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2562 if (m_oesVertexArrayObject) {
2563 if (!m_boundVertexArrayObject->isDefaultObject())
2564 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2565 return WebGLGetInfo();
2567 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2568 return WebGLGetInfo();
2569 case Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2570 if (m_extTextureFilterAnisotropic)
2571 return getUnsignedIntParameter(Extensions3D::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2572 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2573 return WebGLGetInfo();
2575 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getParameter", "invalid parameter name");
2576 return WebGLGetInfo();
2580 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2583 if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2584 return WebGLGetInfo();
2586 WebGLStateRestorer(this, false);
2589 case GraphicsContext3D::DELETE_STATUS:
2590 return WebGLGetInfo(program->isDeleted());
2591 case GraphicsContext3D::VALIDATE_STATUS:
2592 m_context->getProgramiv(objectOrZero(program), pname, &value);
2593 return WebGLGetInfo(static_cast<bool>(value));
2594 case GraphicsContext3D::LINK_STATUS:
2595 return WebGLGetInfo(program->getLinkStatus());
2596 case GraphicsContext3D::ATTACHED_SHADERS:
2597 case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2598 case GraphicsContext3D::ACTIVE_UNIFORMS:
2599 m_context->getProgramiv(objectOrZero(program), pname, &value);
2600 return WebGLGetInfo(value);
2602 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2603 return WebGLGetInfo();
2607 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2610 if (isContextLost())
2612 if (!validateWebGLObject("getProgramInfoLog", program))
2614 WebGLStateRestorer(this, false);
2615 return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2618 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2621 if (isContextLost())
2622 return WebGLGetInfo();
2623 if (target != GraphicsContext3D::RENDERBUFFER) {
2624 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2625 return WebGLGetInfo();
2627 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2628 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2629 return WebGLGetInfo();
2632 if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2633 && !m_renderbufferBinding->isValid()) {
2634 ASSERT(!isDepthStencilSupported());
2637 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2638 value = m_renderbufferBinding->getWidth();
2640 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2641 value = m_renderbufferBinding->getHeight();
2643 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2644 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2645 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2646 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2649 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2652 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2655 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2656 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2658 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2659 return WebGLGetInfo();
2661 return WebGLGetInfo(value);
2664 WebGLStateRestorer(this, false);
2667 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2668 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2669 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2670 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2671 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2672 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2673 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2674 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2675 m_context->getRenderbufferParameteriv(target, pname, &value);
2676 return WebGLGetInfo(value);
2677 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2678 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2680 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2681 return WebGLGetInfo();
2685 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2688 if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2689 return WebGLGetInfo();
2690 WebGLStateRestorer(this, false);
2693 case GraphicsContext3D::DELETE_STATUS:
2694 return WebGLGetInfo(shader->isDeleted());
2695 case GraphicsContext3D::COMPILE_STATUS:
2696 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2697 return WebGLGetInfo(static_cast<bool>(value));
2698 case GraphicsContext3D::SHADER_TYPE:
2699 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2700 return WebGLGetInfo(static_cast<unsigned int>(value));
2702 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2703 return WebGLGetInfo();
2707 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2710 if (isContextLost())
2712 if (!validateWebGLObject("getShaderInfoLog", shader))
2714 WebGLStateRestorer(this, false);
2715 return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2718 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContext::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
2721 if (isContextLost())
2723 switch (shaderType) {
2724 case GraphicsContext3D::VERTEX_SHADER:
2725 case GraphicsContext3D::FRAGMENT_SHADER:
2728 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2731 switch (precisionType) {
2732 case GraphicsContext3D::LOW_FLOAT:
2733 case GraphicsContext3D::MEDIUM_FLOAT:
2734 case GraphicsContext3D::HIGH_FLOAT:
2735 case GraphicsContext3D::LOW_INT:
2736 case GraphicsContext3D::MEDIUM_INT:
2737 case GraphicsContext3D::HIGH_INT:
2740 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2744 GC3Dint range[2] = {0, 0};
2745 GC3Dint precision = 0;
2746 m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2747 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2750 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2753 if (isContextLost())
2755 if (!validateWebGLObject("getShaderSource", shader))
2757 return ensureNotNull(shader->getSource());
2760 Vector<String> WebGLRenderingContext::getSupportedExtensions()
2762 Vector<String> result;
2763 if (m_context->getExtensions()->supports("GL_OES_texture_float"))
2764 result.append("OES_texture_float");
2765 if (m_context->getExtensions()->supports("GL_OES_standard_derivatives"))
2766 result.append("OES_standard_derivatives");
2767 if (m_context->getExtensions()->supports("GL_EXT_texture_filter_anisotropic"))
2768 result.append("WEBKIT_EXT_texture_filter_anisotropic");
2769 if (m_context->getExtensions()->supports("GL_OES_vertex_array_object"))
2770 result.append("OES_vertex_array_object");
2771 result.append("WEBKIT_WEBGL_lose_context");
2772 if (WebGLCompressedTextureS3TC::supported(this))
2773 result.append("WEBKIT_WEBGL_compressed_texture_s3tc");
2775 if (allowPrivilegedExtensions()) {
2776 if (m_context->getExtensions()->supports("GL_ANGLE_translated_shader_source"))
2777 result.append("WEBGL_debug_shaders");
2778 result.append("WEBGL_debug_renderer_info");
2784 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2787 if (isContextLost())
2788 return WebGLGetInfo();
2789 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2791 return WebGLGetInfo();
2792 WebGLStateRestorer(this, false);
2795 case GraphicsContext3D::TEXTURE_MAG_FILTER:
2796 case GraphicsContext3D::TEXTURE_MIN_FILTER:
2797 case GraphicsContext3D::TEXTURE_WRAP_S:
2798 case GraphicsContext3D::TEXTURE_WRAP_T:
2799 m_context->getTexParameteriv(target, pname, &value);
2800 return WebGLGetInfo(static_cast<unsigned int>(value));
2801 case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2802 if (m_extTextureFilterAnisotropic) {
2803 m_context->getTexParameteriv(target, pname, &value);
2804 return WebGLGetInfo(static_cast<unsigned int>(value));
2806 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2807 return WebGLGetInfo();
2809 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2810 return WebGLGetInfo();
2814 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2817 if (isContextLost() || !validateWebGLObject("getUniform", program))
2818 return WebGLGetInfo();
2819 if (!uniformLocation || uniformLocation->program() != program) {
2820 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2821 return WebGLGetInfo();
2823 GC3Dint location = uniformLocation->location();
2825 WebGLStateRestorer(this, false);
2826 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2827 GC3Dint activeUniforms = 0;
2828 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2829 for (GC3Dint i = 0; i < activeUniforms; i++) {
2831 if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2832 return WebGLGetInfo();
2833 // Strip "[0]" from the name if it's an array.
2834 if (info.size > 1 && info.name.endsWith("[0]"))
2835 info.name = info.name.left(info.name.length() - 3);
2836 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2837 for (GC3Dint index = 0; index < info.size; ++index) {
2838 String name = info.name;
2839 if (info.size > 1 && index >= 1) {
2841 name.append(String::number(index));
2844 // Now need to look this up by name again to find its location
2845 GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name);
2846 if (loc == location) {
2847 // Found it. Use the type in the ActiveInfo to determine the return type.
2849 unsigned int length;
2850 switch (info.type) {
2851 case GraphicsContext3D::BOOL:
2852 baseType = GraphicsContext3D::BOOL;
2855 case GraphicsContext3D::BOOL_VEC2:
2856 baseType = GraphicsContext3D::BOOL;
2859 case GraphicsContext3D::BOOL_VEC3:
2860 baseType = GraphicsContext3D::BOOL;
2863 case GraphicsContext3D::BOOL_VEC4:
2864 baseType = GraphicsContext3D::BOOL;
2867 case GraphicsContext3D::INT:
2868 baseType = GraphicsContext3D::INT;
2871 case GraphicsContext3D::INT_VEC2:
2872 baseType = GraphicsContext3D::INT;
2875 case GraphicsContext3D::INT_VEC3:
2876 baseType = GraphicsContext3D::INT;
2879 case GraphicsContext3D::INT_VEC4:
2880 baseType = GraphicsContext3D::INT;
2883 case GraphicsContext3D::FLOAT:
2884 baseType = GraphicsContext3D::FLOAT;
2887 case GraphicsContext3D::FLOAT_VEC2:
2888 baseType = GraphicsContext3D::FLOAT;
2891 case GraphicsContext3D::FLOAT_VEC3:
2892 baseType = GraphicsContext3D::FLOAT;
2895 case GraphicsContext3D::FLOAT_VEC4:
2896 baseType = GraphicsContext3D::FLOAT;
2899 case GraphicsContext3D::FLOAT_MAT2:
2900 baseType = GraphicsContext3D::FLOAT;
2903 case GraphicsContext3D::FLOAT_MAT3:
2904 baseType = GraphicsContext3D::FLOAT;
2907 case GraphicsContext3D::FLOAT_MAT4:
2908 baseType = GraphicsContext3D::FLOAT;
2911 case GraphicsContext3D::SAMPLER_2D:
2912 case GraphicsContext3D::SAMPLER_CUBE:
2913 baseType = GraphicsContext3D::INT;
2917 // Can't handle this type
2918 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2919 return WebGLGetInfo();
2922 case GraphicsContext3D::FLOAT: {
2923 GC3Dfloat value[16] = {0};
2924 m_context->getUniformfv(objectOrZero(program), location, value);
2926 return WebGLGetInfo(value[0]);
2927 return WebGLGetInfo(Float32Array::create(value, length));
2929 case GraphicsContext3D::INT: {
2930 GC3Dint value[4] = {0};
2931 m_context->getUniformiv(objectOrZero(program), location, value);
2933 return WebGLGetInfo(value[0]);
2934 return WebGLGetInfo(Int32Array::create(value, length));
2936 case GraphicsContext3D::BOOL: {
2937 GC3Dint value[4] = {0};
2938 m_context->getUniformiv(objectOrZero(program), location, value);
2940 bool boolValue[16] = {0};
2941 for (unsigned j = 0; j < length; j++)
2942 boolValue[j] = static_cast<bool>(value[j]);
2943 return WebGLGetInfo(boolValue, length);
2945 return WebGLGetInfo(static_cast<bool>(value[0]));
2953 // If we get here, something went wrong in our unfortunately complex logic above
2954 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
2955 return WebGLGetInfo();
2958 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2961 if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
2963 if (!validateLocationLength("getUniformLocation", name))
2965 if (!validateString("getUniformLocation", name))
2967 if (isPrefixReserved(name))
2969 if (!program->getLinkStatus()) {
2970 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
2973 WebGLStateRestorer(this, false);
2974 GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2975 if (uniformLocation == -1)
2977 return WebGLUniformLocation::create(program, uniformLocation);
2980 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2983 if (isContextLost())
2984 return WebGLGetInfo();
2985 WebGLStateRestorer(this, false);
2986 if (index >= m_maxVertexAttribs) {
2987 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
2988 return WebGLGetInfo();
2990 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2992 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2993 if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2994 || !state.bufferBinding
2995 || !state.bufferBinding->object())
2996 return WebGLGetInfo();
2997 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2998 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2999 return WebGLGetInfo(state.enabled);
3000 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
3001 return WebGLGetInfo(state.normalized);
3002 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
3003 return WebGLGetInfo(state.size);
3004 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
3005 return WebGLGetInfo(state.originalStride);
3006 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
3007 return WebGLGetInfo(state.type);
3008 case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
3009 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
3011 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
3012 return WebGLGetInfo();
3016 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
3018 if (isContextLost())
3020 GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
3021 cleanupAfterGraphicsCall(false);
3025 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode)
3027 if (isContextLost())
3029 bool isValid = false;
3031 case GraphicsContext3D::GENERATE_MIPMAP_HINT:
3034 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
3035 if (m_oesStandardDerivatives)
3040 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "hint", "invalid target");
3043 m_context->hint(target, mode);
3044 cleanupAfterGraphicsCall(false);
3047 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer)
3049 if (!buffer || isContextLost())
3052 if (!buffer->hasEverBeenBound())
3055 return m_context->isBuffer(buffer->object());
3058 bool WebGLRenderingContext::isContextLost()
3060 return m_contextLost;
3063 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap)
3065 if (isContextLost() || !validateCapability("isEnabled", cap))
3067 return m_context->isEnabled(cap);
3070 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer)
3072 if (!framebuffer || isContextLost())
3075 if (!framebuffer->hasEverBeenBound())
3078 return m_context->isFramebuffer(framebuffer->object());
3081 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program)
3083 if (!program || isContextLost())
3086 return m_context->isProgram(program->object());
3089 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
3091 if (!renderbuffer || isContextLost())
3094 if (!renderbuffer->hasEverBeenBound())
3097 return m_context->isRenderbuffer(renderbuffer->object());
3100 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader)
3102 if (!shader || isContextLost())
3105 return m_context->isShader(shader->object());
3108 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture)
3110 if (!texture || isContextLost())
3113 if (!texture->hasEverBeenBound())
3116 return m_context->isTexture(texture->object());
3119 void WebGLRenderingContext::lineWidth(GC3Dfloat width)
3121 if (isContextLost())
3123 m_context->lineWidth(width);
3124 cleanupAfterGraphicsCall(false);
3127 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec)
3130 if (isContextLost() || !validateWebGLObject("linkProgram", program))
3132 if (!isGLES2Compliant()) {
3133 if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
3134 program->setLinkStatus(false);
3139 m_context->linkProgram(objectOrZero(program));
3140 program->increaseLinkCount();
3141 cleanupAfterGraphicsCall(false);
3144 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param)
3146 if (isContextLost())
3149 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
3150 m_unpackFlipY = param;
3152 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3153 m_unpackPremultiplyAlpha = param;
3155 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
3156 if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
3157 m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
3159 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
3163 case GraphicsContext3D::PACK_ALIGNMENT:
3164 case GraphicsContext3D::UNPACK_ALIGNMENT:
3165 if (param == 1 || param == 2 || param == 4 || param == 8) {
3166 if (pname == GraphicsContext3D::PACK_ALIGNMENT)
3167 m_packAlignment = param;
3168 else // GraphicsContext3D::UNPACK_ALIGNMENT:
3169 m_unpackAlignment = param;
3170 m_context->pixelStorei(pname, param);
3171 cleanupAfterGraphicsCall(false);
3173 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3178 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
3183 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
3185 if (isContextLost())
3187 m_context->polygonOffset(factor, units);
3188 cleanupAfterGraphicsCall(false);
3191 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
3193 if (isContextLost())
3195 // Due to WebGL's same-origin restrictions, it is not possible to
3196 // taint the origin using the WebGL API.
3197 ASSERT(canvas()->originClean());
3198 // Validate input parameters.
3200 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3204 case GraphicsContext3D::ALPHA:
3205 case GraphicsContext3D::RGB:
3206 case GraphicsContext3D::RGBA:
3209 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
3213 case GraphicsContext3D::UNSIGNED_BYTE:
3214 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
3215 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
3216 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
3219 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
3222 if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
3223 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
3226 // Validate array type against pixel type.
3227 if (!pixels->isUnsignedByteArray()) {
3228 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
3231 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe())) {
3232 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", "framebuffer not readable");
3235 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3236 unsigned int totalBytesRequired;
3237 unsigned int padding;
3238 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3239 if (error != GraphicsContext3D::NO_ERROR) {
3240 synthesizeGLError(error, "readPixels", "invalid dimensions");
3243 if (pixels->byteLength() < totalBytesRequired) {
3244 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3247 clearIfComposited();
3248 void* data = pixels->baseAddress();
3251 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3252 m_context->readPixels(x, y, width, height, format, type, data);