2 * Copyright (C) 2015 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 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 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.
29 #include "WebGLRenderingContextBase.h"
31 #include "ANGLEInstancedArrays.h"
32 #include "CachedImage.h"
33 #include "DOMWindow.h"
35 #include "EXTBlendMinMax.h"
36 #include "EXTFragDepth.h"
37 #include "EXTShaderTextureLOD.h"
38 #include "EXTTextureFilterAnisotropic.h"
40 #include "ExceptionCode.h"
41 #include "Extensions3D.h"
43 #include "FrameLoader.h"
44 #include "FrameLoaderClient.h"
45 #include "FrameView.h"
46 #include "GraphicsContext.h"
47 #include "HTMLCanvasElement.h"
48 #include "HTMLImageElement.h"
49 #include "HTMLVideoElement.h"
50 #include "ImageBuffer.h"
51 #include "ImageData.h"
54 #include "MainFrame.h"
55 #include "NotImplemented.h"
56 #include "OESElementIndexUint.h"
57 #include "OESStandardDerivatives.h"
58 #include "OESTextureFloat.h"
59 #include "OESTextureFloatLinear.h"
60 #include "OESTextureHalfFloat.h"
61 #include "OESTextureHalfFloatLinear.h"
62 #include "OESVertexArrayObject.h"
64 #include "RenderBox.h"
66 #include "WebGL2RenderingContext.h"
67 #include "WebGLActiveInfo.h"
68 #include "WebGLBuffer.h"
69 #include "WebGLCompressedTextureATC.h"
70 #include "WebGLCompressedTexturePVRTC.h"
71 #include "WebGLCompressedTextureS3TC.h"
72 #include "WebGLContextAttributes.h"
73 #include "WebGLContextEvent.h"
74 #include "WebGLContextGroup.h"
75 #include "WebGLDebugRendererInfo.h"
76 #include "WebGLDebugShaders.h"
77 #include "WebGLDepthTexture.h"
78 #include "WebGLDrawBuffers.h"
79 #include "WebGLFramebuffer.h"
80 #include "WebGLLoseContext.h"
81 #include "WebGLProgram.h"
82 #include "WebGLRenderbuffer.h"
83 #include "WebGLRenderingContext.h"
84 #include "WebGLShader.h"
85 #include "WebGLShaderPrecisionFormat.h"
86 #include "WebGLTexture.h"
87 #include "WebGLUniformLocation.h"
89 #include <runtime/JSCInlines.h>
90 #include <runtime/TypedArrayInlines.h>
91 #include <runtime/Uint32Array.h>
92 #include <wtf/StdLibExtras.h>
93 #include <wtf/text/CString.h>
94 #include <wtf/text/StringBuilder.h>
98 const double secondsBetweenRestoreAttempts = 1.0;
99 const int maxGLErrorsAllowedToConsole = 256;
103 Platform3DObject objectOrZero(WebGLObject* object)
105 return object ? object->object() : 0;
108 GC3Dint clamp(GC3Dint value, GC3Dint min, GC3Dint max)
117 // Return true if a character belongs to the ASCII subset as defined in
118 // GLSL ES 1.0 spec section 3.1.
119 bool validateCharacter(unsigned char c)
121 // Printing characters are valid except " $ ` @ \ ' DEL.
122 if (c >= 32 && c <= 126
123 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
125 // Horizontal tab, line feed, vertical tab, form feed, carriage return
127 if (c >= 9 && c <= 13)
132 bool isPrefixReserved(const String& name)
134 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
139 // Strips comments from shader text. This allows non-ASCII characters
140 // to be used in comments without potentially breaking OpenGL
141 // implementations not expecting characters outside the GLSL ES set.
142 class StripComments {
144 StripComments(const String& str)
145 : m_parseState(BeginningOfLine)
146 , m_sourceString(str)
147 , m_length(str.length())
155 return m_builder.toString();
159 bool hasMoreCharacters() const
161 return (m_position < m_length);
166 while (hasMoreCharacters()) {
168 // process() might advance the position.
169 if (hasMoreCharacters())
176 bool peek(UChar& character) const
178 if (m_position + 1 >= m_length)
180 character = m_sourceString[m_position + 1];
184 UChar current() const
186 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
187 return m_sourceString[m_position];
195 bool isNewline(UChar character) const
197 // Don't attempt to canonicalize newline related characters.
198 return (character == '\n' || character == '\r');
201 void emit(UChar character)
203 m_builder.append(character);
207 // Have not seen an ASCII non-whitespace character yet on
208 // this line. Possible that we might see a preprocessor
212 // Have seen at least one ASCII non-whitespace character
216 // Handling a preprocessor directive. Passes through all
217 // characters up to the end of the line. Disables comment
219 InPreprocessorDirective,
221 // Handling a single-line comment. The comment text is
222 // replaced with a single space.
225 // Handling a multi-line comment. Newlines are passed
226 // through to preserve line numbers.
230 ParseState m_parseState;
231 String m_sourceString;
234 StringBuilder m_builder;
237 void StripComments::process(UChar c)
240 // No matter what state we are in, pass through newlines
241 // so we preserve line numbers.
244 if (m_parseState != InMultiLineComment)
245 m_parseState = BeginningOfLine;
251 switch (m_parseState) {
252 case BeginningOfLine:
253 if (WTF::isASCIISpace(c)) {
259 m_parseState = InPreprocessorDirective;
264 // Transition to normal state and re-handle character.
265 m_parseState = MiddleOfLine;
270 if (c == '/' && peek(temp)) {
272 m_parseState = InSingleLineComment;
279 m_parseState = InMultiLineComment;
280 // Emit the comment start in case the user has
281 // an unclosed comment and we want to later
293 case InPreprocessorDirective:
294 // No matter what the character is, just pass it
295 // through. Do not parse comments in this state. This
296 // might not be the right thing to do long term, but it
297 // should handle the #error preprocessor directive.
301 case InSingleLineComment:
302 // The newline code at the top of this function takes care
303 // of resetting our state when we get out of the
304 // single-line comment. Swallow all other characters.
307 case InMultiLineComment:
308 if (c == '*' && peek(temp) && temp == '/') {
311 m_parseState = MiddleOfLine;
316 // Swallow all other characters. Unclear whether we may
317 // want or need to just emit a space per character to try
318 // to preserve column numbers for debugging purposes.
322 } // namespace anonymous
324 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback {
325 WTF_MAKE_FAST_ALLOCATED;
327 explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
328 virtual void onContextLost() override { m_context->forceLostContext(WebGLRenderingContext::RealLostContext); }
329 virtual ~WebGLRenderingContextLostCallback() {}
331 WebGLRenderingContextBase* m_context;
334 class WebGLRenderingContextErrorMessageCallback : public GraphicsContext3D::ErrorMessageCallback {
335 WTF_MAKE_FAST_ALLOCATED;
337 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
338 virtual void onErrorMessage(const String& message, GC3Dint) override
340 if (m_context->m_synthesizedErrorsToConsole)
341 m_context->printGLErrorToConsole(message);
343 virtual ~WebGLRenderingContextErrorMessageCallback() { }
345 WebGLRenderingContextBase* m_context;
348 std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs, const String& type)
350 Document& document = canvas->document();
351 Frame* frame = document.frame();
355 // The FrameLoaderClient might block creation of a new WebGL context despite the page settings; in
356 // particular, if WebGL contexts were lost one or more times via the GL_ARB_robustness extension.
357 if (!frame->loader().client().allowWebGL(frame->settings().webGLEnabled())) {
358 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Web page was not allowed to create a WebGL context."));
362 bool isPendingPolicyResolution = false;
363 Document& topDocument = document.topDocument();
364 Page* page = topDocument.page();
365 if (page && !topDocument.url().isLocalFile()) {
366 WebGLLoadPolicy policy = page->mainFrame().loader().client().webGLPolicyForURL(topDocument.url());
368 if (policy == WebGLBlockCreation) {
369 LOG(WebGL, "The policy for this URL (%s) is to block WebGL.", topDocument.url().host().utf8().data());
373 if (policy == WebGLPendingCreation) {
374 LOG(WebGL, "WebGL policy is pending. May need to be resolved later.");
375 isPendingPolicyResolution = true;
379 GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes();
381 if (attributes.antialias) {
382 if (!frame->settings().openGLMultisamplingEnabled())
383 attributes.antialias = false;
386 attributes.noExtensions = true;
387 attributes.shareResources = false;
388 attributes.preferDiscreteGPU = true;
390 if (frame->settings().forceSoftwareWebGLRendering())
391 attributes.forceSoftwareRenderer = true;
394 attributes.devicePixelRatio = page->deviceScaleFactor();
396 if (isPendingPolicyResolution) {
397 LOG(WebGL, "Create a WebGL context that looks real, but will require a policy resolution if used.");
398 std::unique_ptr<WebGLRenderingContextBase> renderingContext = nullptr;
399 if (type == "experimental-webgl2")
400 renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, attributes));
402 renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, attributes));
403 return renderingContext;
406 HostWindow* hostWindow = document.view()->root()->hostWindow();
407 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow));
409 if (!context || !context->makeContextCurrent()) {
410 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context."));
414 Extensions3D* extensions = context->getExtensions();
415 if (extensions->supports("GL_EXT_debug_marker"))
416 extensions->pushGroupMarkerEXT("WebGLRenderingContext");
418 std::unique_ptr<WebGLRenderingContextBase> renderingContext = nullptr;
419 if (type == "experimental-webgl2")
420 renderingContext = std::unique_ptr<WebGL2RenderingContext>(new WebGL2RenderingContext(canvas, context, attributes));
422 renderingContext = std::unique_ptr<WebGLRenderingContext>(new WebGLRenderingContext(canvas, context, attributes));
423 renderingContext->suspendIfNeeded();
425 return renderingContext;
428 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, GraphicsContext3D::Attributes attributes)
429 : CanvasRenderingContext(passedCanvas)
430 , ActiveDOMObject(&passedCanvas->document())
432 , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
433 , m_restoreAllowed(false)
434 , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
435 , m_generatedImageCache(0)
436 , m_contextLost(false)
437 , m_contextLostMode(SyntheticLostContext)
438 , m_attributes(attributes)
439 , m_synthesizedErrorsToConsole(true)
440 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
441 , m_isPendingPolicyResolution(true)
442 , m_hasRequestedPolicyResolution(false)
446 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context, GraphicsContext3D::Attributes attributes)
447 : CanvasRenderingContext(passedCanvas)
448 , ActiveDOMObject(&passedCanvas->document())
450 , m_dispatchContextLostEventTimer(*this, &WebGLRenderingContextBase::dispatchContextLostEvent)
451 , m_restoreAllowed(false)
452 , m_restoreTimer(*this, &WebGLRenderingContextBase::maybeRestoreContext)
453 , m_generatedImageCache(4)
454 , m_contextLost(false)
455 , m_contextLostMode(SyntheticLostContext)
456 , m_attributes(attributes)
457 , m_synthesizedErrorsToConsole(true)
458 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
459 , m_isPendingPolicyResolution(false)
460 , m_hasRequestedPolicyResolution(false)
463 m_contextGroup = WebGLContextGroup::create();
464 m_contextGroup->addContext(this);
466 m_context->setWebGLContext(this);
468 m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
469 m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims);
472 initializeNewContext();
475 void WebGLRenderingContextBase::initializeNewContext()
477 ASSERT(!m_contextLost);
478 m_needsUpdate = true;
479 m_markedCanvasDirty = false;
480 m_activeTextureUnit = 0;
482 m_unpackAlignment = 4;
483 m_unpackFlipY = false;
484 m_unpackPremultiplyAlpha = false;
485 m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL;
486 m_boundArrayBuffer = 0;
487 m_currentProgram = 0;
488 m_framebufferBinding = 0;
489 m_renderbufferBinding = 0;
491 m_stencilEnabled = false;
492 m_stencilMask = 0xFFFFFFFF;
493 m_stencilMaskBack = 0xFFFFFFFF;
494 m_stencilFuncRef = 0;
495 m_stencilFuncRefBack = 0;
496 m_stencilFuncMask = 0xFFFFFFFF;
497 m_stencilFuncMaskBack = 0xFFFFFFFF;
498 m_layerCleared = false;
499 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
501 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
502 m_scissorEnabled = false;
505 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
507 GC3Dint numCombinedTextureImageUnits = 0;
508 m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
509 m_textureUnits.clear();
510 m_textureUnits.resize(numCombinedTextureImageUnits);
512 GC3Dint numVertexAttribs = 0;
513 m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs);
514 m_maxVertexAttribs = numVertexAttribs;
516 m_maxTextureSize = 0;
517 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize);
518 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
519 m_maxCubeMapTextureSize = 0;
520 m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
521 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
522 m_maxRenderbufferSize = 0;
523 m_context->getIntegerv(GraphicsContext3D::MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
525 // These two values from EXT_draw_buffers are lazily queried.
526 m_maxDrawBuffers = 0;
527 m_maxColorAttachments = 0;
529 m_backDrawBuffer = GraphicsContext3D::BACK;
530 m_drawBuffersWebGLRequirementsChecked = false;
531 m_drawBuffersSupported = false;
533 m_vertexAttribValue.resize(m_maxVertexAttribs);
535 if (!isGLES2NPOTStrict())
536 createFallbackBlackTextures1x1();
538 IntSize canvasSize = clampedCanvasSize();
539 m_context->reshape(canvasSize.width(), canvasSize.height());
540 m_context->viewport(0, 0, canvasSize.width(), canvasSize.height());
541 m_context->scissor(0, 0, canvasSize.width(), canvasSize.height());
543 m_context->setContextLostCallback(std::make_unique<WebGLRenderingContextLostCallback>(this));
544 m_context->setErrorMessageCallback(std::make_unique<WebGLRenderingContextErrorMessageCallback>(this));
547 void WebGLRenderingContextBase::setupFlags()
551 if (Page* page = canvas()->document().page())
552 m_synthesizedErrorsToConsole = page->settings().webGLErrorsToConsoleEnabled();
554 m_isGLES2Compliant = m_context->isGLES2Compliant();
555 m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs");
556 m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe");
557 if (m_isGLES2Compliant) {
558 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot");
559 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil");
561 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two");
562 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil");
564 m_isRobustnessEXTSupported = m_context->getExtensions()->isEnabled("GL_EXT_robustness");
567 bool WebGLRenderingContextBase::allowPrivilegedExtensions() const
569 if (Page* page = canvas()->document().page())
570 return page->settings().privilegedWebGLExtensionsEnabled();
574 void WebGLRenderingContextBase::addCompressedTextureFormat(GC3Denum format)
576 if (!m_compressedTextureFormats.contains(format))
577 m_compressedTextureFormats.append(format);
580 WebGLRenderingContextBase::~WebGLRenderingContextBase()
582 // Remove all references to WebGLObjects so if they are the last reference
583 // they will be freed before the last context is removed from the context group.
584 m_boundArrayBuffer = nullptr;
585 m_defaultVertexArrayObject = nullptr;
586 m_boundVertexArrayObject = nullptr;
587 m_vertexAttrib0Buffer = nullptr;
588 m_currentProgram = nullptr;
589 m_framebufferBinding = nullptr;
590 m_renderbufferBinding = nullptr;
592 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
593 m_textureUnits[i].texture2DBinding = nullptr;
594 m_textureUnits[i].textureCubeMapBinding = nullptr;
597 m_blackTexture2D = nullptr;
598 m_blackTextureCubeMap = nullptr;
600 if (!m_isPendingPolicyResolution) {
601 detachAndRemoveAllObjects();
602 destroyGraphicsContext3D();
603 m_contextGroup->removeContext(this);
607 void WebGLRenderingContextBase::destroyGraphicsContext3D()
609 if (m_isPendingPolicyResolution)
613 m_context->setContextLostCallback(nullptr);
614 m_context->setErrorMessageCallback(nullptr);
619 void WebGLRenderingContextBase::markContextChanged()
621 if (m_framebufferBinding)
624 m_context->markContextChanged();
626 m_layerCleared = false;
627 RenderBox* renderBox = canvas()->renderBox();
628 if (isAccelerated() && renderBox && renderBox->hasAcceleratedCompositing()) {
629 m_markedCanvasDirty = true;
630 canvas()->clearCopiedImage();
631 renderBox->contentChanged(CanvasChanged);
633 if (!m_markedCanvasDirty) {
634 m_markedCanvasDirty = true;
635 canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
640 bool WebGLRenderingContextBase::clearIfComposited(GC3Dbitfield mask)
642 if (isContextLostOrPending())
645 if (!m_context->layerComposited() || m_layerCleared
646 || m_attributes.preserveDrawingBuffer || (mask && m_framebufferBinding))
649 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
651 // Determine if it's possible to combine the clear the user asked for and this clear.
652 bool combinedClear = mask && !m_scissorEnabled;
654 m_context->disable(GraphicsContext3D::SCISSOR_TEST);
655 if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT))
656 m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
657 m_colorMask[1] ? m_clearColor[1] : 0,
658 m_colorMask[2] ? m_clearColor[2] : 0,
659 m_colorMask[3] ? m_clearColor[3] : 0);
661 m_context->clearColor(0, 0, 0, 0);
662 m_context->colorMask(true, true, true, true);
663 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
664 if (contextAttributes->depth()) {
665 if (!combinedClear || !m_depthMask || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))
666 m_context->clearDepth(1.0f);
667 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
668 m_context->depthMask(true);
670 if (contextAttributes->stencil()) {
671 if (combinedClear && (mask & GraphicsContext3D::STENCIL_BUFFER_BIT))
672 m_context->clearStencil(m_clearStencil & m_stencilMask);
674 m_context->clearStencil(0);
675 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
676 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xFFFFFFFF);
678 if (m_framebufferBinding)
679 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
680 m_context->clear(clearMask);
682 restoreStateAfterClear();
683 if (m_framebufferBinding)
684 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
685 m_layerCleared = true;
687 return combinedClear;
690 void WebGLRenderingContextBase::restoreStateAfterClear()
692 // Restore the state that the context set.
693 if (m_scissorEnabled)
694 m_context->enable(GraphicsContext3D::SCISSOR_TEST);
695 m_context->clearColor(m_clearColor[0], m_clearColor[1],
696 m_clearColor[2], m_clearColor[3]);
697 m_context->colorMask(m_colorMask[0], m_colorMask[1],
698 m_colorMask[2], m_colorMask[3]);
699 m_context->clearDepth(m_clearDepth);
700 m_context->clearStencil(m_clearStencil);
701 m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, m_stencilMask);
702 m_context->depthMask(m_depthMask);
705 void WebGLRenderingContextBase::markLayerComposited()
707 if (isContextLostOrPending())
709 m_context->markLayerComposited();
712 void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
714 if (isContextLostOrPending())
717 if (canvas()->document().printing())
718 canvas()->clearPresentationCopy();
720 // Until the canvas is written to by the application, the clear that
721 // happened after it was composited should be ignored by the compositor.
722 if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) {
723 m_context->paintCompositedResultsToCanvas(canvas()->buffer());
725 canvas()->makePresentationCopy();
727 canvas()->clearPresentationCopy();
730 if (!m_markedCanvasDirty && !m_layerCleared)
733 canvas()->clearCopiedImage();
734 m_markedCanvasDirty = false;
736 m_context->paintRenderingResultsToCanvas(canvas()->buffer());
739 PassRefPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
741 if (isContextLostOrPending())
744 return m_context->paintRenderingResultsToImageData();
747 void WebGLRenderingContextBase::reshape(int width, int height)
749 if (isContextLostOrPending())
752 // This is an approximation because at WebGLRenderingContext level we don't
753 // know if the underlying FBO uses textures or renderbuffers.
754 GC3Dint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
755 // Limit drawing buffer size to 4k to avoid memory exhaustion.
756 const int sizeUpperLimit = 4096;
757 maxSize = std::min(maxSize, sizeUpperLimit);
758 GC3Dint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
759 GC3Dint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
760 width = clamp(width, 1, maxWidth);
761 height = clamp(height, 1, maxHeight);
764 RenderBox* renderBox = canvas()->renderBox();
765 if (renderBox && renderBox->hasAcceleratedCompositing())
766 renderBox->contentChanged(CanvasChanged);
767 m_needsUpdate = false;
770 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
771 // clear (and this matches what reshape will do).
772 m_context->reshape(width, height);
774 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].texture2DBinding.get()));
775 m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
776 if (m_framebufferBinding)
777 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
780 int WebGLRenderingContextBase::drawingBufferWidth() const
782 return m_context->getInternalFramebufferSize().width();
785 int WebGLRenderingContextBase::drawingBufferHeight() const
787 return m_context->getInternalFramebufferSize().height();
790 unsigned WebGLRenderingContextBase::sizeInBytes(GC3Denum type)
793 case GraphicsContext3D::BYTE:
794 return sizeof(GC3Dbyte);
795 case GraphicsContext3D::UNSIGNED_BYTE:
796 return sizeof(GC3Dubyte);
797 case GraphicsContext3D::SHORT:
798 return sizeof(GC3Dshort);
799 case GraphicsContext3D::UNSIGNED_SHORT:
800 return sizeof(GC3Dushort);
801 case GraphicsContext3D::INT:
802 return sizeof(GC3Dint);
803 case GraphicsContext3D::UNSIGNED_INT:
804 return sizeof(GC3Duint);
805 case GraphicsContext3D::FLOAT:
806 return sizeof(GC3Dfloat);
808 ASSERT_NOT_REACHED();
812 void WebGLRenderingContextBase::activeTexture(GC3Denum texture, ExceptionCode& ec)
815 if (isContextLostOrPending())
817 if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) {
818 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "activeTexture", "texture unit out of range");
821 m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0;
822 m_context->activeTexture(texture);
825 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
828 if (isContextLostOrPending() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
830 if (!program->attachShader(shader)) {
831 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "attachShader", "shader attachment already has shader");
834 m_context->attachShader(objectOrZero(program), objectOrZero(shader));
835 shader->onAttached();
838 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec)
841 if (isContextLostOrPending() || !validateWebGLObject("bindAttribLocation", program))
843 if (!validateLocationLength("bindAttribLocation", name))
845 if (!validateString("bindAttribLocation", name))
847 if (isPrefixReserved(name)) {
848 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
851 if (index >= m_maxVertexAttribs) {
852 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bindAttribLocation", "index out of range");
855 m_context->bindAttribLocation(objectOrZero(program), index, name);
858 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
861 if (isContextLostOrPending())
864 if (!object->validate(contextGroup(), this)) {
865 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object not from this context");
868 deleted = !object->object();
873 void WebGLRenderingContextBase::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec)
877 if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
881 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
882 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
885 if (target == GraphicsContext3D::ARRAY_BUFFER)
886 m_boundArrayBuffer = buffer;
887 else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER)
888 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
890 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindBuffer", "invalid target");
894 m_context->bindBuffer(target, objectOrZero(buffer));
896 buffer->setTarget(target);
899 void WebGLRenderingContextBase::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec)
903 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
907 if (target != GraphicsContext3D::FRAMEBUFFER) {
908 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindFramebuffer", "invalid target");
911 m_framebufferBinding = buffer;
912 m_context->bindFramebuffer(target, objectOrZero(buffer));
914 buffer->setHasEverBeenBound();
918 void WebGLRenderingContextBase::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec)
922 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
926 if (target != GraphicsContext3D::RENDERBUFFER) {
927 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindRenderbuffer", "invalid target");
930 m_renderbufferBinding = renderBuffer;
931 m_context->bindRenderbuffer(target, objectOrZero(renderBuffer));
933 renderBuffer->setHasEverBeenBound();
936 void WebGLRenderingContextBase::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec)
940 if (!checkObjectToBeBound("bindTexture", texture, deleted))
944 if (texture && texture->getTarget() && texture->getTarget() != target) {
945 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
948 GC3Dint maxLevel = 0;
949 if (target == GraphicsContext3D::TEXTURE_2D) {
950 m_textureUnits[m_activeTextureUnit].texture2DBinding = texture;
951 maxLevel = m_maxTextureLevel;
952 } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) {
953 m_textureUnits[m_activeTextureUnit].textureCubeMapBinding = texture;
954 maxLevel = m_maxCubeMapTextureLevel;
956 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "bindTexture", "invalid target");
959 m_context->bindTexture(target, objectOrZero(texture));
961 texture->setTarget(target, maxLevel);
963 // Note: previously we used to automatically set the TEXTURE_WRAP_R
964 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
965 // ES 2.0 doesn't expose this flag (a bug in the specification) and
966 // otherwise the application has no control over the seams in this
967 // dimension. However, it appears that supporting this properly on all
968 // platforms is fairly involved (will require a HashMap from texture ID
969 // in all ports), and we have not had any complaints, so the logic has
973 void WebGLRenderingContextBase::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha)
975 if (isContextLostOrPending())
977 m_context->blendColor(red, green, blue, alpha);
980 void WebGLRenderingContextBase::blendEquation(GC3Denum mode)
982 if (isContextLostOrPending() || !validateBlendEquation("blendEquation", mode))
984 m_context->blendEquation(mode);
987 void WebGLRenderingContextBase::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
989 if (isContextLostOrPending() || !validateBlendEquation("blendEquation", modeRGB) || !validateBlendEquation("blendEquation", modeAlpha))
991 m_context->blendEquationSeparate(modeRGB, modeAlpha);
995 void WebGLRenderingContextBase::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
997 if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
999 m_context->blendFunc(sfactor, dfactor);
1002 void WebGLRenderingContextBase::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
1004 // Note: Alpha does not have the same restrictions as RGB.
1005 if (isContextLostOrPending() || !validateBlendFuncFactors("blendFunc", srcRGB, dstRGB))
1007 m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1010 void WebGLRenderingContextBase::bufferData(GC3Denum target, long long size, GC3Denum usage, ExceptionCode& ec)
1013 if (isContextLostOrPending())
1015 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1019 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size < 0");
1023 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "size == 0");
1026 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1027 if (!buffer->associateBufferData(static_cast<GC3Dsizeiptr>(size))) {
1028 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1033 m_context->moveErrorsToSyntheticErrorList();
1034 m_context->bufferData(target, static_cast<GC3Dsizeiptr>(size), usage);
1035 if (m_context->moveErrorsToSyntheticErrorList()) {
1036 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1037 buffer->disassociateBufferData();
1041 void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec)
1044 if (isContextLostOrPending())
1046 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1050 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1053 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1054 if (!buffer->associateBufferData(data)) {
1055 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1060 m_context->moveErrorsToSyntheticErrorList();
1061 m_context->bufferData(target, data->byteLength(), data->data(), usage);
1062 if (m_context->moveErrorsToSyntheticErrorList()) {
1063 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1064 buffer->disassociateBufferData();
1068 void WebGLRenderingContextBase::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec)
1071 if (isContextLostOrPending())
1073 WebGLBuffer* buffer = validateBufferDataParameters("bufferData", target, usage);
1077 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "no data");
1080 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1081 if (!buffer->associateBufferData(data)) {
1082 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "invalid buffer");
1087 m_context->moveErrorsToSyntheticErrorList();
1088 m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage);
1089 if (m_context->moveErrorsToSyntheticErrorList()) {
1090 // The bufferData function failed. Tell the buffer it doesn't have the data it thinks it does.
1091 buffer->disassociateBufferData();
1095 void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBuffer* data, ExceptionCode& ec)
1098 if (isContextLostOrPending())
1100 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1104 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1109 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1110 if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1111 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1116 m_context->moveErrorsToSyntheticErrorList();
1117 m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->data());
1118 if (m_context->moveErrorsToSyntheticErrorList()) {
1119 // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1120 buffer->disassociateBufferData();
1124 void WebGLRenderingContextBase::bufferSubData(GC3Denum target, long long offset, ArrayBufferView* data, ExceptionCode& ec)
1127 if (isContextLostOrPending())
1129 WebGLBuffer* buffer = validateBufferDataParameters("bufferSubData", target, GraphicsContext3D::STATIC_DRAW);
1133 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset < 0");
1138 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1139 if (!buffer->associateBufferSubData(static_cast<GC3Dintptr>(offset), data)) {
1140 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferSubData", "offset out of range");
1145 m_context->moveErrorsToSyntheticErrorList();
1146 m_context->bufferSubData(target, static_cast<GC3Dintptr>(offset), data->byteLength(), data->baseAddress());
1147 if (m_context->moveErrorsToSyntheticErrorList()) {
1148 // The bufferSubData function failed. Tell the buffer it doesn't have the data it thinks it does.
1149 buffer->disassociateBufferData();
1153 GC3Denum WebGLRenderingContextBase::checkFramebufferStatus(GC3Denum target)
1155 if (isContextLostOrPending())
1156 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
1157 if (target != GraphicsContext3D::FRAMEBUFFER) {
1158 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1161 if (!m_framebufferBinding || !m_framebufferBinding->object())
1162 return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
1163 const char* reason = "framebuffer incomplete";
1164 GC3Denum result = m_framebufferBinding->checkStatus(&reason);
1165 if (result != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
1166 printGLWarningToConsole("checkFramebufferStatus", reason);
1169 result = m_context->checkFramebufferStatus(target);
1173 void WebGLRenderingContextBase::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a)
1175 if (isContextLostOrPending())
1185 m_clearColor[0] = r;
1186 m_clearColor[1] = g;
1187 m_clearColor[2] = b;
1188 m_clearColor[3] = a;
1189 m_context->clearColor(r, g, b, a);
1192 void WebGLRenderingContextBase::clearDepth(GC3Dfloat depth)
1194 if (isContextLostOrPending())
1196 m_clearDepth = depth;
1197 m_context->clearDepth(depth);
1200 void WebGLRenderingContextBase::clearStencil(GC3Dint s)
1202 if (isContextLostOrPending())
1205 m_context->clearStencil(s);
1208 void WebGLRenderingContextBase::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
1210 if (isContextLostOrPending())
1212 m_colorMask[0] = red;
1213 m_colorMask[1] = green;
1214 m_colorMask[2] = blue;
1215 m_colorMask[3] = alpha;
1216 m_context->colorMask(red, green, blue, alpha);
1219 void WebGLRenderingContextBase::compileShader(WebGLShader* shader, ExceptionCode& ec)
1222 if (isContextLostOrPending() || !validateWebGLObject("compileShader", shader))
1224 m_context->compileShader(objectOrZero(shader));
1226 m_context->getShaderiv(objectOrZero(shader), GraphicsContext3D::COMPILE_STATUS, &value);
1227 shader->setValid(value);
1230 void WebGLRenderingContextBase::compressedTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width,
1231 GC3Dsizei height, GC3Dint border, ArrayBufferView* data)
1233 if (isContextLostOrPending())
1235 if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1238 if (!validateCompressedTexFormat(internalformat)) {
1239 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1243 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "border not 0");
1246 if (!validateCompressedTexDimensions("compressedTexImage2D", target, level, width, height, internalformat))
1248 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1251 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1254 if (!isGLES2NPOTStrict()) {
1255 if (level && WebGLTexture::isNPOT(width, height)) {
1256 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1260 m_context->moveErrorsToSyntheticErrorList();
1261 m_context->compressedTexImage2D(target, level, internalformat, width, height,
1262 border, data->byteLength(), data->baseAddress());
1263 if (m_context->moveErrorsToSyntheticErrorList()) {
1264 // The compressedTexImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
1265 tex->markInvalid(target, level);
1269 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE);
1270 tex->setCompressed();
1273 void WebGLRenderingContextBase::compressedTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset,
1274 GC3Dsizei width, GC3Dsizei height, GC3Denum format, ArrayBufferView* data)
1276 if (isContextLostOrPending())
1278 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1280 if (!validateCompressedTexFormat(format)) {
1281 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1284 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1287 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1291 if (format != tex->getInternalFormat(target, level)) {
1292 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1296 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1299 graphicsContext3D()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1300 width, height, format, data->byteLength(), data->baseAddress());
1301 tex->setCompressed();
1304 bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GC3Denum format)
1306 if (GraphicsContext3D::getClearBitsByFormat(format) & (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) {
1307 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1313 void WebGLRenderingContextBase::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
1315 if (isContextLostOrPending())
1317 if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1319 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1322 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1324 // Before checking if it is in the range, check if overflow happens first.
1325 if (xoffset + width < 0 || yoffset + height < 0) {
1326 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1329 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) {
1330 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1333 GC3Denum internalformat = tex->getInternalFormat(target, level);
1334 if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1336 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) {
1337 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1340 const char* reason = "framebuffer incomplete";
1341 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1342 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1345 clearIfComposited();
1346 if (isResourceSafe())
1347 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1349 GC3Dint clippedX, clippedY;
1350 GC3Dsizei clippedWidth, clippedHeight;
1351 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) {
1352 GC3Denum format = tex->getInternalFormat(target, level);
1353 GC3Denum type = tex->getType(target, level);
1354 std::unique_ptr<unsigned char[]> zero;
1355 if (width && height) {
1357 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0);
1358 if (error != GraphicsContext3D::NO_ERROR) {
1359 synthesizeGLError(error, "copyTexSubImage2D", "bad dimensions");
1362 zero = std::make_unique<unsigned char[]>(size);
1364 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "copyTexSubImage2D", "out of memory");
1367 memset(zero.get(), 0, size);
1369 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get());
1370 if (clippedWidth > 0 && clippedHeight > 0)
1371 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y,
1372 clippedX, clippedY, clippedWidth, clippedHeight);
1374 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1378 PassRefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1380 if (isContextLostOrPending())
1382 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1383 addSharedObject(o.get());
1387 PassRefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1389 if (isContextLostOrPending())
1391 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1392 addContextObject(o.get());
1396 PassRefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1398 if (isContextLostOrPending())
1400 RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1401 addSharedObject(o.get());
1405 PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1407 if (isContextLostOrPending())
1409 RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1410 addSharedObject(o.get());
1414 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1416 if (isContextLostOrPending())
1418 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1419 addSharedObject(o.get());
1423 PassRefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GC3Denum type, ExceptionCode& ec)
1426 if (isContextLostOrPending())
1428 if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) {
1429 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "createShader", "invalid shader type");
1433 RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1434 addSharedObject(o.get());
1438 void WebGLRenderingContextBase::cullFace(GC3Denum mode)
1440 if (isContextLostOrPending())
1442 m_context->cullFace(mode);
1445 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1447 if (isContextLostOrPending() || !object)
1449 if (!object->validate(contextGroup(), this)) {
1450 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "delete", "object does not belong to this context");
1453 if (object->object())
1454 // We need to pass in context here because we want
1455 // things in this context unbound.
1456 object->deleteObject(graphicsContext3D());
1460 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1462 if (!deleteObject(buffer))
1464 if (m_boundArrayBuffer == buffer)
1465 m_boundArrayBuffer = 0;
1467 m_boundVertexArrayObject->unbindBuffer(buffer);
1470 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1472 if (!deleteObject(framebuffer))
1474 if (framebuffer == m_framebufferBinding) {
1475 m_framebufferBinding = 0;
1476 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0);
1480 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1482 deleteObject(program);
1483 // We don't reset m_currentProgram to 0 here because the deletion of the
1484 // current program is delayed.
1487 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1489 if (!deleteObject(renderbuffer))
1491 if (renderbuffer == m_renderbufferBinding)
1492 m_renderbufferBinding = 0;
1493 if (m_framebufferBinding)
1494 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1497 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1499 deleteObject(shader);
1502 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1504 if (!deleteObject(texture))
1506 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
1507 if (texture == m_textureUnits[i].texture2DBinding)
1508 m_textureUnits[i].texture2DBinding = nullptr;
1509 if (texture == m_textureUnits[i].textureCubeMapBinding)
1510 m_textureUnits[i].textureCubeMapBinding = nullptr;
1512 if (m_framebufferBinding)
1513 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1516 void WebGLRenderingContextBase::depthFunc(GC3Denum func)
1518 if (isContextLostOrPending())
1520 m_context->depthFunc(func);
1523 void WebGLRenderingContextBase::depthMask(GC3Dboolean flag)
1525 if (isContextLostOrPending())
1528 m_context->depthMask(flag);
1531 void WebGLRenderingContextBase::depthRange(GC3Dfloat zNear, GC3Dfloat zFar)
1533 if (isContextLostOrPending())
1536 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "depthRange", "zNear > zFar");
1539 m_context->depthRange(zNear, zFar);
1542 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec)
1545 if (isContextLostOrPending() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1547 if (!program->detachShader(shader)) {
1548 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "detachShader", "shader not attached");
1551 m_context->detachShader(objectOrZero(program), objectOrZero(shader));
1552 shader->onDetached(graphicsContext3D());
1555 void WebGLRenderingContextBase::disable(GC3Denum cap)
1557 if (isContextLostOrPending() || !validateCapability("disable", cap))
1559 if (cap == GraphicsContext3D::STENCIL_TEST) {
1560 m_stencilEnabled = false;
1564 if (cap == GraphicsContext3D::SCISSOR_TEST)
1565 m_scissorEnabled = false;
1566 m_context->disable(cap);
1569 void WebGLRenderingContextBase::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1572 if (isContextLostOrPending())
1574 if (index >= m_maxVertexAttribs) {
1575 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1579 WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1580 state.enabled = false;
1582 if (index > 0 || isGLES2Compliant())
1583 m_context->disableVertexAttribArray(index);
1586 bool WebGLRenderingContextBase::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
1588 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1590 if (!elementArrayBuffer)
1596 if (type == GraphicsContext3D::UNSIGNED_INT) {
1597 // For an unsigned int array, offset must be divisible by 4 for alignment reasons.
1601 // Make uoffset an element offset.
1604 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 4;
1605 if (offset > n || count > n - offset)
1607 } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1608 // For an unsigned short array, offset must be divisible by 2 for alignment reasons.
1612 // Make uoffset an element offset.
1615 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2;
1616 if (offset > n || count > n - offset)
1618 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1619 GC3Dsizeiptr n = elementArrayBuffer->byteLength();
1620 if (offset > n || count > n - offset)
1626 bool WebGLRenderingContextBase::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, unsigned& numElementsRequired)
1628 ASSERT(count >= 0 && offset >= 0);
1629 unsigned lastIndex = 0;
1631 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer();
1633 if (!elementArrayBuffer)
1637 numElementsRequired = 0;
1641 if (!elementArrayBuffer->elementArrayBuffer())
1644 unsigned long uoffset = offset;
1645 unsigned long n = count;
1647 if (type == GraphicsContext3D::UNSIGNED_INT) {
1648 // Make uoffset an element offset.
1649 uoffset /= sizeof(GC3Duint);
1650 const GC3Duint* p = static_cast<const GC3Duint*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1656 } else if (type == GraphicsContext3D::UNSIGNED_SHORT) {
1657 // Make uoffset an element offset.
1658 uoffset /= sizeof(GC3Dushort);
1659 const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1665 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) {
1666 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset;
1674 // Then set the last index in the index array and make sure it is valid.
1675 numElementsRequired = lastIndex + 1;
1676 return numElementsRequired > 0;
1679 bool WebGLRenderingContextBase::validateVertexAttributes(unsigned elementCount, unsigned primitiveCount)
1681 if (!m_currentProgram)
1684 // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1685 for (unsigned i = 0; i < m_maxVertexAttribs; ++i) {
1686 if (!m_boundVertexArrayObject->getVertexAttribState(i).validateBinding())
1690 if (elementCount <= 0)
1694 // Look in each consumed vertex attrib (by the current program).
1695 bool sawNonInstancedAttrib = false;
1696 bool sawEnabledAttrib = false;
1697 int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations();
1698 for (int i = 0; i < numActiveAttribLocations; ++i) {
1699 int loc = m_currentProgram->getActiveAttribLocation(i);
1700 if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) {
1701 const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc);
1702 if (state.enabled) {
1703 sawEnabledAttrib = true;
1704 // Avoid off-by-one errors in numElements computation.
1705 // For the last element, we will only touch the data for the
1706 // element and nothing beyond it.
1707 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset);
1708 unsigned numElements = 0;
1709 ASSERT(state.stride > 0);
1710 if (bytesRemaining >= state.bytesPerElement)
1711 numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride;
1712 unsigned instancesRequired = 0;
1713 if (state.divisor) {
1714 instancesRequired = ceil(static_cast<float>(primitiveCount) / state.divisor);
1715 if (instancesRequired > numElements)
1718 sawNonInstancedAttrib = true;
1719 if (elementCount > numElements)
1726 if (!sawNonInstancedAttrib && sawEnabledAttrib)
1732 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1734 if (!object || !object->object()) {
1735 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "no object or object deleted");
1738 if (!object->validate(contextGroup(), this)) {
1739 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "object does not belong to this context");
1745 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primitiveCount)
1747 if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1750 if (!validateStencilSettings(functionName))
1753 if (first < 0 || count < 0) {
1754 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "first or count < 0");
1759 markContextChanged();
1763 if (primitiveCount < 0) {
1764 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1768 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1769 // Ensure we have a valid rendering state
1770 Checked<GC3Dint, RecordOverflow> checkedFirst(first);
1771 Checked<GC3Dint, RecordOverflow> checkedCount(count);
1772 Checked<GC3Dint, RecordOverflow> checkedSum = checkedFirst + checkedCount;
1773 Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1774 if (checkedSum.hasOverflowed() || checkedPrimitiveCount.hasOverflowed() || !validateVertexAttributes(checkedSum.unsafeGet(), checkedPrimitiveCount.unsafeGet())) {
1775 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1779 if (!validateVertexAttributes(0)) {
1780 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
1785 const char* reason = "framebuffer incomplete";
1786 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1787 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1794 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, unsigned& numElements, GC3Dsizei primitiveCount)
1796 if (isContextLostOrPending() || !validateDrawMode(functionName, mode))
1799 if (!validateStencilSettings(functionName))
1803 case GraphicsContext3D::UNSIGNED_BYTE:
1804 case GraphicsContext3D::UNSIGNED_SHORT:
1806 case GraphicsContext3D::UNSIGNED_INT:
1807 if (m_oesElementIndexUint && !isWebGL2())
1809 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1812 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, functionName, "invalid type");
1816 if (count < 0 || offset < 0) {
1817 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "count or offset < 0");
1822 markContextChanged();
1826 if (primitiveCount < 0) {
1827 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "primcount < 0");
1831 if (!m_boundVertexArrayObject->getElementArrayBuffer()) {
1832 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
1836 if (!isErrorGeneratedOnOutOfBoundsAccesses()) {
1837 // Ensure we have a valid rendering state
1838 if (!validateElementArraySize(count, type, static_cast<GC3Dintptr>(offset))) {
1839 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "request out of bounds for current ELEMENT_ARRAY_BUFFER");
1845 Checked<GC3Dint, RecordOverflow> checkedCount(count);
1846 Checked<GC3Dint, RecordOverflow> checkedPrimitiveCount(primitiveCount);
1847 if (checkedCount.hasOverflowed() || checkedPrimitiveCount.hasOverflowed()) {
1848 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1852 if (!validateIndexArrayConservative(type, numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1853 if (!validateIndexArrayPrecise(checkedCount.unsafeGet(), type, static_cast<GC3Dintptr>(offset), numElements) || !validateVertexAttributes(numElements, checkedPrimitiveCount.unsafeGet())) {
1854 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attempt to access out of bounds arrays");
1859 if (!validateVertexAttributes(0)) {
1860 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "attribs not setup correctly");
1865 const char* reason = "framebuffer incomplete";
1866 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
1867 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
1874 void WebGLRenderingContextBase::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec)
1878 if (!validateDrawArrays("drawArrays", mode, first, count, 0))
1881 clearIfComposited();
1883 bool vertexAttrib0Simulated = false;
1884 if (!isGLES2Compliant())
1885 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1);
1886 if (!isGLES2NPOTStrict())
1887 checkTextureCompleteness("drawArrays", true);
1889 m_context->drawArrays(mode, first, count);
1891 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1892 restoreStatesAfterVertexAttrib0Simulation();
1893 if (!isGLES2NPOTStrict())
1894 checkTextureCompleteness("drawArrays", false);
1895 markContextChanged();
1898 void WebGLRenderingContextBase::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, ExceptionCode& ec)
1902 unsigned numElements = 0;
1903 if (!validateDrawElements("drawElements", mode, count, type, offset, numElements, 0))
1906 clearIfComposited();
1908 bool vertexAttrib0Simulated = false;
1909 if (!isGLES2Compliant()) {
1911 validateIndexArrayPrecise(count, type, static_cast<GC3Dintptr>(offset), numElements);
1912 vertexAttrib0Simulated = simulateVertexAttrib0(numElements);
1914 if (!isGLES2NPOTStrict())
1915 checkTextureCompleteness("drawElements", true);
1917 m_context->drawElements(mode, count, type, static_cast<GC3Dintptr>(offset));
1919 if (!isGLES2Compliant() && vertexAttrib0Simulated)
1920 restoreStatesAfterVertexAttrib0Simulation();
1921 if (!isGLES2NPOTStrict())
1922 checkTextureCompleteness("drawElements", false);
1923 markContextChanged();
1926 void WebGLRenderingContextBase::enable(GC3Denum cap)
1928 if (isContextLostOrPending() || !validateCapability("enable", cap))
1930 if (cap == GraphicsContext3D::STENCIL_TEST) {
1931 m_stencilEnabled = true;
1935 if (cap == GraphicsContext3D::SCISSOR_TEST)
1936 m_scissorEnabled = true;
1937 m_context->enable(cap);
1940 void WebGLRenderingContextBase::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec)
1943 if (isContextLostOrPending())
1945 if (index >= m_maxVertexAttribs) {
1946 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1950 WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1951 state.enabled = true;
1953 m_context->enableVertexAttribArray(index);
1956 void WebGLRenderingContextBase::finish()
1958 if (isContextLostOrPending())
1960 m_context->finish();
1963 void WebGLRenderingContextBase::flush()
1965 if (isContextLostOrPending())
1970 void WebGLRenderingContextBase::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec)
1973 if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
1975 if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) {
1976 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
1979 if (buffer && !buffer->validate(contextGroup(), this)) {
1980 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
1983 // Don't allow the default framebuffer to be mutated; all current
1984 // implementations use an FBO internally in place of the default
1986 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1987 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
1990 Platform3DObject bufferObject = objectOrZero(buffer);
1991 switch (attachment) {
1992 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
1993 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1994 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1997 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
1999 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
2003 void WebGLRenderingContextBase::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec)
2006 if (isContextLostOrPending() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
2009 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "framebufferTexture2D", "level not 0");
2012 if (texture && !texture->validate(contextGroup(), this)) {
2013 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
2016 // Don't allow the default framebuffer to be mutated; all current
2017 // implementations use an FBO internally in place of the default
2019 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2020 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
2023 Platform3DObject textureObject = objectOrZero(texture);
2024 switch (attachment) {
2025 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
2026 m_context->framebufferTexture2D(target, GraphicsContext3D::DEPTH_ATTACHMENT, textarget, textureObject, level);
2027 m_context->framebufferTexture2D(target, GraphicsContext3D::STENCIL_ATTACHMENT, textarget, textureObject, level);
2029 case GraphicsContext3D::DEPTH_ATTACHMENT:
2030 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2032 case GraphicsContext3D::STENCIL_ATTACHMENT:
2033 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2036 m_context->framebufferTexture2D(target, attachment, textarget, textureObject, level);
2038 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
2042 void WebGLRenderingContextBase::frontFace(GC3Denum mode)
2044 if (isContextLostOrPending())
2046 m_context->frontFace(mode);
2049 void WebGLRenderingContextBase::generateMipmap(GC3Denum target)
2051 if (isContextLostOrPending())
2053 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
2056 if (!tex->canGenerateMipmaps()) {
2057 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
2060 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=123916. Compressed textures should be allowed in WebGL 2:
2061 if (tex->isCompressed()) {
2062 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "generateMipmap", "trying to generate mipmaps from compressed texture");
2065 if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
2068 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
2069 // on Mac. Remove the hack once this driver bug is fixed.
2071 bool needToResetMinFilter = false;
2072 if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) {
2073 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR);
2074 needToResetMinFilter = true;
2077 m_context->generateMipmap(target);
2079 if (needToResetMinFilter)
2080 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter());
2082 tex->generateMipmapLevelInfo();
2085 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2088 if (isContextLostOrPending() || !validateWebGLObject("getActiveAttrib", program))
2091 if (!m_context->getActiveAttrib(objectOrZero(program), index, info))
2094 LOG(WebGL, "Returning active attribute %d: %s", index, info.name.utf8().data());
2096 return WebGLActiveInfo::create(info.name, info.type, info.size);
2099 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec)
2102 if (isContextLostOrPending() || !validateWebGLObject("getActiveUniform", program))
2105 if (!m_context->getActiveUniform(objectOrZero(program), index, info))
2107 if (!isGLES2Compliant())
2108 if (info.size > 1 && !info.name.endsWith("[0]"))
2109 info.name.append("[0]");
2111 LOG(WebGL, "Returning active uniform %d: %s", index, info.name.utf8().data());
2113 return WebGLActiveInfo::create(info.name, info.type, info.size);
2116 bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader>>& shaderObjects, ExceptionCode& ec)
2119 shaderObjects.clear();
2120 if (isContextLostOrPending() || !validateWebGLObject("getAttachedShaders", program))
2123 const GC3Denum shaderType[] = {
2124 GraphicsContext3D::VERTEX_SHADER,
2125 GraphicsContext3D::FRAGMENT_SHADER
2127 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GC3Denum); ++i) {
2128 WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2130 shaderObjects.append(shader);
2135 GC3Dint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2137 if (isContextLostOrPending() || !validateWebGLObject("getAttribLocation", program))
2139 if (!validateLocationLength("getAttribLocation", name))
2141 if (!validateString("getAttribLocation", name))
2143 if (isPrefixReserved(name))
2145 if (!program->getLinkStatus()) {
2146 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getAttribLocation", "program not linked");
2149 return m_context->getAttribLocation(objectOrZero(program), name);
2152 WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2155 if (isContextLostOrPending())
2156 return WebGLGetInfo();
2157 if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) {
2158 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid target");
2159 return WebGLGetInfo();
2162 if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) {
2163 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2164 return WebGLGetInfo();
2168 m_context->getBufferParameteriv(target, pname, &value);
2169 if (pname == GraphicsContext3D::BUFFER_SIZE)
2170 return WebGLGetInfo(value);
2171 return WebGLGetInfo(static_cast<unsigned int>(value));
2174 PassRefPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2176 if (isContextLostOrPending())
2178 // We always need to return a new WebGLContextAttributes object to
2179 // prevent the user from mutating any cached version.
2181 // Also, we need to enforce requested values of "false" for depth
2182 // and stencil, regardless of the properties of the underlying
2183 // GraphicsContext3D.
2184 RefPtr<WebGLContextAttributes> attributes = WebGLContextAttributes::create(m_context->getContextAttributes());
2185 if (!m_attributes.depth)
2186 attributes->setDepth(false);
2187 if (!m_attributes.stencil)
2188 attributes->setStencil(false);
2189 return attributes.release();
2192 GC3Denum WebGLRenderingContextBase::getError()
2194 if (m_isPendingPolicyResolution)
2195 return GraphicsContext3D::NO_ERROR;
2196 return m_context->getError();
2199 WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec)
2202 if (isContextLostOrPending() || !validateWebGLObject("getProgramParameter", program))
2203 return WebGLGetInfo();
2207 case GraphicsContext3D::DELETE_STATUS:
2208 return WebGLGetInfo(program->isDeleted());
2209 case GraphicsContext3D::VALIDATE_STATUS:
2210 m_context->getProgramiv(objectOrZero(program), pname, &value);
2211 return WebGLGetInfo(static_cast<bool>(value));
2212 case GraphicsContext3D::LINK_STATUS:
2213 return WebGLGetInfo(program->getLinkStatus());
2214 case GraphicsContext3D::ATTACHED_SHADERS:
2215 m_context->getProgramiv(objectOrZero(program), pname, &value);
2216 return WebGLGetInfo(value);
2217 case GraphicsContext3D::ACTIVE_ATTRIBUTES:
2218 case GraphicsContext3D::ACTIVE_UNIFORMS:
2219 m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), pname, &value);
2220 return WebGLGetInfo(value);
2222 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2223 return WebGLGetInfo();
2227 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec)
2230 if (isContextLostOrPending() || !validateWebGLObject("getProgramInfoLog", program))
2232 return ensureNotNull(m_context->getProgramInfoLog(objectOrZero(program)));
2235 WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2238 if (isContextLostOrPending())
2239 return WebGLGetInfo();
2240 if (target != GraphicsContext3D::RENDERBUFFER) {
2241 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2242 return WebGLGetInfo();
2244 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2245 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2246 return WebGLGetInfo();
2249 if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL
2250 && !m_renderbufferBinding->isValid()) {
2251 ASSERT(!isDepthStencilSupported());
2254 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2255 value = m_renderbufferBinding->getWidth();
2257 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2258 value = m_renderbufferBinding->getHeight();
2260 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2261 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2262 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2263 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2266 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2269 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2272 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2273 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2275 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2276 return WebGLGetInfo();
2278 return WebGLGetInfo(value);
2283 case GraphicsContext3D::RENDERBUFFER_WIDTH:
2284 case GraphicsContext3D::RENDERBUFFER_HEIGHT:
2285 case GraphicsContext3D::RENDERBUFFER_RED_SIZE:
2286 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE:
2287 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE:
2288 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE:
2289 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE:
2290 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE:
2291 m_context->getRenderbufferParameteriv(target, pname, &value);
2292 return WebGLGetInfo(value);
2293 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT:
2294 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat());
2296 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2297 return WebGLGetInfo();
2301 WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec)
2304 if (isContextLostOrPending() || !validateWebGLObject("getShaderParameter", shader))
2305 return WebGLGetInfo();
2308 case GraphicsContext3D::DELETE_STATUS:
2309 return WebGLGetInfo(shader->isDeleted());
2310 case GraphicsContext3D::COMPILE_STATUS:
2311 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2312 return WebGLGetInfo(static_cast<bool>(value));
2313 case GraphicsContext3D::SHADER_TYPE:
2314 m_context->getShaderiv(objectOrZero(shader), pname, &value);
2315 return WebGLGetInfo(static_cast<unsigned int>(value));
2317 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2318 return WebGLGetInfo();
2322 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec)
2325 if (isContextLostOrPending() || !validateWebGLObject("getShaderInfoLog", shader))
2327 return ensureNotNull(m_context->getShaderInfoLog(objectOrZero(shader)));
2330 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, ExceptionCode& ec)
2333 if (isContextLostOrPending())
2335 switch (shaderType) {
2336 case GraphicsContext3D::VERTEX_SHADER:
2337 case GraphicsContext3D::FRAGMENT_SHADER:
2340 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2343 switch (precisionType) {
2344 case GraphicsContext3D::LOW_FLOAT:
2345 case GraphicsContext3D::MEDIUM_FLOAT:
2346 case GraphicsContext3D::HIGH_FLOAT:
2347 case GraphicsContext3D::LOW_INT:
2348 case GraphicsContext3D::MEDIUM_INT:
2349 case GraphicsContext3D::HIGH_INT:
2352 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2356 GC3Dint range[2] = {0, 0};
2357 GC3Dint precision = 0;
2358 m_context->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2359 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2362 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader, ExceptionCode& ec)
2365 if (isContextLostOrPending() || !validateWebGLObject("getShaderSource", shader))
2367 return ensureNotNull(shader->getSource());
2370 WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec)
2373 if (isContextLostOrPending())
2374 return WebGLGetInfo();
2375 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2377 return WebGLGetInfo();
2380 case GraphicsContext3D::TEXTURE_MAG_FILTER:
2381 case GraphicsContext3D::TEXTURE_MIN_FILTER:
2382 case GraphicsContext3D::TEXTURE_WRAP_S:
2383 case GraphicsContext3D::TEXTURE_WRAP_T:
2384 m_context->getTexParameteriv(target, pname, &value);
2385 return WebGLGetInfo(static_cast<unsigned int>(value));
2386 case Extensions3D::TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2387 if (m_extTextureFilterAnisotropic) {
2388 m_context->getTexParameteriv(target, pname, &value);
2389 return WebGLGetInfo(static_cast<unsigned int>(value));
2391 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2392 return WebGLGetInfo();
2394 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getTexParameter", "invalid parameter name");
2395 return WebGLGetInfo();
2399 WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec)
2402 if (isContextLostOrPending() || !validateWebGLObject("getUniform", program))
2403 return WebGLGetInfo();
2404 if (!uniformLocation || uniformLocation->program() != program) {
2405 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2406 return WebGLGetInfo();
2408 GC3Dint location = uniformLocation->location();
2412 switch (uniformLocation->type()) {
2413 case GraphicsContext3D::BOOL:
2414 baseType = GraphicsContext3D::BOOL;
2417 case GraphicsContext3D::BOOL_VEC2:
2418 baseType = GraphicsContext3D::BOOL;
2421 case GraphicsContext3D::BOOL_VEC3:
2422 baseType = GraphicsContext3D::BOOL;
2425 case GraphicsContext3D::BOOL_VEC4:
2426 baseType = GraphicsContext3D::BOOL;
2429 case GraphicsContext3D::INT:
2430 baseType = GraphicsContext3D::INT;
2433 case GraphicsContext3D::INT_VEC2:
2434 baseType = GraphicsContext3D::INT;
2437 case GraphicsContext3D::INT_VEC3:
2438 baseType = GraphicsContext3D::INT;
2441 case GraphicsContext3D::INT_VEC4:
2442 baseType = GraphicsContext3D::INT;
2445 case GraphicsContext3D::FLOAT:
2446 baseType = GraphicsContext3D::FLOAT;
2449 case GraphicsContext3D::FLOAT_VEC2:
2450 baseType = GraphicsContext3D::FLOAT;
2453 case GraphicsContext3D::FLOAT_VEC3:
2454 baseType = GraphicsContext3D::FLOAT;
2457 case GraphicsContext3D::FLOAT_VEC4:
2458 baseType = GraphicsContext3D::FLOAT;
2461 case GraphicsContext3D::FLOAT_MAT2:
2462 baseType = GraphicsContext3D::FLOAT;
2465 case GraphicsContext3D::FLOAT_MAT3:
2466 baseType = GraphicsContext3D::FLOAT;
2469 case GraphicsContext3D::FLOAT_MAT4:
2470 baseType = GraphicsContext3D::FLOAT;
2473 case GraphicsContext3D::SAMPLER_2D:
2474 case GraphicsContext3D::SAMPLER_CUBE:
2475 baseType = GraphicsContext3D::INT;
2479 // Can't handle this type
2480 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unhandled type");
2481 return WebGLGetInfo();
2484 case GraphicsContext3D::FLOAT: {
2485 GC3Dfloat value[16] = {0};
2486 if (m_isRobustnessEXTSupported)
2487 m_context->getExtensions()->getnUniformfvEXT(objectOrZero(program), location, 16 * sizeof(GC3Dfloat), value);
2489 m_context->getUniformfv(objectOrZero(program), location, value);
2491 return WebGLGetInfo(value[0]);
2492 return WebGLGetInfo(Float32Array::create(value, length));
2494 case GraphicsContext3D::INT: {
2495 GC3Dint value[4] = {0};
2496 if (m_isRobustnessEXTSupported)
2497 m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2499 m_context->getUniformiv(objectOrZero(program), location, value);
2501 return WebGLGetInfo(value[0]);
2502 return WebGLGetInfo(Int32Array::create(value, length));
2504 case GraphicsContext3D::BOOL: {
2505 GC3Dint value[4] = {0};
2506 if (m_isRobustnessEXTSupported)
2507 m_context->getExtensions()->getnUniformivEXT(objectOrZero(program), location, 4 * sizeof(GC3Dint), value);
2509 m_context->getUniformiv(objectOrZero(program), location, value);
2511 bool boolValue[16] = {0};
2512 for (unsigned j = 0; j < length; j++)
2513 boolValue[j] = static_cast<bool>(value[j]);
2514 return WebGLGetInfo(boolValue, length);
2516 return WebGLGetInfo(static_cast<bool>(value[0]));
2522 // If we get here, something went wrong in our unfortunately complex logic above
2523 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getUniform", "unknown error");
2524 return WebGLGetInfo();
2527 PassRefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec)
2530 if (isContextLostOrPending() || !validateWebGLObject("getUniformLocation", program))
2532 if (!validateLocationLength("getUniformLocation", name))
2534 if (!validateString("getUniformLocation", name))
2536 if (isPrefixReserved(name))
2538 if (!program->getLinkStatus()) {
2539 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "getUniformLocation", "program not linked");
2542 GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name);
2543 if (uniformLocation == -1)
2546 GC3Dint activeUniforms = 0;
2547 m_context->getNonBuiltInActiveSymbolCount(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms);
2548 for (GC3Dint i = 0; i < activeUniforms; i++) {
2550 if (!m_context->getActiveUniform(objectOrZero(program), i, info))
2552 // Strip "[0]" from the name if it's an array.
2553 if (info.name.endsWith("[0]"))
2554 info.name = info.name.left(info.name.length() - 3);
2555 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2556 for (GC3Dint index = 0; index < info.size; ++index) {
2557 String uniformName = info.name + "[" + String::number(index) + "]";
2559 if (name == uniformName || name == info.name)
2560 return WebGLUniformLocation::create(program, uniformLocation, info.type);
2566 WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec)
2570 if (isContextLostOrPending())
2571 return WebGLGetInfo();
2573 if (index >= m_maxVertexAttribs) {
2574 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "getVertexAttrib", "index out of range");
2575 return WebGLGetInfo();
2578 const WebGLVertexArrayObjectBase::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2580 if ((isWebGL2() || m_angleInstancedArrays) && pname == GraphicsContext3D::VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
2581 return WebGLGetInfo(state.divisor);
2584 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2585 if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer)
2586 || !state.bufferBinding
2587 || !state.bufferBinding->object())
2588 return WebGLGetInfo();
2589 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2590 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED:
2591 return WebGLGetInfo(state.enabled);
2592 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED:
2593 return WebGLGetInfo(state.normalized);
2594 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE:
2595 return WebGLGetInfo(state.size);
2596 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE:
2597 return WebGLGetInfo(state.originalStride);
2598 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE:
2599 return WebGLGetInfo(state.type);
2600 case GraphicsContext3D::CURRENT_VERTEX_ATTRIB:
2601 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2603 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
2604 return WebGLGetInfo();
2608 long long WebGLRenderingContextBase::getVertexAttribOffset(GC3Duint index, GC3Denum pname)
2610 if (isContextLostOrPending())
2612 GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname);
2613 return static_cast<long long>(result);
2616 GC3Dboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
2618 if (!buffer || isContextLostOrPending())
2621 if (!buffer->hasEverBeenBound())
2624 return m_context->isBuffer(buffer->object());
2627 bool WebGLRenderingContextBase::isContextLost() const
2629 return m_contextLost;
2632 bool WebGLRenderingContextBase::isContextLostOrPending()
2634 if (m_isPendingPolicyResolution && !m_hasRequestedPolicyResolution) {
2635 LOG(WebGL, "Context is being used. Attempt to resolve the policy.");
2636 Document& document = canvas()->document().topDocument();
2637 Page* page = document.page();
2638 if (page && !document.url().isLocalFile())
2639 page->mainFrame().loader().client().resolveWebGLPolicyForURL(document.url());
2640 // FIXME: We don't currently do anything with the result from resolution. A more
2641 // complete implementation might try to construct a real context, etc and proceed
2642 // with normal operation.
2643 // https://bugs.webkit.org/show_bug.cgi?id=129122
2644 m_hasRequestedPolicyResolution = true;
2647 return m_contextLost || m_isPendingPolicyResolution;
2650 GC3Dboolean WebGLRenderingContextBase::isEnabled(GC3Denum cap)
2652 if (isContextLostOrPending() || !validateCapability("isEnabled", cap))
2654 if (cap == GraphicsContext3D::STENCIL_TEST)
2655 return m_stencilEnabled;
2656 return m_context->isEnabled(cap);
2659 GC3Dboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
2661 if (!framebuffer || isContextLostOrPending())
2664 if (!framebuffer->hasEverBeenBound())
2667 return m_context->isFramebuffer(framebuffer->object());
2670 GC3Dboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
2672 if (!program || isContextLostOrPending())
2675 return m_context->isProgram(program->object());
2678 GC3Dboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2680 if (!renderbuffer || isContextLostOrPending())
2683 if (!renderbuffer->hasEverBeenBound())
2686 return m_context->isRenderbuffer(renderbuffer->object());
2689 GC3Dboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
2691 if (!shader || isContextLostOrPending())
2694 return m_context->isShader(shader->object());
2697 GC3Dboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
2699 if (!texture || isContextLostOrPending())
2702 if (!texture->hasEverBeenBound())
2705 return m_context->isTexture(texture->object());
2708 void WebGLRenderingContextBase::lineWidth(GC3Dfloat width)
2710 if (isContextLostOrPending())
2712 m_context->lineWidth(width);
2715 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program, ExceptionCode& ec)
2718 if (isContextLostOrPending() || !validateWebGLObject("linkProgram", program))
2720 if (!isGLES2Compliant()) {
2721 WebGLShader* vertexShader = program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER);
2722 WebGLShader* fragmentShader = program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER);
2723 if (!vertexShader || !vertexShader->isValid() || !fragmentShader || !fragmentShader->isValid() || !m_context->precisionsMatch(objectOrZero(vertexShader), objectOrZero(fragmentShader)) || !m_context->checkVaryingsPacking(objectOrZero(vertexShader), objectOrZero(fragmentShader))) {
2724 program->setLinkStatus(false);
2729 m_context->linkProgram(objectOrZero(program));
2730 program->increaseLinkCount();
2733 void WebGLRenderingContextBase::pixelStorei(GC3Denum pname, GC3Dint param)
2735 if (isContextLostOrPending())
2738 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL:
2739 m_unpackFlipY = param;
2741 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2742 m_unpackPremultiplyAlpha = param;
2744 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL:
2745 if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE)
2746 m_unpackColorspaceConversion = static_cast<GC3Denum>(param);
2748 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
2752 case GraphicsContext3D::PACK_ALIGNMENT:
2753 case GraphicsContext3D::UNPACK_ALIGNMENT:
2754 if (param == 1 || param == 2 || param == 4 || param == 8) {
2755 if (pname == GraphicsContext3D::PACK_ALIGNMENT)
2756 m_packAlignment = param;
2757 else // GraphicsContext3D::UNPACK_ALIGNMENT:
2758 m_unpackAlignment = param;
2759 m_context->pixelStorei(pname, param);
2761 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
2766 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "pixelStorei", "invalid parameter name");
2771 void WebGLRenderingContextBase::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
2773 if (isContextLostOrPending())
2775 m_context->polygonOffset(factor, units);
2778 void WebGLRenderingContextBase::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode&)
2780 if (isContextLostOrPending())
2782 // Due to WebGL's same-origin restrictions, it is not possible to
2783 // taint the origin using the WebGL API.
2784 ASSERT(canvas()->originClean());
2785 // Validate input parameters.
2787 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
2791 case GraphicsContext3D::ALPHA:
2792 case GraphicsContext3D::RGB:
2793 case GraphicsContext3D::RGBA:
2796 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid format");
2800 case GraphicsContext3D::UNSIGNED_BYTE:
2801 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5:
2802 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4:
2803 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1:
2806 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "readPixels", "invalid type");
2809 if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) {
2810 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "format not RGBA or type not UNSIGNED_BYTE");
2813 // Validate array type against pixel type.
2814 if (pixels->getType() != JSC::TypeUint8) {
2815 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not Uint8Array");
2818 const char* reason = "framebuffer incomplete";
2819 if (m_framebufferBinding && !m_framebufferBinding->onAccess(graphicsContext3D(), !isResourceSafe(), &reason)) {
2820 synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
2823 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
2824 unsigned int totalBytesRequired = 0;
2825 unsigned int padding = 0;
2826 if (!m_isRobustnessEXTSupported) {
2827 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2828 if (error != GraphicsContext3D::NO_ERROR) {
2829 synthesizeGLError(error, "readPixels", "invalid dimensions");
2832 if (pixels->byteLength() < totalBytesRequired) {
2833 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
2838 clearIfComposited();
2839 void* data = pixels->baseAddress();
2842 if (m_isRobustnessEXTSupported)
2843 m_context->getExtensions()->readnPixelsEXT(x, y, width, height, format, type, pixels->byteLength(), data);
2845 m_context->readPixels(x, y, width, height, format, type, data);
2849 if (m_isRobustnessEXTSupported) // we haven't computed padding
2850 m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
2851 // FIXME: remove this section when GL driver bug on Mac AND the GLES driver bug
2852 // on QC is fixed, i.e., when alpha is off, readPixels should
2853 // set alpha to 255 instead of 0.
2854 if (!m_framebufferBinding && !m_context->getContextAttributes().alpha) {
2855 unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
2856 for (GC3Dsizei iy = 0; iy < height; ++iy) {
2857 for (GC3Dsizei ix = 0; ix < width; ++ix) {
2867 void WebGLRenderingContextBase::releaseShaderCompiler()
2869 if (isContextLostOrPending())
2871 m_context->releaseShaderCompiler();
2874 void WebGLRenderingContextBase::sampleCoverage(GC3Dfloat value, GC3Dboolean invert)
2876 if (isContextLostOrPending())
2878 m_context->sampleCoverage(value, invert);
2881 void WebGLRenderingContextBase::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
2883 if (isContextLostOrPending())
2885 if (!validateSize("scissor", width, height))
2887 m_context->scissor(x, y, width, height);
2890 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec)
2893 if (isContextLostOrPending() || !validateWebGLObject("shaderSource", shader))
2895 String stringWithoutComments = StripComments(string).result();
2896 if (!validateString("shaderSource", stringWithoutComments))
2898 shader->setSource(string);
2899 m_context->shaderSource(objectOrZero(shader), stringWithoutComments);
2902 void WebGLRenderingContextBase::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
2904 if (isContextLostOrPending())
2906 if (!validateStencilFunc("stencilFunc", func))
2908 m_stencilFuncRef = ref;
2909 m_stencilFuncRefBack = ref;
2910 m_stencilFuncMask = mask;
2911 m_stencilFuncMaskBack = mask;
2912 m_context->stencilFunc(func, ref, mask);
2915 void WebGLRenderingContextBase::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
2917 if (isContextLostOrPending())
2919 if (!validateStencilFunc("stencilFuncSeparate", func))
2922 case GraphicsContext3D::FRONT_AND_BACK:
2923 m_stencilFuncRef = ref;
2924 m_stencilFuncRefBack = ref;
2925 m_stencilFuncMask = mask;
2926 m_stencilFuncMaskBack = mask;
2928 case GraphicsContext3D::FRONT:
2929 m_stencilFuncRef = ref;
2930 m_stencilFuncMask = mask;
2932 case GraphicsContext3D::BACK:
2933 m_stencilFuncRefBack = ref;
2934 m_stencilFuncMaskBack = mask;
2937 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilFuncSeparate", "invalid face");
2940 m_context->stencilFuncSeparate(face, func, ref, mask);
2943 void WebGLRenderingContextBase::stencilMask(GC3Duint mask)
2945 if (isContextLostOrPending())
2947 m_stencilMask = mask;
2948 m_stencilMaskBack = mask;
2949 m_context->stencilMask(mask);
2952 void WebGLRenderingContextBase::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
2954 if (isContextLostOrPending())
2957 case GraphicsContext3D::FRONT_AND_BACK:
2958 m_stencilMask = mask;
2959 m_stencilMaskBack = mask;
2961 case GraphicsContext3D::FRONT:
2962 m_stencilMask = mask;
2964 case GraphicsContext3D::BACK:
2965 m_stencilMaskBack = mask;
2968 synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "stencilMaskSeparate", "invalid face");
2971 m_context->stencilMaskSeparate(face, mask);
2974 void WebGLRenderingContextBase::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
2976 if (isContextLostOrPending())
2978 m_context->stencilOp(fail, zfail, zpass);
2981 void WebGLRenderingContextBase::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
2983 if (isContextLostOrPending())
2985 m_context->stencilOpSeparate(face, fail, zfail, zpass);
2988 void WebGLRenderingContextBase::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels, ExceptionCode& ec)
2990 // FIXME: For now we ignore any errors returned.
2992 WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
2993 ASSERT(validateTexFuncParameters("texImage2D", TexImage, target, level, internalformat, width, height, border, format, type));
2995 ASSERT(!level || !WebGLTexture::isNPOT(width, height));
2997 // Note: Chromium's OpenGL implementation clears textures and isResourceSafe() is therefore true.
2998 // For other implementations, if they are using ANGLE_depth_texture, ANGLE depth textures
2999 // can not be cleared with texImage2D and must be cleared by binding to an fbo and calling
3001 if (isResourceSafe())
3002 m_context->texImage2D(target, level, internalformat, width, height, border, format, type, nullptr);
3004 bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height,
3005 border, format, type, m_unpackAlignment);
3010 ASSERT(validateSettableTexFormat("texImage2D", internalformat));
3011 m_context->moveErrorsToSyntheticErrorList();
3012 m_context->texImage2D(target, level, internalformat, width, height,
3013 border, format, type, pixels);
3014 if (m_context->moveErrorsToSyntheticErrorList()) {
3015 // The texImage2D function failed. Tell the WebGLTexture it doesn't have the data for this level.
3016 tex->markInvalid(target, level);
3020 tex->setLevelInfo(target, level, internalformat, width, height, type);
3023 void WebGLRenderingContextBase::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Denum format, GC3Denum type, Image* image, GraphicsContext3D::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionCode& ec)
3026 Vector<uint8_t> data;
3027 GraphicsContext3D::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE);
3028 if (!imageExtractor.extractSucceeded()) {
3029 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3032 GraphicsContext3D::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3033 GraphicsContext3D::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3034 const void* imagePixelData = imageExtractor.imagePixelData();
3036 bool needConversion = true;
3037 if (type == GraphicsContext3D::UNSIGNED_BYTE && sourceDataFormat == GraphicsContext3D::DataFormatRGBA8 && format == GraphicsContext3D::RGBA && alphaOp == GraphicsContext3D::AlphaDoNothing && !flipY)
3038 needConversion = false;
3040 if (!m_context->packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3041 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "packImage error");
3046 if (m_unpackAlignment != 1)
3047 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3048 texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, format, type, needConversion ? data.data() : imagePixelData, ec);
3049 if (m_unpackAlignment != 1)
3050 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3053 bool WebGLRenderingContextBase::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, GC3Dint xoffset, GC3Dint yoffset)
3055 if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
3058 WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3062 if (functionType != TexSubImage) {
3063 if (level && WebGLTexture::isNPOT(width, height)) {
3064 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "level > 0 not power of 2");
3067 // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3068 // by checking if the ArrayBufferView is null or not.
3069 if (sourceType != SourceArrayBufferView) {
3070 if (!validateSettableTexFormat(functionName, format))
3074 if (!validateSettableTexFormat(functionName, format))
3076 if (!validateSize(functionName, xoffset, yoffset))
3078 // Before checking if it is in the range, check if overflow happens first.
3079 if (xoffset + width < 0 || yoffset + height < 0) {
3080 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "bad dimensions");
3083 if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3084 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, functionName, "dimensions out of range");
3087 if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
3088 synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, "type and format do not match texture");
3096 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3097 GC3Dsizei width, GC3Dsizei height, GC3Dint border,
3098 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec)
3100 if (isContextLostOrPending() || !validateTexFuncData("texImage2D", level, width, height, internalformat, format, type, pixels, NullAllowed)
3101 || !validateTexFunc("texImage2D", TexImage, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
3103 void* data = pixels ? pixels->baseAddress() : 0;
3104 Vector<uint8_t> tempData;
3105 bool changeUnpackAlignment = false;
3106 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3107 if (!m_context->extractTextureData(width, height, format, type,
3109 m_unpackFlipY, m_unpackPremultiplyAlpha,
3113 data = tempData.data();
3114 changeUnpackAlignment = true;
3116 if (changeUnpackAlignment)
3117 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3118 texImage2DBase(target, level, internalformat, width, height, border,
3119 format, type, data, ec);
3120 if (changeUnpackAlignment)
3121 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3124 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3125 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec)
3128 if (isContextLostOrPending() || !pixels || !validateTexFunc("texImage2D", TexImage, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
3130 Vector<uint8_t> data;
3131 bool needConversion = true;
3132 // The data from ImageData is always of format RGBA8.
3133 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3134 if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GraphicsContext3D::RGBA && type == GraphicsContext3D::UNSIGNED_BYTE)
3135 needConversion = false;
3137 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3138 synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "texImage2D", "bad image data");
3142 if (m_unpackAlignment != 1)
3143 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1);
3144 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), ec);
3145 if (m_unpackAlignment != 1)
3146 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment);
3149 PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, int deviceScaleFactor)
3151 IntSize size(width, height);
3152 size.scale(deviceScaleFactor);
3153 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3155 synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
3159 FloatRect srcRect(FloatPoint(), image->size());
3160 FloatRect destRect(FloatPoint(), size);
3161 buf->context()->drawImage(image, ColorSpaceDeviceRGB, destRect, srcRect);
3162 return buf->copyImage(ImageBuffer::fastCopyImageMode());
3165 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3166 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec)
3169 if (isContextLostOrPending() || !validateHTMLImageElement("texImage2D", image, ec))
3172 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3173 if (imageForRender->isSVGImage())
3174 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), 1);
3176 if (!imageForRender || !validateTexFunc("texImage2D", TexImage, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
3179 texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), GraphicsContext3D::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3182 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,
3183 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec)
3186 if (isContextLostOrPending() || !validateHTMLCanvasElement("texImage2D", canvas, ec) || !validateTexFunc("texImage2D", TexImage, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
3189 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3190 // If possible, copy from the canvas element directly to the texture
3191 // via the GPU, without a read-back to system memory.
3193 // FIXME: restriction of (RGB || RGBA)/UNSIGNED_BYTE should be lifted when
3194 // ImageBuffer::copyToPlatformTexture implementations are fully functional.
3195 if (GraphicsContext3D::TEXTURE_2D == target && texture && type == texture->getType(target, level)
3196 && (format == GraphicsContext3D::RGB || format == GraphicsContext3D::RGBA) && type == GraphicsContext3D::UNSIGNED_BYTE) {
3197 ImageBuffer* buffer = canvas->buffer();
3198 if (buffer && buffer->copyToPlatformTexture(*m_context.get(), texture->object(), internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3199 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3204 RefPtr<ImageData> imageData = canvas->getImageData();
3206 texImage2D(target, level, internalformat, format, type, imageData.get(), ec);
3208 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), GraphicsContext3D::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, ec);
3212 PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy, ExceptionCode&)
3214 IntSize size(video->videoWidth(), video->videoHeight());
3215 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3217 synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "texImage2D", "out of memory");
3220 FloatRect destRect(0, 0, size.width(), size.height());
3221 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3222 video->paintCurrentFrameInContext(buf->context(), destRect);
3223 return buf->copyImage(backingStoreCopy);
3226 void WebGLRenderingContextBase::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat,