2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "core/html/canvas/WebGLRenderingContextBase.h"
29 #include "RuntimeEnabledFeatures.h"
30 #include "bindings/v8/ExceptionMessages.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "core/dom/ExceptionCode.h"
33 #include "core/fetch/ImageResource.h"
34 #include "core/frame/LocalFrame.h"
35 #include "core/frame/Settings.h"
36 #include "core/html/HTMLCanvasElement.h"
37 #include "core/html/HTMLImageElement.h"
38 #include "core/html/HTMLVideoElement.h"
39 #include "core/html/ImageData.h"
40 #include "core/html/canvas/ANGLEInstancedArrays.h"
41 #include "core/html/canvas/EXTFragDepth.h"
42 #include "core/html/canvas/EXTShaderTextureLOD.h"
43 #include "core/html/canvas/EXTTextureFilterAnisotropic.h"
44 #include "core/html/canvas/OESElementIndexUint.h"
45 #include "core/html/canvas/OESStandardDerivatives.h"
46 #include "core/html/canvas/OESTextureFloat.h"
47 #include "core/html/canvas/OESTextureFloatLinear.h"
48 #include "core/html/canvas/OESTextureHalfFloat.h"
49 #include "core/html/canvas/OESTextureHalfFloatLinear.h"
50 #include "core/html/canvas/OESVertexArrayObject.h"
51 #include "core/html/canvas/WebGLActiveInfo.h"
52 #include "core/html/canvas/WebGLBuffer.h"
53 #include "core/html/canvas/WebGLCompressedTextureATC.h"
54 #include "core/html/canvas/WebGLCompressedTextureETC1.h"
55 #include "core/html/canvas/WebGLCompressedTexturePVRTC.h"
56 #include "core/html/canvas/WebGLCompressedTextureS3TC.h"
57 #include "core/html/canvas/WebGLContextAttributes.h"
58 #include "core/html/canvas/WebGLContextEvent.h"
59 #include "core/html/canvas/WebGLContextGroup.h"
60 #include "core/html/canvas/WebGLDebugRendererInfo.h"
61 #include "core/html/canvas/WebGLDebugShaders.h"
62 #include "core/html/canvas/WebGLDepthTexture.h"
63 #include "core/html/canvas/WebGLDrawBuffers.h"
64 #include "core/html/canvas/WebGLFramebuffer.h"
65 #include "core/html/canvas/WebGLLoseContext.h"
66 #include "core/html/canvas/WebGLProgram.h"
67 #include "core/html/canvas/WebGLRenderbuffer.h"
68 #include "core/html/canvas/WebGLShader.h"
69 #include "core/html/canvas/WebGLShaderPrecisionFormat.h"
70 #include "core/html/canvas/WebGLTexture.h"
71 #include "core/html/canvas/WebGLUniformLocation.h"
72 #include "core/inspector/InspectorInstrumentation.h"
73 #include "core/loader/FrameLoader.h"
74 #include "core/loader/FrameLoaderClient.h"
75 #include "core/rendering/RenderBox.h"
76 #include "platform/CheckedInt.h"
77 #include "platform/NotImplemented.h"
78 #include "platform/geometry/IntSize.h"
79 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
80 #include "platform/graphics/gpu/DrawingBuffer.h"
81 #include "public/platform/Platform.h"
83 #include "wtf/PassOwnPtr.h"
84 #include "wtf/Uint32Array.h"
85 #include "wtf/text/StringBuilder.h"
89 const double secondsBetweenRestoreAttempts = 1.0;
90 const int maxGLErrorsAllowedToConsole = 256;
91 const unsigned maxGLActiveContexts = 16;
93 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::activeContexts()
95 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, activeContexts, ());
96 return activeContexts;
99 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::forciblyEvictedContexts()
101 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, forciblyEvictedContexts, ());
102 return forciblyEvictedContexts;
105 void WebGLRenderingContextBase::forciblyLoseOldestContext(const String& reason)
107 size_t candidateID = oldestContextIndex();
108 if (candidateID >= activeContexts().size())
111 WebGLRenderingContextBase* candidate = activeContexts()[candidateID];
113 activeContexts().remove(candidateID);
115 candidate->printWarningToConsole(reason);
116 InspectorInstrumentation::didFireWebGLWarning(candidate->canvas());
118 // This will call deactivateContext once the context has actually been lost.
119 candidate->forceLostContext(WebGLRenderingContextBase::SyntheticLostContext);
122 size_t WebGLRenderingContextBase::oldestContextIndex()
124 if (!activeContexts().size())
125 return maxGLActiveContexts;
127 WebGLRenderingContextBase* candidate = activeContexts().first();
128 blink::WebGraphicsContext3D* candidateWGC3D = candidate->isContextLost() ? 0 : candidate->webContext();
129 size_t candidateID = 0;
130 for (size_t ii = 1; ii < activeContexts().size(); ++ii) {
131 WebGLRenderingContextBase* context = activeContexts()[ii];
132 blink::WebGraphicsContext3D* contextWGC3D = context->isContextLost() ? 0 : context->webContext();
133 if (contextWGC3D && candidateWGC3D && contextWGC3D->lastFlushID() < candidateWGC3D->lastFlushID()) {
142 IntSize WebGLRenderingContextBase::oldestContextSize()
146 size_t candidateID = oldestContextIndex();
147 if (candidateID < activeContexts().size()) {
148 WebGLRenderingContextBase* candidate = activeContexts()[candidateID];
149 size.setWidth(candidate->drawingBufferWidth());
150 size.setHeight(candidate->drawingBufferHeight());
156 void WebGLRenderingContextBase::activateContext(WebGLRenderingContextBase* context)
158 unsigned removedContexts = 0;
159 while (activeContexts().size() >= maxGLActiveContexts && removedContexts < maxGLActiveContexts) {
160 forciblyLoseOldestContext("WARNING: Too many active WebGL contexts. Oldest context will be lost.");
164 if (!activeContexts().contains(context))
165 activeContexts().append(context);
168 void WebGLRenderingContextBase::deactivateContext(WebGLRenderingContextBase* context, bool addToEvictedList)
170 size_t position = activeContexts().find(context);
171 if (position != WTF::kNotFound)
172 activeContexts().remove(position);
174 if (addToEvictedList && !forciblyEvictedContexts().contains(context))
175 forciblyEvictedContexts().append(context);
178 void WebGLRenderingContextBase::willDestroyContext(WebGLRenderingContextBase* context)
180 size_t position = forciblyEvictedContexts().find(context);
181 if (position != WTF::kNotFound)
182 forciblyEvictedContexts().remove(position);
184 deactivateContext(context, false);
186 // Try to re-enable the oldest inactive contexts.
187 while(activeContexts().size() < maxGLActiveContexts && forciblyEvictedContexts().size()) {
188 WebGLRenderingContextBase* evictedContext = forciblyEvictedContexts().first();
189 if (!evictedContext->m_restoreAllowed) {
190 forciblyEvictedContexts().remove(0);
194 IntSize desiredSize = DrawingBuffer::adjustSize(evictedContext->clampedCanvasSize(), IntSize(), evictedContext->m_maxTextureSize);
196 // If there's room in the pixel budget for this context, restore it.
197 if (!desiredSize.isEmpty()) {
198 forciblyEvictedContexts().remove(0);
199 evictedContext->forceRestoreContext();
200 activeContexts().append(evictedContext);
206 class WebGLRenderingContextEvictionManager : public ContextEvictionManager {
208 void forciblyLoseOldestContext(const String& reason) {
209 WebGLRenderingContextBase::forciblyLoseOldestContext(reason);
211 IntSize oldestContextSize() {
212 return WebGLRenderingContextBase::oldestContextSize();
218 class ScopedDrawingBufferBinder {
220 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding)
221 : m_drawingBuffer(drawingBuffer)
222 , m_framebufferBinding(framebufferBinding)
224 // Commit DrawingBuffer if needed (e.g., for multisampling)
225 if (!m_framebufferBinding && m_drawingBuffer)
226 m_drawingBuffer->commit();
229 ~ScopedDrawingBufferBinder()
231 // Restore DrawingBuffer if needed
232 if (!m_framebufferBinding && m_drawingBuffer)
233 m_drawingBuffer->bind();
237 DrawingBuffer* m_drawingBuffer;
238 WebGLFramebuffer* m_framebufferBinding;
241 Platform3DObject objectOrZero(WebGLObject* object)
243 return object ? object->object() : 0;
246 GLint clamp(GLint value, GLint min, GLint max)
255 // Return true if a character belongs to the ASCII subset as defined in
256 // GLSL ES 1.0 spec section 3.1.
257 bool validateCharacter(unsigned char c)
259 // Printing characters are valid except " $ ` @ \ ' DEL.
260 if (c >= 32 && c <= 126
261 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
263 // Horizontal tab, line feed, vertical tab, form feed, carriage return
265 if (c >= 9 && c <= 13)
270 bool isPrefixReserved(const String& name)
272 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_"))
277 // Strips comments from shader text. This allows non-ASCII characters
278 // to be used in comments without potentially breaking OpenGL
279 // implementations not expecting characters outside the GLSL ES set.
280 class StripComments {
282 StripComments(const String& str)
283 : m_parseState(BeginningOfLine)
284 , m_sourceString(str)
285 , m_length(str.length())
293 return m_builder.toString();
297 bool hasMoreCharacters() const
299 return (m_position < m_length);
304 while (hasMoreCharacters()) {
306 // process() might advance the position.
307 if (hasMoreCharacters())
314 bool peek(UChar& character) const
316 if (m_position + 1 >= m_length)
318 character = m_sourceString[m_position + 1];
324 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length);
325 return m_sourceString[m_position];
333 static bool isNewline(UChar character)
335 // Don't attempt to canonicalize newline related characters.
336 return (character == '\n' || character == '\r');
339 void emit(UChar character)
341 m_builder.append(character);
345 // Have not seen an ASCII non-whitespace character yet on
346 // this line. Possible that we might see a preprocessor
350 // Have seen at least one ASCII non-whitespace character
354 // Handling a preprocessor directive. Passes through all
355 // characters up to the end of the line. Disables comment
357 InPreprocessorDirective,
359 // Handling a single-line comment. The comment text is
360 // replaced with a single space.
363 // Handling a multi-line comment. Newlines are passed
364 // through to preserve line numbers.
368 ParseState m_parseState;
369 String m_sourceString;
372 StringBuilder m_builder;
375 void StripComments::process(UChar c)
378 // No matter what state we are in, pass through newlines
379 // so we preserve line numbers.
382 if (m_parseState != InMultiLineComment)
383 m_parseState = BeginningOfLine;
389 switch (m_parseState) {
390 case BeginningOfLine:
391 if (WTF::isASCIISpace(c)) {
397 m_parseState = InPreprocessorDirective;
402 // Transition to normal state and re-handle character.
403 m_parseState = MiddleOfLine;
408 if (c == '/' && peek(temp)) {
410 m_parseState = InSingleLineComment;
417 m_parseState = InMultiLineComment;
418 // Emit the comment start in case the user has
419 // an unclosed comment and we want to later
431 case InPreprocessorDirective:
432 // No matter what the character is, just pass it
433 // through. Do not parse comments in this state. This
434 // might not be the right thing to do long term, but it
435 // should handle the #error preprocessor directive.
439 case InSingleLineComment:
440 // The newline code at the top of this function takes care
441 // of resetting our state when we get out of the
442 // single-line comment. Swallow all other characters.
445 case InMultiLineComment:
446 if (c == '*' && peek(temp) && temp == '/') {
449 m_parseState = MiddleOfLine;
454 // Swallow all other characters. Unclear whether we may
455 // want or need to just emit a space per character to try
456 // to preserve column numbers for debugging purposes.
460 } // namespace anonymous
462 class ScopedTexture2DRestorer {
464 ScopedTexture2DRestorer(WebGLRenderingContextBase* context)
469 ~ScopedTexture2DRestorer()
471 m_context->restoreCurrentTexture2D();
475 WebGLRenderingContextBase* m_context;
478 class WebGLRenderingContextLostCallback : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback {
479 WTF_MAKE_FAST_ALLOCATED;
481 explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
482 virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContextBase::RealLostContext); }
483 virtual ~WebGLRenderingContextLostCallback() {}
485 WebGLRenderingContextBase* m_context;
488 class WebGLRenderingContextErrorMessageCallback : public blink::WebGraphicsContext3D::WebGraphicsErrorMessageCallback {
489 WTF_MAKE_FAST_ALLOCATED;
491 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { }
492 virtual void onErrorMessage(const blink::WebString& message, blink::WGC3Dint)
494 if (m_context->m_synthesizedErrorsToConsole)
495 m_context->printGLErrorToConsole(message);
496 InspectorInstrumentation::didFireWebGLErrorOrWarning(m_context->canvas(), message);
498 virtual ~WebGLRenderingContextErrorMessageCallback() { }
500 WebGLRenderingContextBase* m_context;
503 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassOwnPtr<blink::WebGraphicsContext3D> context, WebGLContextAttributes* requestedAttributes)
504 : CanvasRenderingContext(passedCanvas)
505 , ActiveDOMObject(&passedCanvas->document())
506 , m_drawingBuffer(nullptr)
507 , m_dispatchContextLostEventTimer(this, &WebGLRenderingContextBase::dispatchContextLostEvent)
508 , m_restoreAllowed(false)
509 , m_restoreTimer(this, &WebGLRenderingContextBase::maybeRestoreContext)
510 , m_generatedImageCache(4)
511 , m_contextLost(false)
512 , m_contextLostMode(SyntheticLostContext)
513 , m_requestedAttributes(requestedAttributes->clone())
514 , m_synthesizedErrorsToConsole(true)
515 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole)
516 , m_multisamplingAllowed(false)
517 , m_multisamplingObserverRegistered(false)
518 , m_onePlusMaxEnabledAttribIndex(0)
519 , m_onePlusMaxNonDefaultTextureUnit(0)
523 m_contextGroup = WebGLContextGroup::create();
524 m_contextGroup->addContext(this);
526 m_maxViewportDims[0] = m_maxViewportDims[1] = 0;
527 context->getIntegerv(GL_MAX_VIEWPORT_DIMS, m_maxViewportDims);
529 RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager());
531 // Create the DrawingBuffer and initialize the platform layer.
532 DrawingBuffer::PreserveDrawingBuffer preserve = requestedAttributes->preserveDrawingBuffer() ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
533 m_drawingBuffer = DrawingBuffer::create(context, clampedCanvasSize(), preserve, contextEvictionManager.release());
534 if (!m_drawingBuffer)
537 m_drawingBuffer->bind();
539 initializeNewContext();
542 void WebGLRenderingContextBase::initializeNewContext()
544 ASSERT(!isContextLost());
545 m_needsUpdate = true;
546 m_markedCanvasDirty = false;
547 m_activeTextureUnit = 0;
549 m_unpackAlignment = 4;
550 m_unpackFlipY = false;
551 m_unpackPremultiplyAlpha = false;
552 m_unpackColorspaceConversion = GC3D_BROWSER_DEFAULT_WEBGL;
553 m_boundArrayBuffer = nullptr;
554 m_currentProgram = nullptr;
555 m_framebufferBinding = nullptr;
556 m_renderbufferBinding = nullptr;
558 m_stencilEnabled = false;
559 m_stencilMask = 0xFFFFFFFF;
560 m_stencilMaskBack = 0xFFFFFFFF;
561 m_stencilFuncRef = 0;
562 m_stencilFuncRefBack = 0;
563 m_stencilFuncMask = 0xFFFFFFFF;
564 m_stencilFuncMaskBack = 0xFFFFFFFF;
565 m_layerCleared = false;
566 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole;
568 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0;
569 m_scissorEnabled = false;
572 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true;
574 GLint numCombinedTextureImageUnits = 0;
575 webContext()->getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits);
576 m_textureUnits.clear();
577 m_textureUnits.resize(numCombinedTextureImageUnits);
579 GLint numVertexAttribs = 0;
580 webContext()->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &numVertexAttribs);
581 m_maxVertexAttribs = numVertexAttribs;
583 m_maxTextureSize = 0;
584 webContext()->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
585 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize);
586 m_maxCubeMapTextureSize = 0;
587 webContext()->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
588 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize);
589 m_maxRenderbufferSize = 0;
590 webContext()->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
592 // These two values from EXT_draw_buffers are lazily queried.
593 m_maxDrawBuffers = 0;
594 m_maxColorAttachments = 0;
596 m_backDrawBuffer = GL_BACK;
598 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault);
599 addContextObject(m_defaultVertexArrayObject.get());
600 m_boundVertexArrayObject = m_defaultVertexArrayObject;
602 m_vertexAttribValue.resize(m_maxVertexAttribs);
604 createFallbackBlackTextures1x1();
606 webContext()->viewport(0, 0, drawingBufferWidth(), drawingBufferHeight());
607 webContext()->scissor(0, 0, drawingBufferWidth(), drawingBufferHeight());
609 m_contextLostCallbackAdapter = adoptPtr(new WebGLRenderingContextLostCallback(this));
610 m_errorMessageCallbackAdapter = adoptPtr(new WebGLRenderingContextErrorMessageCallback(this));
612 webContext()->setContextLostCallback(m_contextLostCallbackAdapter.get());
613 webContext()->setErrorMessageCallback(m_errorMessageCallbackAdapter.get());
615 // This ensures that the context has a valid "lastFlushID" and won't be mistakenly identified as the "least recently used" context.
616 webContext()->flush();
618 for (int i = 0; i < WebGLExtensionNameCount; ++i)
619 m_extensionEnabled[i] = false;
621 activateContext(this);
624 void WebGLRenderingContextBase::setupFlags()
626 ASSERT(m_drawingBuffer);
627 if (Page* p = canvas()->document().page()) {
628 m_synthesizedErrorsToConsole = p->settings().webGLErrorsToConsoleEnabled();
630 if (!m_multisamplingObserverRegistered && m_requestedAttributes->antialias()) {
631 m_multisamplingAllowed = m_drawingBuffer->multisample();
632 p->addMultisamplingChangedObserver(this);
633 m_multisamplingObserverRegistered = true;
637 m_isGLES2NPOTStrict = !extensionsUtil()->isExtensionEnabled("GL_OES_texture_npot");
638 m_isDepthStencilSupported = extensionsUtil()->isExtensionEnabled("GL_OES_packed_depth_stencil");
641 bool WebGLRenderingContextBase::allowPrivilegedExtensions() const
643 if (Page* p = canvas()->document().page())
644 return p->settings().privilegedWebGLExtensionsEnabled();
648 bool WebGLRenderingContextBase::allowWebGLDebugRendererInfo() const
653 void WebGLRenderingContextBase::addCompressedTextureFormat(GLenum format)
655 if (!m_compressedTextureFormats.contains(format))
656 m_compressedTextureFormats.append(format);
659 void WebGLRenderingContextBase::removeAllCompressedTextureFormats()
661 m_compressedTextureFormats.clear();
664 // Helper function for V8 bindings to identify what version of WebGL a CanvasRenderingContext supports.
665 unsigned WebGLRenderingContextBase::getWebGLVersion(const CanvasRenderingContext* context)
667 if (!context->is3d())
669 return static_cast<const WebGLRenderingContextBase*>(context)->version();
672 WebGLRenderingContextBase::~WebGLRenderingContextBase()
674 // Remove all references to WebGLObjects so if they are the last reference
675 // they will be freed before the last context is removed from the context group.
676 m_boundArrayBuffer = nullptr;
677 m_defaultVertexArrayObject = nullptr;
678 m_boundVertexArrayObject = nullptr;
679 m_vertexAttrib0Buffer = nullptr;
680 m_currentProgram = nullptr;
681 m_framebufferBinding = nullptr;
682 m_renderbufferBinding = nullptr;
684 for (size_t i = 0; i < m_textureUnits.size(); ++i) {
685 m_textureUnits[i].m_texture2DBinding = nullptr;
686 m_textureUnits[i].m_textureCubeMapBinding = nullptr;
689 m_blackTexture2D = nullptr;
690 m_blackTextureCubeMap = nullptr;
692 detachAndRemoveAllObjects();
694 // release all extensions
695 for (size_t i = 0; i < m_extensions.size(); ++i)
696 delete m_extensions[i];
698 // Context must be removed from the group prior to the destruction of the
699 // WebGraphicsContext3D, otherwise shared objects may not be properly deleted.
700 m_contextGroup->removeContext(this);
705 if (m_multisamplingObserverRegistered) {
706 Page* page = canvas()->document().page();
708 page->removeMultisamplingChangedObserver(this);
712 willDestroyContext(this);
715 void WebGLRenderingContextBase::destroyContext()
717 m_contextLost = true;
719 if (!m_drawingBuffer)
722 m_extensionsUtil.clear();
724 webContext()->setContextLostCallback(0);
725 webContext()->setErrorMessageCallback(0);
727 ASSERT(m_drawingBuffer);
728 m_drawingBuffer->beginDestruction();
729 m_drawingBuffer.clear();
732 void WebGLRenderingContextBase::markContextChanged(ContentChangeType changeType)
734 if (m_framebufferBinding || isContextLost())
737 m_drawingBuffer->markContentsChanged();
739 m_layerCleared = false;
740 RenderBox* renderBox = canvas()->renderBox();
741 if (renderBox && renderBox->hasAcceleratedCompositing()) {
742 m_markedCanvasDirty = true;
743 canvas()->clearCopiedImage();
744 renderBox->contentChanged(changeType);
746 if (!m_markedCanvasDirty) {
747 m_markedCanvasDirty = true;
748 canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize()));
753 bool WebGLRenderingContextBase::clearIfComposited(GLbitfield mask)
758 if (!m_drawingBuffer->layerComposited() || m_layerCleared
759 || m_requestedAttributes->preserveDrawingBuffer() || (mask && m_framebufferBinding))
762 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes();
764 // Determine if it's possible to combine the clear the user asked for and this clear.
765 bool combinedClear = mask && !m_scissorEnabled;
767 webContext()->disable(GL_SCISSOR_TEST);
768 if (combinedClear && (mask & GL_COLOR_BUFFER_BIT)) {
769 webContext()->clearColor(m_colorMask[0] ? m_clearColor[0] : 0,
770 m_colorMask[1] ? m_clearColor[1] : 0,
771 m_colorMask[2] ? m_clearColor[2] : 0,
772 m_colorMask[3] ? m_clearColor[3] : 0);
774 webContext()->clearColor(0, 0, 0, 0);
776 webContext()->colorMask(true, true, true, true);
777 GLbitfield clearMask = GL_COLOR_BUFFER_BIT;
778 if (contextAttributes->depth()) {
779 if (!combinedClear || !m_depthMask || !(mask & GL_DEPTH_BUFFER_BIT))
780 webContext()->clearDepth(1.0f);
781 clearMask |= GL_DEPTH_BUFFER_BIT;
782 webContext()->depthMask(true);
784 if (contextAttributes->stencil()) {
785 if (combinedClear && (mask & GL_STENCIL_BUFFER_BIT))
786 webContext()->clearStencil(m_clearStencil & m_stencilMask);
788 webContext()->clearStencil(0);
789 clearMask |= GL_STENCIL_BUFFER_BIT;
790 webContext()->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
793 m_drawingBuffer->clearFramebuffers(clearMask);
795 restoreStateAfterClear();
796 if (m_framebufferBinding)
797 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
798 m_layerCleared = true;
800 return combinedClear;
803 void WebGLRenderingContextBase::restoreStateAfterClear()
808 // Restore the state that the context set.
809 if (m_scissorEnabled)
810 webContext()->enable(GL_SCISSOR_TEST);
811 webContext()->clearColor(m_clearColor[0], m_clearColor[1],
812 m_clearColor[2], m_clearColor[3]);
813 webContext()->colorMask(m_colorMask[0], m_colorMask[1],
814 m_colorMask[2], m_colorMask[3]);
815 webContext()->clearDepth(m_clearDepth);
816 webContext()->clearStencil(m_clearStencil);
817 webContext()->stencilMaskSeparate(GL_FRONT, m_stencilMask);
818 webContext()->depthMask(m_depthMask);
821 void WebGLRenderingContextBase::markLayerComposited()
823 if (!isContextLost())
824 m_drawingBuffer->markLayerComposited();
827 void WebGLRenderingContextBase::paintRenderingResultsToCanvas()
829 if (isContextLost()) {
830 canvas()->clearPresentationCopy();
834 if (canvas()->document().printing())
835 canvas()->clearPresentationCopy();
837 // Until the canvas is written to by the application, the clear that
838 // happened after it was composited should be ignored by the compositor.
839 if (m_drawingBuffer->layerComposited() && !m_requestedAttributes->preserveDrawingBuffer()) {
840 m_drawingBuffer->paintCompositedResultsToCanvas(canvas()->buffer());
842 canvas()->makePresentationCopy();
844 canvas()->clearPresentationCopy();
847 if (!m_markedCanvasDirty && !m_layerCleared)
850 canvas()->clearCopiedImage();
851 m_markedCanvasDirty = false;
853 ScopedTexture2DRestorer restorer(this);
855 m_drawingBuffer->commit();
856 if (!(canvas()->buffer())->copyRenderingResultsFromDrawingBuffer(m_drawingBuffer.get())) {
857 canvas()->ensureUnacceleratedImageBuffer();
858 if (canvas()->hasImageBuffer())
859 m_drawingBuffer->paintRenderingResultsToCanvas(canvas()->buffer());
862 if (m_framebufferBinding)
863 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
865 m_drawingBuffer->bind();
868 PassRefPtrWillBeRawPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData()
874 m_drawingBuffer->commit();
876 RefPtr<Uint8ClampedArray> imageDataPixels = m_drawingBuffer->paintRenderingResultsToImageData(width, height);
877 if (!imageDataPixels)
880 if (m_framebufferBinding)
881 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
883 m_drawingBuffer->bind();
885 return ImageData::create(IntSize(width, height), imageDataPixels);
888 void WebGLRenderingContextBase::reshape(int width, int height)
893 // This is an approximation because at WebGLRenderingContextBase level we don't
894 // know if the underlying FBO uses textures or renderbuffers.
895 GLint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize);
896 // Limit drawing buffer size to 4k to avoid memory exhaustion.
897 const int sizeUpperLimit = 4096;
898 maxSize = std::min(maxSize, sizeUpperLimit);
899 GLint maxWidth = std::min(maxSize, m_maxViewportDims[0]);
900 GLint maxHeight = std::min(maxSize, m_maxViewportDims[1]);
901 width = clamp(width, 1, maxWidth);
902 height = clamp(height, 1, maxHeight);
905 RenderBox* renderBox = canvas()->renderBox();
906 if (renderBox && renderBox->hasAcceleratedCompositing())
907 renderBox->contentChanged(CanvasChanged);
908 m_needsUpdate = false;
911 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off
912 // clear (and this matches what reshape will do).
913 m_drawingBuffer->reset(IntSize(width, height));
914 restoreStateAfterClear();
916 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()));
917 webContext()->bindRenderbuffer(GL_RENDERBUFFER, objectOrZero(m_renderbufferBinding.get()));
918 if (m_framebufferBinding)
919 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get()));
922 int WebGLRenderingContextBase::drawingBufferWidth() const
924 return isContextLost() ? 0 : m_drawingBuffer->size().width();
927 int WebGLRenderingContextBase::drawingBufferHeight() const
929 return isContextLost() ? 0 : m_drawingBuffer->size().height();
932 unsigned WebGLRenderingContextBase::sizeInBytes(GLenum type)
936 return sizeof(GLbyte);
937 case GL_UNSIGNED_BYTE:
938 return sizeof(GLubyte);
940 return sizeof(GLshort);
941 case GL_UNSIGNED_SHORT:
942 return sizeof(GLushort);
944 return sizeof(GLint);
945 case GL_UNSIGNED_INT:
946 return sizeof(GLuint);
948 return sizeof(GLfloat);
950 ASSERT_NOT_REACHED();
954 void WebGLRenderingContextBase::activeTexture(GLenum texture)
958 if (texture - GL_TEXTURE0 >= m_textureUnits.size()) {
959 synthesizeGLError(GL_INVALID_ENUM, "activeTexture", "texture unit out of range");
962 m_activeTextureUnit = texture - GL_TEXTURE0;
963 webContext()->activeTexture(texture);
965 m_drawingBuffer->setActiveTextureUnit(texture);
969 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader)
971 if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader))
973 if (!program->attachShader(shader)) {
974 synthesizeGLError(GL_INVALID_OPERATION, "attachShader", "shader attachment already has shader");
977 webContext()->attachShader(objectOrZero(program), objectOrZero(shader));
978 shader->onAttached();
981 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name)
983 if (isContextLost() || !validateWebGLObject("bindAttribLocation", program))
985 if (!validateLocationLength("bindAttribLocation", name))
987 if (!validateString("bindAttribLocation", name))
989 if (isPrefixReserved(name)) {
990 synthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation", "reserved prefix");
993 if (index >= m_maxVertexAttribs) {
994 synthesizeGLError(GL_INVALID_VALUE, "bindAttribLocation", "index out of range");
997 webContext()->bindAttribLocation(objectOrZero(program), index, name.utf8().data());
1000 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted)
1003 if (isContextLost())
1006 if (!object->validate(contextGroup(), this)) {
1007 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object not from this context");
1010 deleted = !object->object();
1015 void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer)
1018 if (!checkObjectToBeBound("bindBuffer", buffer, deleted))
1022 if (buffer && buffer->getTarget() && buffer->getTarget() != target) {
1023 synthesizeGLError(GL_INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets");
1026 if (target == GL_ARRAY_BUFFER)
1027 m_boundArrayBuffer = buffer;
1028 else if (target == GL_ELEMENT_ARRAY_BUFFER)
1029 m_boundVertexArrayObject->setElementArrayBuffer(buffer);
1031 synthesizeGLError(GL_INVALID_ENUM, "bindBuffer", "invalid target");
1035 webContext()->bindBuffer(target, objectOrZero(buffer));
1037 buffer->setTarget(target);
1040 void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer)
1043 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted))
1047 if (target != GL_FRAMEBUFFER) {
1048 synthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target");
1051 m_framebufferBinding = buffer;
1052 m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get()));
1053 if (!m_framebufferBinding) {
1054 // Instead of binding fb 0, bind the drawing buffer.
1055 m_drawingBuffer->bind();
1057 webContext()->bindFramebuffer(target, objectOrZero(buffer));
1060 buffer->setHasEverBeenBound();
1064 void WebGLRenderingContextBase::bindRenderbuffer(GLenum target, WebGLRenderbuffer* renderBuffer)
1067 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted))
1071 if (target != GL_RENDERBUFFER) {
1072 synthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target");
1075 m_renderbufferBinding = renderBuffer;
1076 webContext()->bindRenderbuffer(target, objectOrZero(renderBuffer));
1078 renderBuffer->setHasEverBeenBound();
1081 void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture)
1084 if (!checkObjectToBeBound("bindTexture", texture, deleted))
1088 if (texture && texture->getTarget() && texture->getTarget() != target) {
1089 synthesizeGLError(GL_INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets");
1093 if (target == GL_TEXTURE_2D) {
1094 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture;
1095 maxLevel = m_maxTextureLevel;
1097 if (!m_activeTextureUnit)
1098 m_drawingBuffer->setTexture2DBinding(objectOrZero(texture));
1100 } else if (target == GL_TEXTURE_CUBE_MAP) {
1101 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture;
1102 maxLevel = m_maxCubeMapTextureLevel;
1104 synthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target");
1108 webContext()->bindTexture(target, objectOrZero(texture));
1110 texture->setTarget(target, maxLevel);
1111 m_onePlusMaxNonDefaultTextureUnit = max(m_activeTextureUnit + 1, m_onePlusMaxNonDefaultTextureUnit);
1113 // If the disabled index is the current maximum, trace backwards to find the new max enabled texture index
1114 if (m_onePlusMaxNonDefaultTextureUnit == m_activeTextureUnit + 1) {
1115 findNewMaxNonDefaultTextureUnit();
1119 // Note: previously we used to automatically set the TEXTURE_WRAP_R
1120 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
1121 // ES 2.0 doesn't expose this flag (a bug in the specification) and
1122 // otherwise the application has no control over the seams in this
1123 // dimension. However, it appears that supporting this properly on all
1124 // platforms is fairly involved (will require a HashMap from texture ID
1125 // in all ports), and we have not had any complaints, so the logic has
1130 void WebGLRenderingContextBase::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
1132 if (isContextLost())
1134 webContext()->blendColor(red, green, blue, alpha);
1137 void WebGLRenderingContextBase::blendEquation(GLenum mode)
1139 if (isContextLost() || !validateBlendEquation("blendEquation", mode))
1141 webContext()->blendEquation(mode);
1144 void WebGLRenderingContextBase::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
1146 if (isContextLost() || !validateBlendEquation("blendEquationSeparate", modeRGB) || !validateBlendEquation("blendEquationSeparate", modeAlpha))
1148 webContext()->blendEquationSeparate(modeRGB, modeAlpha);
1152 void WebGLRenderingContextBase::blendFunc(GLenum sfactor, GLenum dfactor)
1154 if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor))
1156 webContext()->blendFunc(sfactor, dfactor);
1159 void WebGLRenderingContextBase::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
1161 // Note: Alpha does not have the same restrictions as RGB.
1162 if (isContextLost() || !validateBlendFuncFactors("blendFuncSeparate", srcRGB, dstRGB))
1164 webContext()->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
1167 void WebGLRenderingContextBase::bufferDataImpl(GLenum target, long long size, const void* data, GLenum usage)
1169 WebGLBuffer* buffer = validateBufferDataTarget("bufferData", target);
1174 case GL_STREAM_DRAW:
1175 case GL_STATIC_DRAW:
1176 case GL_DYNAMIC_DRAW:
1179 synthesizeGLError(GL_INVALID_ENUM, "bufferData", "invalid usage");
1183 if (!validateValueFitNonNegInt32("bufferData", "size", size))
1186 webContext()->bufferData(target, static_cast<GLsizeiptr>(size), data, usage);
1189 void WebGLRenderingContextBase::bufferData(GLenum target, long long size, GLenum usage)
1191 if (isContextLost())
1194 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "size == 0");
1197 bufferDataImpl(target, size, 0, usage);
1200 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBuffer* data, GLenum usage)
1202 if (isContextLost())
1205 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
1208 bufferDataImpl(target, data->byteLength(), data->data(), usage);
1211 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBufferView* data, GLenum usage)
1213 if (isContextLost())
1216 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
1219 bufferDataImpl(target, data->byteLength(), data->baseAddress(), usage);
1222 void WebGLRenderingContextBase::bufferSubDataImpl(GLenum target, long long offset, GLsizeiptr size, const void* data)
1224 WebGLBuffer* buffer = validateBufferDataTarget("bufferSubData", target);
1227 if (!validateValueFitNonNegInt32("bufferSubData", "offset", offset))
1232 webContext()->bufferSubData(target, static_cast<GLintptr>(offset), size, data);
1235 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBuffer* data)
1237 if (isContextLost())
1241 bufferSubDataImpl(target, offset, data->byteLength(), data->data());
1244 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBufferView* data)
1246 if (isContextLost())
1250 bufferSubDataImpl(target, offset, data->byteLength(), data->baseAddress());
1253 GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target)
1255 if (isContextLost())
1256 return GL_FRAMEBUFFER_UNSUPPORTED;
1257 if (target != GL_FRAMEBUFFER) {
1258 synthesizeGLError(GL_INVALID_ENUM, "checkFramebufferStatus", "invalid target");
1261 if (!m_framebufferBinding || !m_framebufferBinding->object())
1262 return GL_FRAMEBUFFER_COMPLETE;
1263 const char* reason = "framebuffer incomplete";
1264 GLenum result = m_framebufferBinding->checkStatus(&reason);
1265 if (result != GL_FRAMEBUFFER_COMPLETE) {
1266 emitGLWarning("checkFramebufferStatus", reason);
1269 result = webContext()->checkFramebufferStatus(target);
1273 void WebGLRenderingContextBase::clear(GLbitfield mask)
1275 if (isContextLost())
1277 if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
1278 synthesizeGLError(GL_INVALID_VALUE, "clear", "invalid mask");
1281 const char* reason = "framebuffer incomplete";
1282 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1283 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
1286 if (!clearIfComposited(mask))
1287 webContext()->clear(mask);
1288 markContextChanged(CanvasChanged);
1291 void WebGLRenderingContextBase::clearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1293 if (isContextLost())
1303 m_clearColor[0] = r;
1304 m_clearColor[1] = g;
1305 m_clearColor[2] = b;
1306 m_clearColor[3] = a;
1307 webContext()->clearColor(r, g, b, a);
1310 void WebGLRenderingContextBase::clearDepth(GLfloat depth)
1312 if (isContextLost())
1314 m_clearDepth = depth;
1315 webContext()->clearDepth(depth);
1318 void WebGLRenderingContextBase::clearStencil(GLint s)
1320 if (isContextLost())
1323 webContext()->clearStencil(s);
1326 void WebGLRenderingContextBase::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
1328 if (isContextLost())
1330 m_colorMask[0] = red;
1331 m_colorMask[1] = green;
1332 m_colorMask[2] = blue;
1333 m_colorMask[3] = alpha;
1334 webContext()->colorMask(red, green, blue, alpha);
1337 void WebGLRenderingContextBase::compileShader(WebGLShader* shader)
1339 if (isContextLost() || !validateWebGLObject("compileShader", shader))
1341 webContext()->compileShader(objectOrZero(shader));
1344 void WebGLRenderingContextBase::compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, ArrayBufferView* data)
1346 if (isContextLost())
1348 if (!validateTexFuncLevel("compressedTexImage2D", target, level))
1351 if (!validateCompressedTexFormat(internalformat)) {
1352 synthesizeGLError(GL_INVALID_ENUM, "compressedTexImage2D", "invalid internalformat");
1356 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "border not 0");
1359 if (!validateCompressedTexDimensions("compressedTexImage2D", NotTexSubImage2D, target, level, width, height, internalformat))
1361 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data))
1364 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true);
1367 if (!isGLES2NPOTStrict()) {
1368 if (level && WebGLTexture::isNPOT(width, height)) {
1369 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2");
1373 webContext()->compressedTexImage2D(target, level, internalformat, width, height,
1374 border, data->byteLength(), data->baseAddress());
1375 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE);
1378 void WebGLRenderingContextBase::compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* data)
1380 if (isContextLost())
1382 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level))
1384 if (!validateCompressedTexFormat(format)) {
1385 synthesizeGLError(GL_INVALID_ENUM, "compressedTexSubImage2D", "invalid format");
1388 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data))
1391 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true);
1395 if (format != tex->getInternalFormat(target, level)) {
1396 synthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format");
1400 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex))
1403 webContext()->compressedTexSubImage2D(target, level, xoffset, yoffset,
1404 width, height, format, data->byteLength(), data->baseAddress());
1407 bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GLenum format)
1409 if (WebGLImageConversion::getClearBitsByFormat(format) & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
1410 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format can not be set, only rendered to");
1416 void WebGLRenderingContextBase::copyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
1418 if (isContextLost())
1420 if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GL_UNSIGNED_BYTE))
1422 if (!validateSettableTexFormat("copyTexImage2D", internalformat))
1424 WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true);
1427 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) {
1428 synthesizeGLError(GL_INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format");
1431 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) {
1432 synthesizeGLError(GL_INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2");
1435 const char* reason = "framebuffer incomplete";
1436 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1437 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason);
1440 clearIfComposited();
1441 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1442 webContext()->copyTexImage2D(target, level, internalformat, x, y, width, height, border);
1443 // FIXME: if the framebuffer is not complete, none of the below should be executed.
1444 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE);
1447 void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
1449 if (isContextLost())
1451 if (!validateTexFuncLevel("copyTexSubImage2D", target, level))
1453 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true);
1456 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height))
1458 // Before checking if it is in the range, check if overflow happens first.
1459 Checked<GLint, RecordOverflow> maxX = xoffset;
1461 Checked<GLint, RecordOverflow> maxY = yoffset;
1463 if (maxX.hasOverflowed() || maxY.hasOverflowed()) {
1464 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "bad dimensions");
1467 if (maxX.unsafeGet() > tex->getWidth(target, level) || maxY.unsafeGet() > tex->getHeight(target, level)) {
1468 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range");
1471 GLenum internalformat = tex->getInternalFormat(target, level);
1472 if (!validateSettableTexFormat("copyTexSubImage2D", internalformat))
1474 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) {
1475 synthesizeGLError(GL_INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format");
1478 const char* reason = "framebuffer incomplete";
1479 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
1480 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason);
1483 clearIfComposited();
1484 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
1485 webContext()->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
1488 PassRefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer()
1490 if (isContextLost())
1492 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this);
1493 addSharedObject(o.get());
1497 PassRefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer()
1499 if (isContextLost())
1501 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this);
1502 addContextObject(o.get());
1506 PassRefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture()
1508 if (isContextLost())
1510 RefPtr<WebGLTexture> o = WebGLTexture::create(this);
1511 addSharedObject(o.get());
1515 PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram()
1517 if (isContextLost())
1519 RefPtr<WebGLProgram> o = WebGLProgram::create(this);
1520 addSharedObject(o.get());
1524 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer()
1526 if (isContextLost())
1528 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this);
1529 addSharedObject(o.get());
1533 WebGLRenderbuffer* WebGLRenderingContextBase::ensureEmulatedStencilBuffer(GLenum target, WebGLRenderbuffer* renderbuffer)
1535 if (isContextLost())
1537 if (!renderbuffer->emulatedStencilBuffer()) {
1538 renderbuffer->setEmulatedStencilBuffer(createRenderbuffer());
1539 webContext()->bindRenderbuffer(target, objectOrZero(renderbuffer->emulatedStencilBuffer()));
1540 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
1542 return renderbuffer->emulatedStencilBuffer();
1545 PassRefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GLenum type)
1547 if (isContextLost())
1549 if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) {
1550 synthesizeGLError(GL_INVALID_ENUM, "createShader", "invalid shader type");
1554 RefPtr<WebGLShader> o = WebGLShader::create(this, type);
1555 addSharedObject(o.get());
1559 void WebGLRenderingContextBase::cullFace(GLenum mode)
1561 if (isContextLost())
1564 case GL_FRONT_AND_BACK:
1569 synthesizeGLError(GL_INVALID_ENUM, "cullFace", "invalid mode");
1572 webContext()->cullFace(mode);
1575 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object)
1577 if (isContextLost() || !object)
1579 if (!object->validate(contextGroup(), this)) {
1580 synthesizeGLError(GL_INVALID_OPERATION, "delete", "object does not belong to this context");
1583 if (object->object()) {
1584 // We need to pass in context here because we want
1585 // things in this context unbound.
1586 object->deleteObject(webContext());
1591 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer)
1593 if (!deleteObject(buffer))
1595 if (m_boundArrayBuffer == buffer)
1596 m_boundArrayBuffer = nullptr;
1598 m_boundVertexArrayObject->unbindBuffer(buffer);
1601 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer)
1603 if (!deleteObject(framebuffer))
1605 if (framebuffer == m_framebufferBinding) {
1606 m_framebufferBinding = nullptr;
1607 m_drawingBuffer->setFramebufferBinding(0);
1608 // Have to call bindFramebuffer here to bind back to internal fbo.
1609 m_drawingBuffer->bind();
1613 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program)
1615 deleteObject(program);
1616 // We don't reset m_currentProgram to 0 here because the deletion of the
1617 // current program is delayed.
1620 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer)
1622 if (!deleteObject(renderbuffer))
1624 if (renderbuffer == m_renderbufferBinding)
1625 m_renderbufferBinding = nullptr;
1626 if (m_framebufferBinding)
1627 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer);
1630 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader)
1632 deleteObject(shader);
1635 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture)
1637 if (!deleteObject(texture))
1640 int maxBoundTextureIndex = -1;
1641 for (size_t i = 0; i < m_onePlusMaxNonDefaultTextureUnit; ++i) {
1642 if (texture == m_textureUnits[i].m_texture2DBinding) {
1643 m_textureUnits[i].m_texture2DBinding = nullptr;
1644 maxBoundTextureIndex = i;
1646 m_drawingBuffer->setTexture2DBinding(0);
1648 if (texture == m_textureUnits[i].m_textureCubeMapBinding) {
1649 m_textureUnits[i].m_textureCubeMapBinding = nullptr;
1650 maxBoundTextureIndex = i;
1653 if (m_framebufferBinding)
1654 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture);
1656 // If the deleted was bound to the the current maximum index, trace backwards to find the new max texture index
1657 if (m_onePlusMaxNonDefaultTextureUnit == static_cast<unsigned long>(maxBoundTextureIndex + 1)) {
1658 findNewMaxNonDefaultTextureUnit();
1662 void WebGLRenderingContextBase::depthFunc(GLenum func)
1664 if (isContextLost())
1666 if (!validateStencilOrDepthFunc("depthFunc", func))
1668 webContext()->depthFunc(func);
1671 void WebGLRenderingContextBase::depthMask(GLboolean flag)
1673 if (isContextLost())
1676 webContext()->depthMask(flag);
1679 void WebGLRenderingContextBase::depthRange(GLfloat zNear, GLfloat zFar)
1681 if (isContextLost())
1684 synthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar");
1687 webContext()->depthRange(zNear, zFar);
1690 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader)
1692 if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader))
1694 if (!program->detachShader(shader)) {
1695 synthesizeGLError(GL_INVALID_OPERATION, "detachShader", "shader not attached");
1698 webContext()->detachShader(objectOrZero(program), objectOrZero(shader));
1699 shader->onDetached(webContext());
1702 void WebGLRenderingContextBase::disable(GLenum cap)
1704 if (isContextLost() || !validateCapability("disable", cap))
1706 if (cap == GL_STENCIL_TEST) {
1707 m_stencilEnabled = false;
1711 if (cap == GL_SCISSOR_TEST) {
1712 m_scissorEnabled = false;
1713 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1715 webContext()->disable(cap);
1718 void WebGLRenderingContextBase::disableVertexAttribArray(GLuint index)
1720 if (isContextLost())
1722 if (index >= m_maxVertexAttribs) {
1723 synthesizeGLError(GL_INVALID_VALUE, "disableVertexAttribArray", "index out of range");
1727 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1728 state.enabled = false;
1730 // If the disabled index is the current maximum, trace backwards to find the new max enabled attrib index
1731 if (m_onePlusMaxEnabledAttribIndex == index + 1) {
1732 findNewMaxEnabledAttribIndex();
1735 webContext()->disableVertexAttribArray(index);
1738 bool WebGLRenderingContextBase::validateRenderingState(const char* functionName)
1740 if (!m_currentProgram) {
1741 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no valid shader program in use");
1745 // Look in each enabled vertex attrib and check if they've been bound to a buffer.
1746 for (unsigned i = 0; i < m_onePlusMaxEnabledAttribIndex; ++i) {
1747 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
1749 && (!state.bufferBinding || !state.bufferBinding->object())) {
1750 synthesizeGLError(GL_INVALID_OPERATION, functionName, String::format("attribute %d is enabled but has no buffer bound", i).utf8().data());
1758 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object)
1760 if (!object || !object->object()) {
1761 synthesizeGLError(GL_INVALID_VALUE, functionName, "no object or object deleted");
1764 if (!object->validate(contextGroup(), this)) {
1765 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object does not belong to this context");
1771 void WebGLRenderingContextBase::drawArrays(GLenum mode, GLint first, GLsizei count)
1773 if (!validateDrawArrays("drawArrays", mode, first, count))
1776 clearIfComposited();
1778 handleTextureCompleteness("drawArrays", true);
1779 webContext()->drawArrays(mode, first, count);
1780 handleTextureCompleteness("drawArrays", false);
1781 markContextChanged(CanvasChanged);
1784 void WebGLRenderingContextBase::drawElements(GLenum mode, GLsizei count, GLenum type, long long offset)
1786 if (!validateDrawElements("drawElements", mode, count, type, offset))
1789 clearIfComposited();
1791 handleTextureCompleteness("drawElements", true);
1792 webContext()->drawElements(mode, count, type, static_cast<GLintptr>(offset));
1793 handleTextureCompleteness("drawElements", false);
1794 markContextChanged(CanvasChanged);
1797 void WebGLRenderingContextBase::drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
1799 if (!validateDrawArrays("drawArraysInstancedANGLE", mode, first, count))
1802 if (!validateDrawInstanced("drawArraysInstancedANGLE", primcount))
1805 clearIfComposited();
1807 handleTextureCompleteness("drawArraysInstancedANGLE", true);
1808 webContext()->drawArraysInstancedANGLE(mode, first, count, primcount);
1809 handleTextureCompleteness("drawArraysInstancedANGLE", false);
1810 markContextChanged(CanvasChanged);
1813 void WebGLRenderingContextBase::drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, long long offset, GLsizei primcount)
1815 if (!validateDrawElements("drawElementsInstancedANGLE", mode, count, type, offset))
1818 if (!validateDrawInstanced("drawElementsInstancedANGLE", primcount))
1821 clearIfComposited();
1823 handleTextureCompleteness("drawElementsInstancedANGLE", true);
1824 webContext()->drawElementsInstancedANGLE(mode, count, type, static_cast<GLintptr>(offset), primcount);
1825 handleTextureCompleteness("drawElementsInstancedANGLE", false);
1826 markContextChanged(CanvasChanged);
1829 void WebGLRenderingContextBase::enable(GLenum cap)
1831 if (isContextLost() || !validateCapability("enable", cap))
1833 if (cap == GL_STENCIL_TEST) {
1834 m_stencilEnabled = true;
1838 if (cap == GL_SCISSOR_TEST) {
1839 m_scissorEnabled = true;
1840 m_drawingBuffer->setScissorEnabled(m_scissorEnabled);
1842 webContext()->enable(cap);
1845 void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index)
1847 if (isContextLost())
1849 if (index >= m_maxVertexAttribs) {
1850 synthesizeGLError(GL_INVALID_VALUE, "enableVertexAttribArray", "index out of range");
1854 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
1855 state.enabled = true;
1857 m_onePlusMaxEnabledAttribIndex = max(index + 1, m_onePlusMaxEnabledAttribIndex);
1859 webContext()->enableVertexAttribArray(index);
1862 void WebGLRenderingContextBase::finish()
1864 if (isContextLost())
1866 webContext()->flush(); // Intentionally a flush, not a finish.
1869 void WebGLRenderingContextBase::flush()
1871 if (isContextLost())
1873 webContext()->flush();
1876 void WebGLRenderingContextBase::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer* buffer)
1878 if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment))
1880 if (renderbuffertarget != GL_RENDERBUFFER) {
1881 synthesizeGLError(GL_INVALID_ENUM, "framebufferRenderbuffer", "invalid target");
1884 if (buffer && !buffer->validate(contextGroup(), this)) {
1885 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context");
1888 // Don't allow the default framebuffer to be mutated; all current
1889 // implementations use an FBO internally in place of the default
1891 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1892 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound");
1895 Platform3DObject bufferObject = objectOrZero(buffer);
1896 switch (attachment) {
1897 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
1898 if (isDepthStencilSupported() || !buffer) {
1899 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1900 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, bufferObject);
1902 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(renderbuffertarget, buffer);
1903 if (!emulatedStencilBuffer) {
1904 synthesizeGLError(GL_OUT_OF_MEMORY, "framebufferRenderbuffer", "out of memory");
1907 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject);
1908 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, objectOrZero(emulatedStencilBuffer));
1912 webContext()->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject);
1914 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer);
1918 void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture* texture, GLint level)
1920 if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment))
1923 synthesizeGLError(GL_INVALID_VALUE, "framebufferTexture2D", "level not 0");
1926 if (texture && !texture->validate(contextGroup(), this)) {
1927 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context");
1930 // Don't allow the default framebuffer to be mutated; all current
1931 // implementations use an FBO internally in place of the default
1933 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
1934 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound");
1937 Platform3DObject textureObject = objectOrZero(texture);
1938 switch (attachment) {
1939 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
1940 webContext()->framebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, textureObject, level);
1941 webContext()->framebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, textureObject, level);
1943 case GL_DEPTH_ATTACHMENT:
1944 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
1946 case GL_STENCIL_ATTACHMENT:
1947 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
1950 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level);
1952 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level);
1956 void WebGLRenderingContextBase::frontFace(GLenum mode)
1958 if (isContextLost())
1965 synthesizeGLError(GL_INVALID_ENUM, "frontFace", "invalid mode");
1968 webContext()->frontFace(mode);
1971 void WebGLRenderingContextBase::generateMipmap(GLenum target)
1973 if (isContextLost())
1975 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false);
1978 if (!tex->canGenerateMipmaps()) {
1979 synthesizeGLError(GL_INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size");
1982 if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0)))
1985 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR
1986 // on Mac. Remove the hack once this driver bug is fixed.
1988 bool needToResetMinFilter = false;
1989 if (tex->getMinFilter() != GL_NEAREST_MIPMAP_LINEAR) {
1990 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
1991 needToResetMinFilter = true;
1994 webContext()->generateMipmap(target);
1996 if (needToResetMinFilter)
1997 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, tex->getMinFilter());
1999 tex->generateMipmapLevelInfo();
2002 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GLuint index)
2004 if (isContextLost() || !validateWebGLObject("getActiveAttrib", program))
2006 blink::WebGraphicsContext3D::ActiveInfo info;
2007 if (!webContext()->getActiveAttrib(objectOrZero(program), index, info))
2009 return WebGLActiveInfo::create(info.name, info.type, info.size);
2012 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GLuint index)
2014 if (isContextLost() || !validateWebGLObject("getActiveUniform", program))
2016 blink::WebGraphicsContext3D::ActiveInfo info;
2017 if (!webContext()->getActiveUniform(objectOrZero(program), index, info))
2019 return WebGLActiveInfo::create(info.name, info.type, info.size);
2022 bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects)
2024 shaderObjects.clear();
2025 if (isContextLost() || !validateWebGLObject("getAttachedShaders", program))
2028 const GLenum shaderType[] = {
2032 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GLenum); ++i) {
2033 WebGLShader* shader = program->getAttachedShader(shaderType[i]);
2035 shaderObjects.append(shader);
2040 GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name)
2042 if (isContextLost() || !validateWebGLObject("getAttribLocation", program))
2044 if (!validateLocationLength("getAttribLocation", name))
2046 if (!validateString("getAttribLocation", name))
2048 if (isPrefixReserved(name))
2050 if (!program->linkStatus()) {
2051 synthesizeGLError(GL_INVALID_OPERATION, "getAttribLocation", "program not linked");
2054 return webContext()->getAttribLocation(objectOrZero(program), name.utf8().data());
2057 WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GLenum target, GLenum pname)
2059 if (isContextLost())
2060 return WebGLGetInfo();
2061 if (target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER) {
2062 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid target");
2063 return WebGLGetInfo();
2066 if (pname != GL_BUFFER_SIZE && pname != GL_BUFFER_USAGE) {
2067 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid parameter name");
2068 return WebGLGetInfo();
2072 webContext()->getBufferParameteriv(target, pname, &value);
2073 if (pname == GL_BUFFER_SIZE)
2074 return WebGLGetInfo(value);
2075 return WebGLGetInfo(static_cast<unsigned>(value));
2078 PassRefPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes()
2080 if (isContextLost())
2082 // We always need to return a new WebGLContextAttributes object to
2083 // prevent the user from mutating any cached version.
2084 blink::WebGraphicsContext3D::Attributes attrs = webContext()->getContextAttributes();
2085 RefPtr<WebGLContextAttributes> attributes = m_requestedAttributes->clone();
2086 // Some requested attributes may not be honored, so we need to query the underlying
2087 // context/drawing buffer and adjust accordingly.
2088 if (m_requestedAttributes->depth() && !attrs.depth)
2089 attributes->setDepth(false);
2090 if (m_requestedAttributes->stencil() && !attrs.stencil)
2091 attributes->setStencil(false);
2092 attributes->setAntialias(m_drawingBuffer->multisample());
2093 return attributes.release();
2096 GLenum WebGLRenderingContextBase::getError()
2098 if (m_lostContextErrors.size()) {
2099 GLenum err = m_lostContextErrors.first();
2100 m_lostContextErrors.remove(0);
2104 if (isContextLost())
2107 return webContext()->getError();
2110 const char* const* WebGLRenderingContextBase::ExtensionTracker::prefixes() const
2112 static const char* const unprefixed[] = { "", 0, };
2113 return m_prefixes ? m_prefixes : unprefixed;
2116 bool WebGLRenderingContextBase::ExtensionTracker::matchesNameWithPrefixes(const String& name) const
2118 const char* const* prefixSet = prefixes();
2119 for (; *prefixSet; ++prefixSet) {
2120 String prefixedName = String(*prefixSet) + extensionName();
2121 if (equalIgnoringCase(prefixedName, name)) {
2128 bool WebGLRenderingContextBase::extensionSupportedAndAllowed(const ExtensionTracker* tracker)
2130 if (tracker->webglDebugRendererInfo() && !allowWebGLDebugRendererInfo())
2132 if (tracker->privileged() && !allowPrivilegedExtensions())
2134 if (tracker->draft() && !RuntimeEnabledFeatures::webGLDraftExtensionsEnabled())
2136 if (!tracker->supported(this))
2142 PassRefPtr<WebGLExtension> WebGLRenderingContextBase::getExtension(const String& name)
2144 if (isContextLost())
2147 for (size_t i = 0; i < m_extensions.size(); ++i) {
2148 ExtensionTracker* tracker = m_extensions[i];
2149 if (tracker->matchesNameWithPrefixes(name)) {
2150 if (!extensionSupportedAndAllowed(tracker))
2153 RefPtr<WebGLExtension> extension = tracker->getExtension(this);
2155 m_extensionEnabled[extension->name()] = true;
2156 return extension.release();
2163 WebGLGetInfo WebGLRenderingContextBase::getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname)
2165 if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment))
2166 return WebGLGetInfo();
2168 if (!m_framebufferBinding || !m_framebufferBinding->object()) {
2169 synthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound");
2170 return WebGLGetInfo();
2173 WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment);
2175 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
2176 return WebGLGetInfo(GL_NONE);
2177 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
2178 // specifies INVALID_OPERATION.
2179 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name");
2180 return WebGLGetInfo();
2183 ASSERT(object->isTexture() || object->isRenderbuffer());
2184 if (object->isTexture()) {
2186 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2187 return WebGLGetInfo(GL_TEXTURE);
2188 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2189 return WebGLGetInfo(PassRefPtr<WebGLTexture>(static_cast<WebGLTexture*>(object)));
2190 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2191 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2194 webContext()->getFramebufferAttachmentParameteriv(target, attachment, pname, &value);
2195 return WebGLGetInfo(value);
2198 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment");
2199 return WebGLGetInfo();
2203 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2204 return WebGLGetInfo(GL_RENDERBUFFER);
2205 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2206 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(static_cast<WebGLRenderbuffer*>(object)));
2208 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment");
2209 return WebGLGetInfo();
2214 WebGLGetInfo WebGLRenderingContextBase::getParameter(GLenum pname)
2216 if (isContextLost())
2217 return WebGLGetInfo();
2218 const int intZero = 0;
2220 case GL_ACTIVE_TEXTURE:
2221 return getUnsignedIntParameter(pname);
2222 case GL_ALIASED_LINE_WIDTH_RANGE:
2223 return getWebGLFloatArrayParameter(pname);
2224 case GL_ALIASED_POINT_SIZE_RANGE:
2225 return getWebGLFloatArrayParameter(pname);
2227 return getIntParameter(pname);
2228 case GL_ARRAY_BUFFER_BINDING:
2229 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer));
2231 return getBooleanParameter(pname);
2232 case GL_BLEND_COLOR:
2233 return getWebGLFloatArrayParameter(pname);
2234 case GL_BLEND_DST_ALPHA:
2235 return getUnsignedIntParameter(pname);
2236 case GL_BLEND_DST_RGB:
2237 return getUnsignedIntParameter(pname);
2238 case GL_BLEND_EQUATION_ALPHA:
2239 return getUnsignedIntParameter(pname);
2240 case GL_BLEND_EQUATION_RGB:
2241 return getUnsignedIntParameter(pname);
2242 case GL_BLEND_SRC_ALPHA:
2243 return getUnsignedIntParameter(pname);
2244 case GL_BLEND_SRC_RGB:
2245 return getUnsignedIntParameter(pname);
2247 return getIntParameter(pname);
2248 case GL_COLOR_CLEAR_VALUE:
2249 return getWebGLFloatArrayParameter(pname);
2250 case GL_COLOR_WRITEMASK:
2251 return getBooleanArrayParameter(pname);
2252 case GL_COMPRESSED_TEXTURE_FORMATS:
2253 return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size()));
2255 return getBooleanParameter(pname);
2256 case GL_CULL_FACE_MODE:
2257 return getUnsignedIntParameter(pname);
2258 case GL_CURRENT_PROGRAM:
2259 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram));
2261 if (!m_framebufferBinding && !m_requestedAttributes->depth())
2262 return WebGLGetInfo(intZero);
2263 return getIntParameter(pname);
2264 case GL_DEPTH_CLEAR_VALUE:
2265 return getFloatParameter(pname);
2267 return getUnsignedIntParameter(pname);
2268 case GL_DEPTH_RANGE:
2269 return getWebGLFloatArrayParameter(pname);
2271 return getBooleanParameter(pname);
2272 case GL_DEPTH_WRITEMASK:
2273 return getBooleanParameter(pname);
2275 return getBooleanParameter(pname);
2276 case GL_ELEMENT_ARRAY_BUFFER_BINDING:
2277 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->boundElementArrayBuffer()));
2278 case GL_FRAMEBUFFER_BINDING:
2279 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding));
2281 return getUnsignedIntParameter(pname);
2282 case GL_GENERATE_MIPMAP_HINT:
2283 return getUnsignedIntParameter(pname);
2285 return getIntParameter(pname);
2286 case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
2287 return getIntParameter(pname);
2288 case GL_IMPLEMENTATION_COLOR_READ_TYPE:
2289 return getIntParameter(pname);
2291 return getFloatParameter(pname);
2292 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
2293 return getIntParameter(pname);
2294 case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
2295 return getIntParameter(pname);
2296 case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
2297 return getIntParameter(pname);
2298 case GL_MAX_RENDERBUFFER_SIZE:
2299 return getIntParameter(pname);
2300 case GL_MAX_TEXTURE_IMAGE_UNITS:
2301 return getIntParameter(pname);
2302 case GL_MAX_TEXTURE_SIZE:
2303 return getIntParameter(pname);
2304 case GL_MAX_VARYING_VECTORS:
2305 return getIntParameter(pname);
2306 case GL_MAX_VERTEX_ATTRIBS:
2307 return getIntParameter(pname);
2308 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
2309 return getIntParameter(pname);
2310 case GL_MAX_VERTEX_UNIFORM_VECTORS:
2311 return getIntParameter(pname);
2312 case GL_MAX_VIEWPORT_DIMS:
2313 return getWebGLIntArrayParameter(pname);
2314 case GL_NUM_SHADER_BINARY_FORMATS:
2315 // FIXME: should we always return 0 for this?
2316 return getIntParameter(pname);
2317 case GL_PACK_ALIGNMENT:
2318 return getIntParameter(pname);
2319 case GL_POLYGON_OFFSET_FACTOR:
2320 return getFloatParameter(pname);
2321 case GL_POLYGON_OFFSET_FILL:
2322 return getBooleanParameter(pname);
2323 case GL_POLYGON_OFFSET_UNITS:
2324 return getFloatParameter(pname);
2326 return getIntParameter(pname);
2327 case GL_RENDERBUFFER_BINDING:
2328 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding));
2330 return WebGLGetInfo(String("WebKit WebGL"));
2331 case GL_SAMPLE_BUFFERS:
2332 return getIntParameter(pname);
2333 case GL_SAMPLE_COVERAGE_INVERT:
2334 return getBooleanParameter(pname);
2335 case GL_SAMPLE_COVERAGE_VALUE:
2336 return getFloatParameter(pname);
2338 return getIntParameter(pname);
2339 case GL_SCISSOR_BOX:
2340 return getWebGLIntArrayParameter(pname);
2341 case GL_SCISSOR_TEST:
2342 return getBooleanParameter(pname);
2343 case GL_SHADING_LANGUAGE_VERSION:
2344 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + String(webContext()->getString(GL_SHADING_LANGUAGE_VERSION)) + ")");
2345 case GL_STENCIL_BACK_FAIL:
2346 return getUnsignedIntParameter(pname);
2347 case GL_STENCIL_BACK_FUNC:
2348 return getUnsignedIntParameter(pname);
2349 case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
2350 return getUnsignedIntParameter(pname);
2351 case GL_STENCIL_BACK_PASS_DEPTH_PASS:
2352 return getUnsignedIntParameter(pname);
2353 case GL_STENCIL_BACK_REF:
2354 return getIntParameter(pname);
2355 case GL_STENCIL_BACK_VALUE_MASK:
2356 return getUnsignedIntParameter(pname);
2357 case GL_STENCIL_BACK_WRITEMASK:
2358 return getUnsignedIntParameter(pname);
2359 case GL_STENCIL_BITS:
2360 if (!m_framebufferBinding && !m_requestedAttributes->stencil())
2361 return WebGLGetInfo(intZero);
2362 return getIntParameter(pname);
2363 case GL_STENCIL_CLEAR_VALUE:
2364 return getIntParameter(pname);
2365 case GL_STENCIL_FAIL:
2366 return getUnsignedIntParameter(pname);
2367 case GL_STENCIL_FUNC:
2368 return getUnsignedIntParameter(pname);
2369 case GL_STENCIL_PASS_DEPTH_FAIL:
2370 return getUnsignedIntParameter(pname);
2371 case GL_STENCIL_PASS_DEPTH_PASS:
2372 return getUnsignedIntParameter(pname);
2373 case GL_STENCIL_REF:
2374 return getIntParameter(pname);
2375 case GL_STENCIL_TEST:
2376 return getBooleanParameter(pname);
2377 case GL_STENCIL_VALUE_MASK:
2378 return getUnsignedIntParameter(pname);
2379 case GL_STENCIL_WRITEMASK:
2380 return getUnsignedIntParameter(pname);
2381 case GL_SUBPIXEL_BITS:
2382 return getIntParameter(pname);
2383 case GL_TEXTURE_BINDING_2D:
2384 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding));
2385 case GL_TEXTURE_BINDING_CUBE_MAP:
2386 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding));
2387 case GL_UNPACK_ALIGNMENT:
2388 return getIntParameter(pname);
2389 case GC3D_UNPACK_FLIP_Y_WEBGL:
2390 return WebGLGetInfo(m_unpackFlipY);
2391 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2392 return WebGLGetInfo(m_unpackPremultiplyAlpha);
2393 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
2394 return WebGLGetInfo(m_unpackColorspaceConversion);
2396 return WebGLGetInfo(String("WebKit"));
2398 return WebGLGetInfo("WebGL 1.0 (" + String(webContext()->getString(GL_VERSION)) + ")");
2400 return getWebGLIntArrayParameter(pname);
2401 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2402 if (extensionEnabled(OESStandardDerivativesName))
2403 return getUnsignedIntParameter(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
2404 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled");
2405 return WebGLGetInfo();
2406 case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL:
2407 if (extensionEnabled(WebGLDebugRendererInfoName))
2408 return WebGLGetInfo(webContext()->getString(GL_RENDERER));
2409 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2410 return WebGLGetInfo();
2411 case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL:
2412 if (extensionEnabled(WebGLDebugRendererInfoName))
2413 return WebGLGetInfo(webContext()->getString(GL_VENDOR));
2414 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled");
2415 return WebGLGetInfo();
2416 case GL_VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object
2417 if (extensionEnabled(OESVertexArrayObjectName)) {
2418 if (!m_boundVertexArrayObject->isDefaultObject())
2419 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject));
2420 return WebGLGetInfo();
2422 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled");
2423 return WebGLGetInfo();
2424 case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2425 if (extensionEnabled(EXTTextureFilterAnisotropicName))
2426 return getUnsignedIntParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
2427 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2428 return WebGLGetInfo();
2429 case GL_MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN
2430 if (extensionEnabled(WebGLDrawBuffersName))
2431 return WebGLGetInfo(maxColorAttachments());
2432 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2433 return WebGLGetInfo();
2434 case GL_MAX_DRAW_BUFFERS_EXT:
2435 if (extensionEnabled(WebGLDrawBuffersName))
2436 return WebGLGetInfo(maxDrawBuffers());
2437 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled");
2438 return WebGLGetInfo();
2440 if (extensionEnabled(WebGLDrawBuffersName)
2441 && pname >= GL_DRAW_BUFFER0_EXT
2442 && pname < static_cast<GLenum>(GL_DRAW_BUFFER0_EXT + maxDrawBuffers())) {
2443 GLint value = GL_NONE;
2444 if (m_framebufferBinding)
2445 value = m_framebufferBinding->getDrawBuffer(pname);
2446 else // emulated backbuffer
2447 value = m_backDrawBuffer;
2448 return WebGLGetInfo(value);
2450 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name");
2451 return WebGLGetInfo();
2455 WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GLenum pname)
2457 if (isContextLost() || !validateWebGLObject("getProgramParameter", program))
2458 return WebGLGetInfo();
2462 case GL_DELETE_STATUS:
2463 return WebGLGetInfo(program->isDeleted());
2464 case GL_VALIDATE_STATUS:
2465 webContext()->getProgramiv(objectOrZero(program), pname, &value);
2466 return WebGLGetInfo(static_cast<bool>(value));
2467 case GL_LINK_STATUS:
2468 return WebGLGetInfo(program->linkStatus());
2469 case GL_ATTACHED_SHADERS:
2470 case GL_ACTIVE_ATTRIBUTES:
2471 case GL_ACTIVE_UNIFORMS:
2472 webContext()->getProgramiv(objectOrZero(program), pname, &value);
2473 return WebGLGetInfo(value);
2475 synthesizeGLError(GL_INVALID_ENUM, "getProgramParameter", "invalid parameter name");
2476 return WebGLGetInfo();
2480 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program)
2482 if (isContextLost())
2484 if (!validateWebGLObject("getProgramInfoLog", program))
2486 return ensureNotNull(webContext()->getProgramInfoLog(objectOrZero(program)));
2489 WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GLenum target, GLenum pname)
2491 if (isContextLost())
2492 return WebGLGetInfo();
2493 if (target != GL_RENDERBUFFER) {
2494 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid target");
2495 return WebGLGetInfo();
2497 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
2498 synthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound");
2499 return WebGLGetInfo();
2504 case GL_RENDERBUFFER_WIDTH:
2505 case GL_RENDERBUFFER_HEIGHT:
2506 case GL_RENDERBUFFER_RED_SIZE:
2507 case GL_RENDERBUFFER_GREEN_SIZE:
2508 case GL_RENDERBUFFER_BLUE_SIZE:
2509 case GL_RENDERBUFFER_ALPHA_SIZE:
2510 case GL_RENDERBUFFER_DEPTH_SIZE:
2511 webContext()->getRenderbufferParameteriv(target, pname, &value);
2512 return WebGLGetInfo(value);
2513 case GL_RENDERBUFFER_STENCIL_SIZE:
2514 if (m_renderbufferBinding->emulatedStencilBuffer()) {
2515 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding->emulatedStencilBuffer()));
2516 webContext()->getRenderbufferParameteriv(target, pname, &value);
2517 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
2519 webContext()->getRenderbufferParameteriv(target, pname, &value);
2521 return WebGLGetInfo(value);
2522 case GL_RENDERBUFFER_INTERNAL_FORMAT:
2523 return WebGLGetInfo(m_renderbufferBinding->internalFormat());
2525 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name");
2526 return WebGLGetInfo();
2530 WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GLenum pname)
2532 if (isContextLost() || !validateWebGLObject("getShaderParameter", shader))
2533 return WebGLGetInfo();
2536 case GL_DELETE_STATUS:
2537 return WebGLGetInfo(shader->isDeleted());
2538 case GL_COMPILE_STATUS:
2539 webContext()->getShaderiv(objectOrZero(shader), pname, &value);
2540 return WebGLGetInfo(static_cast<bool>(value));
2541 case GL_SHADER_TYPE:
2542 webContext()->getShaderiv(objectOrZero(shader), pname, &value);
2543 return WebGLGetInfo(static_cast<unsigned>(value));
2545 synthesizeGLError(GL_INVALID_ENUM, "getShaderParameter", "invalid parameter name");
2546 return WebGLGetInfo();
2550 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader)
2552 if (isContextLost())
2554 if (!validateWebGLObject("getShaderInfoLog", shader))
2556 return ensureNotNull(webContext()->getShaderInfoLog(objectOrZero(shader)));
2559 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GLenum shaderType, GLenum precisionType)
2561 if (isContextLost())
2563 switch (shaderType) {
2564 case GL_VERTEX_SHADER:
2565 case GL_FRAGMENT_SHADER:
2568 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type");
2571 switch (precisionType) {
2573 case GL_MEDIUM_FLOAT:
2580 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type");
2584 GLint range[2] = {0, 0};
2585 GLint precision = 0;
2586 webContext()->getShaderPrecisionFormat(shaderType, precisionType, range, &precision);
2587 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision);
2590 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader)
2592 if (isContextLost())
2594 if (!validateWebGLObject("getShaderSource", shader))
2596 return ensureNotNull(shader->source());
2599 Vector<String> WebGLRenderingContextBase::getSupportedExtensions()
2601 Vector<String> result;
2602 if (isContextLost())
2605 for (size_t i = 0; i < m_extensions.size(); ++i) {
2606 ExtensionTracker* tracker = m_extensions[i];
2607 if (extensionSupportedAndAllowed(tracker)) {
2608 const char* const* prefixes = tracker->prefixes();
2609 for (; *prefixes; ++prefixes) {
2610 String prefixedName = String(*prefixes) + tracker->extensionName();
2611 result.append(prefixedName);
2619 WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GLenum target, GLenum pname)
2621 if (isContextLost())
2622 return WebGLGetInfo();
2623 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false);
2625 return WebGLGetInfo();
2627 case GL_TEXTURE_MAG_FILTER:
2628 case GL_TEXTURE_MIN_FILTER:
2629 case GL_TEXTURE_WRAP_S:
2630 case GL_TEXTURE_WRAP_T:
2633 webContext()->getTexParameteriv(target, pname, &value);
2634 return WebGLGetInfo(static_cast<unsigned>(value));
2636 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
2637 if (extensionEnabled(EXTTextureFilterAnisotropicName)) {
2638 GLfloat value = 0.f;
2639 webContext()->getTexParameterfv(target, pname, &value);
2640 return WebGLGetInfo(value);
2642 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
2643 return WebGLGetInfo();
2645 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name");
2646 return WebGLGetInfo();
2650 WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation)
2652 if (isContextLost() || !validateWebGLObject("getUniform", program))
2653 return WebGLGetInfo();
2654 if (!uniformLocation || uniformLocation->program() != program) {
2655 synthesizeGLError(GL_INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program");
2656 return WebGLGetInfo();
2658 GLint location = uniformLocation->location();
2660 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it
2661 GLint activeUniforms = 0;
2662 webContext()->getProgramiv(objectOrZero(program), GL_ACTIVE_UNIFORMS, &activeUniforms);
2663 for (GLint i = 0; i < activeUniforms; i++) {
2664 blink::WebGraphicsContext3D::ActiveInfo info;
2665 if (!webContext()->getActiveUniform(objectOrZero(program), i, info))
2666 return WebGLGetInfo();
2667 String name = info.name;
2668 StringBuilder nameBuilder;
2669 // Strip "[0]" from the name if it's an array.
2670 if (info.size > 1 && name.endsWith("[0]"))
2671 info.name = name.left(name.length() - 3);
2672 // If it's an array, we need to iterate through each element, appending "[index]" to the name.
2673 for (GLint index = 0; index < info.size; ++index) {
2674 nameBuilder.clear();
2675 nameBuilder.append(info.name);
2676 if (info.size > 1 && index >= 1) {
2677 nameBuilder.append('[');
2678 nameBuilder.append(String::number(index));
2679 nameBuilder.append(']');
2681 // Now need to look this up by name again to find its location
2682 GLint loc = webContext()->getUniformLocation(objectOrZero(program), nameBuilder.toString().utf8().data());
2683 if (loc == location) {
2684 // Found it. Use the type in the ActiveInfo to determine the return type.
2687 switch (info.type) {
2721 baseType = GL_FLOAT;
2725 baseType = GL_FLOAT;
2729 baseType = GL_FLOAT;
2733 baseType = GL_FLOAT;
2737 baseType = GL_FLOAT;
2741 baseType = GL_FLOAT;
2745 baseType = GL_FLOAT;
2749 case GL_SAMPLER_CUBE:
2754 // Can't handle this type
2755 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unhandled type");
2756 return WebGLGetInfo();
2760 GLfloat value[16] = {0};
2761 webContext()->getUniformfv(objectOrZero(program), location, value);
2763 return WebGLGetInfo(value[0]);
2764 return WebGLGetInfo(Float32Array::create(value, length));
2767 GLint value[4] = {0};
2768 webContext()->getUniformiv(objectOrZero(program), location, value);
2770 return WebGLGetInfo(value[0]);
2771 return WebGLGetInfo(Int32Array::create(value, length));
2774 GLint value[4] = {0};
2775 webContext()->getUniformiv(objectOrZero(program), location, value);
2777 bool boolValue[16] = {0};
2778 for (unsigned j = 0; j < length; j++)
2779 boolValue[j] = static_cast<bool>(value[j]);
2780 return WebGLGetInfo(boolValue, length);
2782 return WebGLGetInfo(static_cast<bool>(value[0]));
2790 // If we get here, something went wrong in our unfortunately complex logic above
2791 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error");
2792 return WebGLGetInfo();
2795 PassRefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name)
2797 if (isContextLost() || !validateWebGLObject("getUniformLocation", program))
2799 if (!validateLocationLength("getUniformLocation", name))
2801 if (!validateString("getUniformLocation", name))
2803 if (isPrefixReserved(name))
2805 if (!program->linkStatus()) {
2806 synthesizeGLError(GL_INVALID_OPERATION, "getUniformLocation", "program not linked");
2809 GLint uniformLocation = webContext()->getUniformLocation(objectOrZero(program), name.utf8().data());
2810 if (uniformLocation == -1)
2812 return WebGLUniformLocation::create(program, uniformLocation);
2815 WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GLuint index, GLenum pname)
2817 if (isContextLost())
2818 return WebGLGetInfo();
2819 if (index >= m_maxVertexAttribs) {
2820 synthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib", "index out of range");
2821 return WebGLGetInfo();
2823 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index);
2825 if (extensionEnabled(ANGLEInstancedArraysName) && pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE)
2826 return WebGLGetInfo(state.divisor);
2829 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2830 if (!state.bufferBinding || !state.bufferBinding->object())
2831 return WebGLGetInfo();
2832 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding));
2833 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2834 return WebGLGetInfo(state.enabled);
2835 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2836 return WebGLGetInfo(state.normalized);
2837 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2838 return WebGLGetInfo(state.size);
2839 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2840 return WebGLGetInfo(state.originalStride);
2841 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2842 return WebGLGetInfo(state.type);
2843 case GL_CURRENT_VERTEX_ATTRIB:
2844 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4));
2846 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib", "invalid parameter name");
2847 return WebGLGetInfo();
2851 long long WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, GLenum pname)
2853 if (isContextLost())
2855 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) {
2856 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttribOffset", "invalid parameter name");
2859 GLsizeiptr result = webContext()->getVertexAttribOffset(index, pname);
2860 return static_cast<long long>(result);
2863 void WebGLRenderingContextBase::hint(GLenum target, GLenum mode)
2865 if (isContextLost())
2867 bool isValid = false;
2869 case GL_GENERATE_MIPMAP_HINT:
2872 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives
2873 if (extensionEnabled(OESStandardDerivativesName))
2878 synthesizeGLError(GL_INVALID_ENUM, "hint", "invalid target");
2881 webContext()->hint(target, mode);
2884 GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer)
2886 if (!buffer || isContextLost())
2889 if (!buffer->hasEverBeenBound())
2892 return webContext()->isBuffer(buffer->object());
2895 bool WebGLRenderingContextBase::isContextLost() const
2897 return m_contextLost;
2900 GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap)
2902 if (isContextLost() || !validateCapability("isEnabled", cap))
2904 if (cap == GL_STENCIL_TEST)
2905 return m_stencilEnabled;
2906 return webContext()->isEnabled(cap);
2909 GLboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer)
2911 if (!framebuffer || isContextLost())
2914 if (!framebuffer->hasEverBeenBound())
2917 return webContext()->isFramebuffer(framebuffer->object());
2920 GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program)
2922 if (!program || isContextLost())
2925 return webContext()->isProgram(program->object());
2928 GLboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
2930 if (!renderbuffer || isContextLost())
2933 if (!renderbuffer->hasEverBeenBound())
2936 return webContext()->isRenderbuffer(renderbuffer->object());
2939 GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader)
2941 if (!shader || isContextLost())
2944 return webContext()->isShader(shader->object());
2947 GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture)
2949 if (!texture || isContextLost())
2952 if (!texture->hasEverBeenBound())
2955 return webContext()->isTexture(texture->object());
2958 void WebGLRenderingContextBase::lineWidth(GLfloat width)
2960 if (isContextLost())
2962 webContext()->lineWidth(width);
2965 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program)
2967 if (isContextLost() || !validateWebGLObject("linkProgram", program))
2970 webContext()->linkProgram(objectOrZero(program));
2971 program->increaseLinkCount();
2974 void WebGLRenderingContextBase::pixelStorei(GLenum pname, GLint param)
2976 if (isContextLost())
2979 case GC3D_UNPACK_FLIP_Y_WEBGL:
2980 m_unpackFlipY = param;
2982 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
2983 m_unpackPremultiplyAlpha = param;
2985 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
2986 if (static_cast<GLenum>(param) == GC3D_BROWSER_DEFAULT_WEBGL || param == GL_NONE) {
2987 m_unpackColorspaceConversion = static_cast<GLenum>(param);
2989 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
2993 case GL_PACK_ALIGNMENT:
2994 case GL_UNPACK_ALIGNMENT:
2995 if (param == 1 || param == 2 || param == 4 || param == 8) {
2996 if (pname == GL_PACK_ALIGNMENT) {
2997 m_packAlignment = param;
2998 m_drawingBuffer->setPackAlignment(param);
2999 } else { // GL_UNPACK_ALIGNMENT:
3000 m_unpackAlignment = param;
3002 webContext()->pixelStorei(pname, param);
3004 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for alignment");
3009 synthesizeGLError(GL_INVALID_ENUM, "pixelStorei", "invalid parameter name");
3014 void WebGLRenderingContextBase::polygonOffset(GLfloat factor, GLfloat units)
3016 if (isContextLost())
3018 webContext()->polygonOffset(factor, units);
3021 void WebGLRenderingContextBase::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels)
3023 if (isContextLost())
3025 // Due to WebGL's same-origin restrictions, it is not possible to
3026 // taint the origin using the WebGL API.
3027 ASSERT(canvas()->originClean());
3028 // Validate input parameters.
3030 synthesizeGLError(GL_INVALID_VALUE, "readPixels", "no destination ArrayBufferView");
3039 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid format");
3043 ArrayBufferView::ViewType expectedViewType;
3046 case GL_UNSIGNED_BYTE:
3047 expectedViewType = ArrayBufferView::TypeUint8;
3049 case GL_UNSIGNED_SHORT_5_6_5:
3050 case GL_UNSIGNED_SHORT_4_4_4_4:
3051 case GL_UNSIGNED_SHORT_5_5_5_1:
3052 expectedViewType = ArrayBufferView::TypeUint16;
3055 expectedViewType = ArrayBufferView::TypeFloat32;
3057 case GL_HALF_FLOAT_OES:
3058 expectedViewType = ArrayBufferView::TypeUint16;
3061 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
3064 if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) {
3065 // Check against the implementation color read format and type.
3066 blink::WGC3Dint implFormat = 0, implType = 0;
3067 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &implFormat);
3068 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &implType);
3069 if (!implFormat || !implType || format != static_cast<GLenum>(implFormat) || type != static_cast<GLenum>(implType)) {
3070 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "format/type not RGBA/UNSIGNED_BYTE or implementation-defined values");
3074 // Validate array type against pixel type.
3075 if (pixels->type() != expectedViewType) {
3076 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView was the wrong type for the pixel format");
3079 const char* reason = "framebuffer incomplete";
3080 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
3081 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
3084 // Calculate array size, taking into consideration of PACK_ALIGNMENT.
3085 unsigned totalBytesRequired = 0;
3086 unsigned padding = 0;
3087 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding);
3088 if (error != GL_NO_ERROR) {
3089 synthesizeGLError(error, "readPixels", "invalid dimensions");
3092 if (pixels->byteLength() < totalBytesRequired) {
3093 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions");
3097 clearIfComposited();
3098 void* data = pixels->baseAddress();
3101 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get());
3102 webContext()->readPixels(x, y, width, height, format, type, data);
3106 // FIXME: remove this section when GL driver bug on Mac is fixed, i.e.,
3107 // when alpha is off, readPixels should set alpha to 255 instead of 0.
3108 if (!m_framebufferBinding && !webContext()->getContextAttributes().alpha) {
3109 unsigned char* pixels = reinterpret_cast<unsigned char*>(data);
3110 for (GLsizei iy = 0; iy < height; ++iy) {
3111 for (GLsizei ix = 0; ix < width; ++ix) {
3121 void WebGLRenderingContextBase::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
3123 if (isContextLost())
3125 if (target != GL_RENDERBUFFER) {
3126 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid target");
3129 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) {
3130 synthesizeGLError(GL_INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer");
3133 if (!validateSize("renderbufferStorage", width, height))
3135 switch (internalformat) {
3136 case GL_DEPTH_COMPONENT16:
3140 case GL_STENCIL_INDEX8:
3141 webContext()->renderbufferStorage(target, internalformat, width, height);
3142 m_renderbufferBinding->setInternalFormat(internalformat);
3143 m_renderbufferBinding->setSize(width, height);
3144 m_renderbufferBinding->deleteEmulatedStencilBuffer(webContext());
3146 case GL_DEPTH_STENCIL_OES:
3147 if (isDepthStencilSupported()) {
3148 webContext()->renderbufferStorage(target, GL_DEPTH24_STENCIL8_OES, width, height);
3150 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(target, m_renderbufferBinding.get());
3151 if (!emulatedStencilBuffer) {
3152 synthesizeGLError(GL_OUT_OF_MEMORY, "renderbufferStorage", "out of memory");
3155 webContext()->renderbufferStorage(target, GL_DEPTH_COMPONENT16, width, height);
3156 webContext()->bindRenderbuffer(target, objectOrZero(emulatedStencilBuffer));
3157 webContext()->renderbufferStorage(target, GL_STENCIL_INDEX8, width, height);
3158 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get()));
3159 emulatedStencilBuffer->setSize(width, height);
3160 emulatedStencilBuffer->setInternalFormat(GL_STENCIL_INDEX8);
3162 m_renderbufferBinding->setSize(width, height);
3163 m_renderbufferBinding->setInternalFormat(internalformat);
3166 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid internalformat");
3172 void WebGLRenderingContextBase::sampleCoverage(GLfloat value, GLboolean invert)
3174 if (isContextLost())
3176 webContext()->sampleCoverage(value, invert);
3179 void WebGLRenderingContextBase::scissor(GLint x, GLint y, GLsizei width, GLsizei height)
3181 if (isContextLost())
3183 if (!validateSize("scissor", width, height))
3185 webContext()->scissor(x, y, width, height);
3188 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string)
3190 if (isContextLost() || !validateWebGLObject("shaderSource", shader))
3192 String stringWithoutComments = StripComments(string).result();
3193 if (!validateString("shaderSource", stringWithoutComments))
3195 shader->setSource(string);
3196 webContext()->shaderSource(objectOrZero(shader), stringWithoutComments.utf8().data());
3199 void WebGLRenderingContextBase::stencilFunc(GLenum func, GLint ref, GLuint mask)
3201 if (isContextLost())
3203 if (!validateStencilOrDepthFunc("stencilFunc", func))
3205 m_stencilFuncRef = ref;
3206 m_stencilFuncRefBack = ref;
3207 m_stencilFuncMask = mask;
3208 m_stencilFuncMaskBack = mask;
3209 webContext()->stencilFunc(func, ref, mask);
3212 void WebGLRenderingContextBase::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
3214 if (isContextLost())
3216 if (!validateStencilOrDepthFunc("stencilFuncSeparate", func))
3219 case GL_FRONT_AND_BACK:
3220 m_stencilFuncRef = ref;
3221 m_stencilFuncRefBack = ref;
3222 m_stencilFuncMask = mask;
3223 m_stencilFuncMaskBack = mask;
3226 m_stencilFuncRef = ref;
3227 m_stencilFuncMask = mask;
3230 m_stencilFuncRefBack = ref;
3231 m_stencilFuncMaskBack = mask;
3234 synthesizeGLError(GL_INVALID_ENUM, "stencilFuncSeparate", "invalid face");
3237 webContext()->stencilFuncSeparate(face, func, ref, mask);
3240 void WebGLRenderingContextBase::stencilMask(GLuint mask)
3242 if (isContextLost())
3244 m_stencilMask = mask;
3245 m_stencilMaskBack = mask;
3246 webContext()->stencilMask(mask);
3249 void WebGLRenderingContextBase::stencilMaskSeparate(GLenum face, GLuint mask)
3251 if (isContextLost())
3254 case GL_FRONT_AND_BACK:
3255 m_stencilMask = mask;
3256 m_stencilMaskBack = mask;
3259 m_stencilMask = mask;
3262 m_stencilMaskBack = mask;
3265 synthesizeGLError(GL_INVALID_ENUM, "stencilMaskSeparate", "invalid face");
3268 webContext()->stencilMaskSeparate(face, mask);
3271 void WebGLRenderingContextBase::stencilOp(GLenum fail, GLenum zfail, GLenum zpass)
3273 if (isContextLost())
3275 webContext()->stencilOp(fail, zfail, zpass);
3278 void WebGLRenderingContextBase::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
3280 if (isContextLost())
3282 webContext()->stencilOpSeparate(face, fail, zfail, zpass);
3285 GLenum WebGLRenderingContextBase::convertTexInternalFormat(GLenum internalformat, GLenum type)
3287 // Convert to sized internal formats that are renderable with GL_CHROMIUM_color_buffer_float_rgb(a).
3288 if (type == GL_FLOAT && internalformat == GL_RGBA
3289 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba"))
3290 return GL_RGBA32F_EXT;
3291 if (type == GL_FLOAT && internalformat == GL_RGB
3292 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb"))
3293 return GL_RGB32F_EXT;
3294 return internalformat;
3297 void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState)
3299 // All calling functions check isContextLost, so a duplicate check is not needed here.
3300 // FIXME: Handle errors.
3301 WebGLTexture* tex = validateTextureBinding("texImage2D", target, true);
3302 ASSERT(validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type));
3304 ASSERT(!level || !WebGLTexture::isNPOT(width, height));
3305 ASSERT(!pixels || validateSettableTexFormat("texImage2D", internalformat));
3306 webContext()->texImage2D(target, level, convertTexInternalFormat(internalformat, type), width, height, border, format, type, pixels);
3307 tex->setLevelInfo(target, level, internalformat, width, height, type);
3310 void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionState& exceptionState)
3312 // All calling functions check isContextLost, so a duplicate check is not needed here.
3313 Vector<uint8_t> data;
3314 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE);
3315 if (!imageExtractor.extractSucceeded()) {
3316 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data");
3319 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3320 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3321 const void* imagePixelData = imageExtractor.imagePixelData();
3323 bool needConversion = true;
3324 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY)
3325 needConversion = false;
3327 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3328 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "packImage error");
3333 if (m_unpackAlignment != 1)
3334 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3335 texImage2DBase(target, level, internalformat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), 0, format, type, needConversion ? data.data() : imagePixelData, exceptionState);
3336 if (m_unpackAlignment != 1)
3337 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3340 bool WebGLRenderingContextBase::validateTexFunc(const char* functionName, TexFuncValidationFunctionType functionType, TexFuncValidationSourceType sourceType, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint xoffset, GLint yoffset)
3342 if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
3345 WebGLTexture* texture = validateTextureBinding(functionName, target, true);
3349 if (functionType == NotTexSubImage2D) {
3350 if (level && WebGLTexture::isNPOT(width, height)) {
3351 synthesizeGLError(GL_INVALID_VALUE, functionName, "level > 0 not power of 2");
3354 // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat
3355 // by checking if the ArrayBufferView is null or not.
3356 if (sourceType != SourceArrayBufferView) {
3357 if (!validateSettableTexFormat(functionName, format))
3361 if (!validateSettableTexFormat(functionName, format))
3363 if (!validateSize(functionName, xoffset, yoffset))
3365 // Before checking if it is in the range, check if overflow happens first.
3366 if (xoffset + width < 0 || yoffset + height < 0) {
3367 synthesizeGLError(GL_INVALID_VALUE, functionName, "bad dimensions");
3370 if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) {
3371 synthesizeGLError(GL_INVALID_VALUE, functionName, "dimensions out of range");
3374 if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) {
3375 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type and format do not match texture");
3383 bool WebGLRenderingContextBase::validateValueFitNonNegInt32(const char* functionName, const char* paramName, long long value)
3386 String errorMsg = String(paramName) + " < 0";
3387 synthesizeGLError(GL_INVALID_VALUE, functionName, errorMsg.ascii().data());
3390 if (value > static_cast<long long>(std::numeric_limits<int>::max())) {
3391 String errorMsg = String(paramName) + " more than 32-bit";
3392 synthesizeGLError(GL_INVALID_OPERATION, functionName, errorMsg.ascii().data());
3398 PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, const char* functionName)
3400 IntSize size(width, height);
3401 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3403 synthesizeGLError(GL_OUT_OF_MEMORY, functionName, "out of memory");
3407 IntRect srcRect(IntPoint(), image->size());
3408 IntRect destRect(0, 0, size.width(), size.height());
3409 buf->context()->drawImage(image, destRect, srcRect);
3410 return buf->copyImage(ImageBuffer::fastCopyImageMode());
3413 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3414 GLsizei width, GLsizei height, GLint border,
3415 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState)
3417 if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed)
3418 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0))
3420 void* data = pixels ? pixels->baseAddress() : 0;
3421 Vector<uint8_t> tempData;
3422 bool changeUnpackAlignment = false;
3423 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3424 if (!WebGLImageConversion::extractTextureData(width, height, format, type, m_unpackAlignment, m_unpackFlipY, m_unpackPremultiplyAlpha, data, tempData))
3426 data = tempData.data();
3427 changeUnpackAlignment = true;
3429 if (changeUnpackAlignment)
3430 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3431 texImage2DBase(target, level, internalformat, width, height, border, format, type, data, exceptionState);
3432 if (changeUnpackAlignment)
3433 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3436 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3437 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState)
3439 if (isContextLost() || !pixels || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0))
3441 Vector<uint8_t> data;
3442 bool needConversion = true;
3443 // The data from ImageData is always of format RGBA8.
3444 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3445 if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GL_RGBA && type == GL_UNSIGNED_BYTE)
3446 needConversion = false;
3448 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3449 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data");
3453 if (m_unpackAlignment != 1)
3454 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3455 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState);
3456 if (m_unpackAlignment != 1)
3457 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3460 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3461 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState)
3463 if (isContextLost() || !validateHTMLImageElement("texImage2D", image, exceptionState))
3466 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3467 if (imageForRender->isSVGImage())
3468 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texImage2D");
3470 if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0))
3473 texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3476 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3477 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
3479 if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, exceptionState) || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0))
3482 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3484 // If possible, copy from the canvas element directly to the texture
3485 // via the GPU, without a read-back to system memory.
3486 if (GL_TEXTURE_2D == target && texture) {
3487 ScopedTexture2DRestorer restorer(this);
3489 if (!canvas->is3D()) {
3490 ImageBuffer* buffer = canvas->buffer();
3491 if (buffer && buffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type,
3492 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3493 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3497 WebGLRenderingContextBase* gl = toWebGLRenderingContextBase(canvas->renderingContext());
3498 ScopedTexture2DRestorer restorer(gl);
3499 if (gl && gl->m_drawingBuffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type,
3500 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3501 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type);
3507 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData();
3509 texImage2D(target, level, internalformat, format, type, imageData.get(), exceptionState);
3511 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3514 PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy)
3516 IntSize size(video->videoWidth(), video->videoHeight());
3517 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size);
3519 synthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
3522 IntRect destRect(0, 0, size.width(), size.height());
3523 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback.
3524 video->paintCurrentFrameInContext(buf->context(), destRect);
3525 return buf->copyImage(backingStoreCopy);
3528 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat,
3529 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState)
3531 if (isContextLost() || !validateHTMLVideoElement("texImage2D", video, exceptionState)
3532 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 0, format, type, 0, 0))
3535 // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible.
3536 // Otherwise, it will fall back to the normal SW path.
3537 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true);
3538 if (GL_TEXTURE_2D == target && texture) {
3539 if (video->copyVideoTextureToPlatformTexture(webContext(), texture->object(), level, type, internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) {
3540 texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type);
3545 // Normal pure SW path.
3546 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode());
3549 texImage2DImpl(target, level, internalformat, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3552 void WebGLRenderingContextBase::texParameter(GLenum target, GLenum pname, GLfloat paramf, GLint parami, bool isFloat)
3554 if (isContextLost())
3556 WebGLTexture* tex = validateTextureBinding("texParameter", target, false);
3560 case GL_TEXTURE_MIN_FILTER:
3561 case GL_TEXTURE_MAG_FILTER:
3563 case GL_TEXTURE_WRAP_S:
3564 case GL_TEXTURE_WRAP_T:
3565 if ((isFloat && paramf != GL_CLAMP_TO_EDGE && paramf != GL_MIRRORED_REPEAT && paramf != GL_REPEAT)
3566 || (!isFloat && parami != GL_CLAMP_TO_EDGE && parami != GL_MIRRORED_REPEAT && parami != GL_REPEAT)) {
3567 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter");
3571 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic
3572 if (!extensionEnabled(EXTTextureFilterAnisotropicName)) {
3573 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled");
3578 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter name");
3582 tex->setParameterf(pname, paramf);
3583 webContext()->texParameterf(target, pname, paramf);
3585 tex->setParameteri(pname, parami);
3586 webContext()->texParameteri(target, pname, parami);
3590 void WebGLRenderingContextBase::texParameterf(GLenum target, GLenum pname, GLfloat param)
3592 texParameter(target, pname, param, 0, true);
3595 void WebGLRenderingContextBase::texParameteri(GLenum target, GLenum pname, GLint param)
3597 texParameter(target, pname, 0, param, false);
3600 void WebGLRenderingContextBase::texSubImage2DBase(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState)
3602 // FIXME: Handle errors.
3603 ASSERT(!isContextLost());
3604 ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type));
3605 ASSERT(validateSize("texSubImage2D", xoffset, yoffset));
3606 ASSERT(validateSettableTexFormat("texSubImage2D", format));
3607 WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true);
3609 ASSERT_NOT_REACHED();
3612 ASSERT((xoffset + width) >= 0);
3613 ASSERT((yoffset + height) >= 0);
3614 ASSERT(tex->getWidth(target, level) >= (xoffset + width));
3615 ASSERT(tex->getHeight(target, level) >= (yoffset + height));
3616 ASSERT(tex->getInternalFormat(target, level) == format);
3617 ASSERT(tex->getType(target, level) == type);
3618 webContext()->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
3621 void WebGLRenderingContextBase::texSubImage2DImpl(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionState& exceptionState)
3623 // All calling functions check isContextLost, so a duplicate check is not needed here.
3624 Vector<uint8_t> data;
3625 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE);
3626 if (!imageExtractor.extractSucceeded()) {
3627 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image");
3630 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat();
3631 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp();
3632 const void* imagePixelData = imageExtractor.imagePixelData();
3634 bool needConversion = true;
3635 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY)
3636 needConversion = false;
3638 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) {
3639 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data");
3644 if (m_unpackAlignment != 1)
3645 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3646 texSubImage2DBase(target, level, xoffset, yoffset, imageExtractor.imageWidth(), imageExtractor.imageHeight(), format, type, needConversion ? data.data() : imagePixelData, exceptionState);
3647 if (m_unpackAlignment != 1)
3648 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3651 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3652 GLsizei width, GLsizei height,
3653 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState)
3655 if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed)
3656 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset))
3658 void* data = pixels->baseAddress();
3659 Vector<uint8_t> tempData;
3660 bool changeUnpackAlignment = false;
3661 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) {
3662 if (!WebGLImageConversion::extractTextureData(width, height, format, type,
3664 m_unpackFlipY, m_unpackPremultiplyAlpha,
3668 data = tempData.data();
3669 changeUnpackAlignment = true;
3671 if (changeUnpackAlignment)
3672 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3673 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, exceptionState);
3674 if (changeUnpackAlignment)
3675 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3678 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3679 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState)
3681 if (isContextLost() || !pixels || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, format, pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset))
3684 Vector<uint8_t> data;
3685 bool needConversion = true;
3686 // The data from ImageData is always of format RGBA8.
3687 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required.
3688 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha)
3689 needConversion = false;
3691 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) {
3692 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data");
3696 if (m_unpackAlignment != 1)
3697 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1);
3698 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState);
3699 if (m_unpackAlignment != 1)
3700 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment);
3703 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3704 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState)
3706 if (isContextLost() || !validateHTMLImageElement("texSubImage2D", image, exceptionState))
3709 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer());
3710 if (imageForRender->isSVGImage())
3711 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texSubImage2D");
3713 if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset))
3716 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3719 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3720 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
3722 if (isContextLost() || !validateHTMLCanvasElement("texSubImage2D", canvas, exceptionState)
3723 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset))
3726 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData();
3728 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), exceptionState);
3730 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3733 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
3734 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState)
3736 if (isContextLost() || !validateHTMLVideoElement("texSubImage2D", video, exceptionState)
3737 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset))
3740 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode());
3743 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState);
3746 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GLfloat x)
3748 if (isContextLost() || !location)
3751 if (location->program() != m_currentProgram) {
3752 synthesizeGLError(GL_INVALID_OPERATION, "uniform1f", "location not for current program");
3756 webContext()->uniform1f(location->location(), x);
3759 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, Float32Array* v)
3761 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, 1))
3764 webContext()->uniform1fv(location->location(), v->length(), v->data());
3767 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3769 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, size, 1))
3772 webContext()->uniform1fv(location->location(), size, v);
3775 void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location, GLint x)
3777 if (isContextLost() || !location)
3780 if (location->program() != m_currentProgram) {
3781 synthesizeGLError(GL_INVALID_OPERATION, "uniform1i", "location not for current program");
3785 webContext()->uniform1i(location->location(), x);
3788 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, Int32Array* v)
3790 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, 1))
3793 webContext()->uniform1iv(location->location(), v->length(), v->data());
3796 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3798 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, size, 1))
3801 webContext()->uniform1iv(location->location(), size, v);
3804 void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location, GLfloat x, GLfloat y)
3806 if (isContextLost() || !location)
3809 if (location->program() != m_currentProgram) {
3810 synthesizeGLError(GL_INVALID_OPERATION, "uniform2f", "location not for current program");
3814 webContext()->uniform2f(location->location(), x, y);
3817 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, Float32Array* v)
3819 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, 2))
3822 webContext()->uniform2fv(location->location(), v->length() / 2, v->data());
3825 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3827 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, size, 2))
3830 webContext()->uniform2fv(location->location(), size / 2, v);
3833 void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location, GLint x, GLint y)
3835 if (isContextLost() || !location)
3838 if (location->program() != m_currentProgram) {
3839 synthesizeGLError(GL_INVALID_OPERATION, "uniform2i", "location not for current program");
3843 webContext()->uniform2i(location->location(), x, y);
3846 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, Int32Array* v)
3848 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, 2))
3851 webContext()->uniform2iv(location->location(), v->length() / 2, v->data());
3854 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3856 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, size, 2))
3859 webContext()->uniform2iv(location->location(), size / 2, v);
3862 void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z)
3864 if (isContextLost() || !location)
3867 if (location->program() != m_currentProgram) {
3868 synthesizeGLError(GL_INVALID_OPERATION, "uniform3f", "location not for current program");
3872 webContext()->uniform3f(location->location(), x, y, z);
3875 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, Float32Array* v)
3877 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, 3))
3880 webContext()->uniform3fv(location->location(), v->length() / 3, v->data());
3883 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3885 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, size, 3))
3888 webContext()->uniform3fv(location->location(), size / 3, v);
3891 void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z)
3893 if (isContextLost() || !location)
3896 if (location->program() != m_currentProgram) {
3897 synthesizeGLError(GL_INVALID_OPERATION, "uniform3i", "location not for current program");
3901 webContext()->uniform3i(location->location(), x, y, z);
3904 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, Int32Array* v)
3906 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, 3))
3909 webContext()->uniform3iv(location->location(), v->length() / 3, v->data());
3912 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3914 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, size, 3))
3917 webContext()->uniform3iv(location->location(), size / 3, v);
3920 void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
3922 if (isContextLost() || !location)
3925 if (location->program() != m_currentProgram) {
3926 synthesizeGLError(GL_INVALID_OPERATION, "uniform4f", "location not for current program");
3930 webContext()->uniform4f(location->location(), x, y, z, w);
3933 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, Float32Array* v)
3935 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, 4))
3938 webContext()->uniform4fv(location->location(), v->length() / 4, v->data());
3941 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size)
3943 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, size, 4))
3946 webContext()->uniform4fv(location->location(), size / 4, v);
3949 void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z, GLint w)
3951 if (isContextLost() || !location)
3954 if (location->program() != m_currentProgram) {
3955 synthesizeGLError(GL_INVALID_OPERATION, "uniform4i", "location not for current program");
3959 webContext()->uniform4i(location->location(), x, y, z, w);
3962 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, Int32Array* v)
3964 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, 4))
3967 webContext()->uniform4iv(location->location(), v->length() / 4, v->data());
3970 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, GLint* v, GLsizei size)
3972 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, size, 4))
3975 webContext()->uniform4iv(location->location(), size / 4, v);
3978 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
3980 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4))
3982 webContext()->uniformMatrix2fv(location->location(), v->length() / 4, transpose, v->data());
3985 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
3987 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4))
3989 webContext()->uniformMatrix2fv(location->location(), size / 4, transpose, v);
3992 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
3994 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9))
3996 webContext()->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data());
3999 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
4001 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9))
4003 webContext()->uniformMatrix3fv(location->location(), size / 9, transpose, v);
4006 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v)
4008 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16))
4010 webContext()->uniformMatrix4fv(location->location(), v->length() / 16, transpose, v->data());
4013 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size)
4015 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16))
4017 webContext()->uniformMatrix4fv(location->location(), size / 16, transpose, v);
4020 void WebGLRenderingContextBase::useProgram(WebGLProgram* program)
4023 if (!checkObjectToBeBound("useProgram", program, deleted))
4027 if (program && !program->linkStatus()) {
4028 synthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid");
4031 if (m_currentProgram != program) {
4032 if (m_currentProgram)
4033 m_currentProgram->onDetached(webContext());
4034 m_currentProgram = program;
4035 webContext()->useProgram(objectOrZero(program));
4037 program->onAttached();
4041 void WebGLRenderingContextBase::validateProgram(WebGLProgram* program)
4043 if (isContextLost() || !validateWebGLObject("validateProgram", program))
4045 webContext()->validateProgram(objectOrZero(program));
4048 void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0)
4050 vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f);
4053 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, Float32Array* v)
4055 vertexAttribfvImpl("vertexAttrib1fv", index, v, 1);
4058 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, GLfloat* v, GLsizei size)
4060 vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1);
4063 void WebGLRenderingContextBase::vertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1)
4065 vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f);
4068 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, Float32Array* v)
4070 vertexAttribfvImpl("vertexAttrib2fv", index, v, 2);
4073 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, GLfloat* v, GLsizei size)
4075 vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2);
4078 void WebGLRenderingContextBase::vertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2)
4080 vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f);
4083 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, Float32Array* v)
4085 vertexAttribfvImpl("vertexAttrib3fv", index, v, 3);
4088 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, GLfloat* v, GLsizei size)
4090 vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3);
4093 void WebGLRenderingContextBase::vertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
4095 vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3);
4098 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, Float32Array* v)
4100 vertexAttribfvImpl("vertexAttrib4fv", index, v, 4);
4103 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, GLfloat* v, GLsizei size)
4105 vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4);
4108 void WebGLRenderingContextBase::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset)
4110 if (isContextLost())
4114 case GL_UNSIGNED_BYTE:
4116 case GL_UNSIGNED_SHORT:
4120 synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type");
4123 if (index >= m_maxVertexAttribs) {
4124 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "index out of range");
4127 if (size < 1 || size > 4 || stride < 0 || stride > 255) {
4128 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "bad size or stride");
4131 if (!validateValueFitNonNegInt32("vertexAttribPointer", "offset", offset))
4133 if (!m_boundArrayBuffer) {
4134 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER");
4137 // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride
4138 unsigned typeSize = sizeInBytes(type);
4140 synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type");
4143 if ((stride % typeSize) || (static_cast<GLintptr>(offset) % typeSize)) {
4144 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type");
4147 GLsizei bytesPerElement = size * typeSize;
4149 m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer);
4150 webContext()->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GLintptr>(offset));
4153 void WebGLRenderingContextBase::vertexAttribDivisorANGLE(GLuint index, GLuint divisor)
4155 if (isContextLost())
4158 if (index >= m_maxVertexAttribs) {
4159 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribDivisorANGLE", "index out of range");
4163 m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor);
4164 webContext()->vertexAttribDivisorANGLE(index, divisor);
4167 void WebGLRenderingContextBase::viewport(GLint x, GLint y, GLsizei width, GLsizei height)
4169 if (isContextLost())
4171 if (!validateSize("viewport", width, height))
4173 webContext()->viewport(x, y, width, height);
4176 void WebGLRenderingContextBase::forceLostContext(WebGLRenderingContextBase::LostContextMode mode)
4178 if (isContextLost()) {
4179 synthesizeGLError(GL_INVALID_OPERATION, "loseContext", "context already lost");
4183 m_contextGroup->loseContextGroup(mode);
4186 void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode)
4188 if (isContextLost())
4191 m_contextLost = true;
4192 m_contextLostMode = mode;
4194 if (mode == RealLostContext) {
4195 // Inform the embedder that a lost context was received. In response, the embedder might
4196 // decide to take action such as asking the user for permission to use WebGL again.
4197 if (LocalFrame* frame = canvas()->document().frame())
4198 frame->loader().client()->didLoseWebGLContext(webContext()->getGraphicsResetStatusARB());
4201 // Make absolutely sure we do not refer to an already-deleted texture or framebuffer.
4202 m_drawingBuffer->setTexture2DBinding(0);
4203 m_drawingBuffer->setFramebufferBinding(0);
4205 detachAndRemoveAllObjects();
4207 // Lose all the extensions.
4208 for (size_t i = 0; i < m_extensions.size(); ++i) {
4209 ExtensionTracker* tracker = m_extensions[i];
4210 tracker->loseExtension();
4213 for (size_t i = 0; i < WebGLExtensionNameCount; ++i)
4214 m_extensionEnabled[i] = false;
4216 removeAllCompressedTextureFormats();
4218 if (mode != RealLostContext)
4221 ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole;
4222 synthesizeGLError(GC3D_CONTEXT_LOST_WEBGL, "loseContext", "context lost", display);
4224 // Don't allow restoration unless the context lost event has both been
4225 // dispatched and its default behavior prevented.
4226 m_restoreAllowed = false;
4228 // Always defer the dispatch of the context lost event, to implement
4229 // the spec behavior of queueing a task.
4230 m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE);
4233 void WebGLRenderingContextBase::forceRestoreContext()
4235 if (!isContextLost()) {
4236 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context not lost");
4240 if (!m_restoreAllowed) {
4241 if (m_contextLostMode == SyntheticLostContext)
4242 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context restoration not allowed");
4246 if (!m_restoreTimer.isActive())
4247 m_restoreTimer.startOneShot(0, FROM_HERE);
4250 blink::WebLayer* WebGLRenderingContextBase::platformLayer() const
4252 return isContextLost() ? 0 : m_drawingBuffer->platformLayer();
4255 Extensions3DUtil* WebGLRenderingContextBase::extensionsUtil()
4257 ASSERT(!isContextLost());
4258 if (!m_extensionsUtil)
4259 m_extensionsUtil = Extensions3DUtil::create(webContext());
4260 return m_extensionsUtil.get();
4263 void WebGLRenderingContextBase::removeSharedObject(WebGLSharedObject* object)
4265 m_contextGroup->removeObject(object);
4268 void WebGLRenderingContextBase::addSharedObject(WebGLSharedObject* object)
4270 ASSERT(!isContextLost());
4271 m_contextGroup->addObject(object);
4274 void WebGLRenderingContextBase::removeContextObject(WebGLContextObject* object)
4276 m_contextObjects.remove(object);
4279 void WebGLRenderingContextBase::addContextObject(WebGLContextObject* object)
4281 ASSERT(!isContextLost());
4282 m_contextObjects.add(object);
4285 void WebGLRenderingContextBase::detachAndRemoveAllObjects()
4287 while (m_contextObjects.size() > 0) {
4288 HashSet<WebGLContextObject*>::iterator it = m_contextObjects.begin();
4289 (*it)->detachContext();
4293 bool WebGLRenderingContextBase::hasPendingActivity() const
4298 void WebGLRenderingContextBase::stop()
4300 if (!isContextLost()) {
4301 forceLostContext(SyntheticLostContext);
4306 WebGLGetInfo WebGLRenderingContextBase::getBooleanParameter(GLenum pname)
4308 GLboolean value = 0;
4309 if (!isContextLost())
4310 webContext()->getBooleanv(pname, &value);
4311 return WebGLGetInfo(static_cast<bool>(value));
4314 WebGLGetInfo WebGLRenderingContextBase::getBooleanArrayParameter(GLenum pname)
4316 if (pname != GL_COLOR_WRITEMASK) {
4318 return WebGLGetInfo(0, 0);
4320 GLboolean value[4] = {0};
4321 if (!isContextLost())
4322 webContext()->getBooleanv(pname, value);
4324 for (int ii = 0; ii < 4; ++ii)
4325 boolValue[ii] = static_cast<bool>(value[ii]);
4326 return WebGLGetInfo(boolValue, 4);
4329 WebGLGetInfo WebGLRenderingContextBase::getFloatParameter(GLenum pname)
4332 if (!isContextLost())
4333 webContext()->getFloatv(pname, &value);
4334 return WebGLGetInfo(value);
4337 WebGLGetInfo WebGLRenderingContextBase::getIntParameter(GLenum pname)
4340 if (!isContextLost())
4341 webContext()->getIntegerv(pname, &value);
4342 return WebGLGetInfo(value);
4345 WebGLGetInfo WebGLRenderingContextBase::getUnsignedIntParameter(GLenum pname)
4348 if (!isContextLost())
4349 webContext()->getIntegerv(pname, &value);
4350 return WebGLGetInfo(static_cast<unsigned>(value));
4353 WebGLGetInfo WebGLRenderingContextBase::getWebGLFloatArrayParameter(GLenum pname)
4355 GLfloat value[4] = {0};
4356 if (!isContextLost())
4357 webContext()->getFloatv(pname, value);
4358 unsigned length = 0;
4360 case GL_ALIASED_POINT_SIZE_RANGE:
4361 case GL_ALIASED_LINE_WIDTH_RANGE:
4362 case GL_DEPTH_RANGE:
4365 case GL_BLEND_COLOR:
4366 case GL_COLOR_CLEAR_VALUE:
4372 return WebGLGetInfo(Float32Array::create(value, length));
4375 WebGLGetInfo WebGLRenderingContextBase::getWebGLIntArrayParameter(GLenum pname)
4377 GLint value[4] = {0};
4378 if (!isContextLost())
4379 webContext()->getIntegerv(pname, value);
4380 unsigned length = 0;
4382 case GL_MAX_VIEWPORT_DIMS:
4385 case GL_SCISSOR_BOX:
4392 return WebGLGetInfo(Int32Array::create(value, length));
4395 void WebGLRenderingContextBase::handleTextureCompleteness(const char* functionName, bool prepareToDraw)
4397 // All calling functions check isContextLost, so a duplicate check is not needed here.
4398 bool resetActiveUnit = false;
4399 WebGLTexture::TextureExtensionFlag flag = static_cast<WebGLTexture::TextureExtensionFlag>((extensionEnabled(OESTextureFloatLinearName) ? WebGLTexture::TextureFloatLinearExtensionEnabled : 0)
4400 | (extensionEnabled(OESTextureHalfFloatLinearName) ? WebGLTexture::TextureHalfFloatLinearExtensionEnabled : 0));
4401 for (unsigned ii = 0; ii < m_onePlusMaxNonDefaultTextureUnit; ++ii) {
4402 if ((m_textureUnits[ii].m_texture2DBinding.get() && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
4403 || (m_textureUnits[ii].m_textureCubeMapBinding.get() && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))) {
4404 if (ii != m_activeTextureUnit) {
4405 webContext()->activeTexture(ii);
4406 resetActiveUnit = true;
4407 } else if (resetActiveUnit) {
4408 webContext()->activeTexture(ii);
4409 resetActiveUnit = false;
4411 WebGLTexture* tex2D;
4412 WebGLTexture* texCubeMap;
4413 if (prepareToDraw) {
4414 String msg(String("texture bound to texture unit ") + String::number(ii)
4415 + " is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'."
4416 + " Or the texture is Float or Half Float type with linear filtering while OES_float_linear or OES_half_float_linear extension is not enabled.");
4417 emitGLWarning(functionName, msg.utf8().data());
4418 tex2D = m_blackTexture2D.get();
4419 texCubeMap = m_blackTextureCubeMap.get();
4421 tex2D = m_textureUnits[ii].m_texture2DBinding.get();
4422 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get();
4424 if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag))
4425 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(tex2D));
4426 if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))
4427 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, objectOrZero(texCubeMap));
4430 if (resetActiveUnit)
4431 webContext()->activeTexture(m_activeTextureUnit);
4434 void WebGLRenderingContextBase::createFallbackBlackTextures1x1()
4436 // All calling functions check isContextLost, so a duplicate check is not needed here.
4437 unsigned char black[] = {0, 0, 0, 255};
4438 m_blackTexture2D = createTexture();
4439 webContext()->bindTexture(GL_TEXTURE_2D, m_blackTexture2D->object());
4440 webContext()->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
4441 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4442 webContext()->bindTexture(GL_TEXTURE_2D, 0);
4443 m_blackTextureCubeMap = createTexture();
4444 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object());
4445 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 1, 1,
4446 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4447 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 1, 1,
4448 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4449 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 1, 1,
4450 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4451 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 1, 1,
4452 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4453 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 1, 1,
4454 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4455 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 1, 1,
4456 0, GL_RGBA, GL_UNSIGNED_BYTE, black);
4457 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, 0);
4460 bool WebGLRenderingContextBase::isTexInternalFormatColorBufferCombinationValid(GLenum texInternalFormat, GLenum colorBufferFormat)
4462 unsigned need = WebGLImageConversion::getChannelBitsByFormat(texInternalFormat);
4463 unsigned have = WebGLImageConversion::getChannelBitsByFormat(colorBufferFormat);
4464 return (need & have) == need;
4467 GLenum WebGLRenderingContextBase::boundFramebufferColorFormat()
4469 if (m_framebufferBinding && m_framebufferBinding->object())
4470 return m_framebufferBinding->colorBufferFormat();
4471 if (m_requestedAttributes->alpha())
4476 WebGLTexture* WebGLRenderingContextBase::validateTextureBinding(const char* functionName, GLenum target, bool useSixEnumsForCubeMap)
4478 WebGLTexture* tex = 0;
4481 tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get();
4483 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4484 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4485 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4486 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4487 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4488 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4489 if (!useSixEnumsForCubeMap) {
4490 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4493 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4495 case GL_TEXTURE_CUBE_MAP:
4496 if (useSixEnumsForCubeMap) {
4497 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4500 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get();
4503 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target");
4507 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no texture");
4511 bool WebGLRenderingContextBase::validateLocationLength(const char* functionName, const String& string)
4513 const unsigned maxWebGLLocationLength = 256;
4514 if (string.length() > maxWebGLLocationLength) {
4515 synthesizeGLError(GL_INVALID_VALUE, functionName, "location length > 256");
4521 bool WebGLRenderingContextBase::validateSize(const char* functionName, GLint x, GLint y)
4523 if (x < 0 || y < 0) {
4524 synthesizeGLError(GL_INVALID_VALUE, functionName, "size < 0");
4530 bool WebGLRenderingContextBase::validateString(const char* functionName, const String& string)
4532 for (size_t i = 0; i < string.length(); ++i) {
4533 if (!validateCharacter(string[i])) {
4534 synthesizeGLError(GL_INVALID_VALUE, functionName, "string not ASCII");
4541 bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GLenum format, GLenum type, GLint level)
4546 case GL_LUMINANCE_ALPHA:
4550 case GL_DEPTH_STENCIL_OES:
4551 case GL_DEPTH_COMPONENT:
4552 if (extensionEnabled(WebGLDepthTextureName))
4554 synthesizeGLError(GL_INVALID_ENUM, functionName, "depth texture formats not enabled");
4557 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture format");
4562 case GL_UNSIGNED_BYTE:
4563 case GL_UNSIGNED_SHORT_5_6_5:
4564 case GL_UNSIGNED_SHORT_4_4_4_4:
4565 case GL_UNSIGNED_SHORT_5_5_5_1:
4568 if (extensionEnabled(OESTextureFloatName))
4570 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4572 case GL_HALF_FLOAT_OES:
4573 if (extensionEnabled(OESTextureHalfFloatName))
4575 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4577 case GL_UNSIGNED_INT:
4578 case GL_UNSIGNED_INT_24_8_OES:
4579 case GL_UNSIGNED_SHORT:
4580 if (extensionEnabled(WebGLDepthTextureName))
4582 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4585 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type");
4589 // Verify that the combination of format and type is supported.
4593 case GL_LUMINANCE_ALPHA:
4594 if (type != GL_UNSIGNED_BYTE
4596 && type != GL_HALF_FLOAT_OES) {
4597 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for format");
4602 if (type != GL_UNSIGNED_BYTE
4603 && type != GL_UNSIGNED_SHORT_5_6_5
4605 && type != GL_HALF_FLOAT_OES) {
4606 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGB format");
4611 if (type != GL_UNSIGNED_BYTE
4612 && type != GL_UNSIGNED_SHORT_4_4_4_4
4613 && type != GL_UNSIGNED_SHORT_5_5_5_1
4615 && type != GL_HALF_FLOAT_OES) {
4616 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGBA format");
4620 case GL_DEPTH_COMPONENT:
4621 if (!extensionEnabled(WebGLDepthTextureName)) {
4622 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled");
4625 if (type != GL_UNSIGNED_SHORT
4626 && type != GL_UNSIGNED_INT) {
4627 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format");
4631 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format");
4635 case GL_DEPTH_STENCIL_OES:
4636 if (!extensionEnabled(WebGLDepthTextureName)) {
4637 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled");
4640 if (type != GL_UNSIGNED_INT_24_8_OES) {
4641 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format");
4645 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format");
4650 ASSERT_NOT_REACHED();
4656 bool WebGLRenderingContextBase::validateTexFuncLevel(const char* functionName, GLenum target, GLint level)
4659 synthesizeGLError(GL_INVALID_VALUE, functionName, "level < 0");
4664 if (level >= m_maxTextureLevel) {
4665 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range");
4669 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4670 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4671 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4672 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4673 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4674 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4675 if (level >= m_maxCubeMapTextureLevel) {
4676 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range");
4681 // This function only checks if level is legal, so we return true and don't
4682 // generate INVALID_ENUM if target is illegal.
4686 bool WebGLRenderingContextBase::validateTexFuncDimensions(const char* functionName, TexFuncValidationFunctionType functionType,
4687 GLenum target, GLint level, GLsizei width, GLsizei height)
4689 if (width < 0 || height < 0) {
4690 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0");
4696 if (width > (m_maxTextureSize >> level) || height > (m_maxTextureSize >> level)) {
4697 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range");
4701 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4702 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4703 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4704 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4705 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4706 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4707 if (functionType != TexSubImage2D && width != height) {
4708 synthesizeGLError(GL_INVALID_VALUE, functionName, "width != height for cube map");
4711 // No need to check height here. For texImage width == height.
4712 // For texSubImage that will be checked when checking yoffset + height is in range.
4713 if (width > (m_maxCubeMapTextureSize >> level)) {
4714 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range for cube map");
4719 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
4725 bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target,
4726 GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type)
4728 // We absolutely have to validate the format and type combination.
4729 // The texImage2D entry points taking HTMLImage, etc. will produce
4730 // temporary data based on this combination, so it must be legal.
4731 if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level))
4734 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
4737 if (format != internalformat) {
4738 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format != internalformat");
4743 synthesizeGLError(GL_INVALID_VALUE, functionName, "border != 0");
4750 bool WebGLRenderingContextBase::validateTexFuncData(const char* functionName, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels, NullDisposition disposition)
4752 // All calling functions check isContextLost, so a duplicate check is not needed here.
4754 if (disposition == NullAllowed)
4756 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels");
4760 if (!validateTexFuncFormatAndType(functionName, format, type, level))
4762 if (!validateSettableTexFormat(functionName, format))
4766 case GL_UNSIGNED_BYTE:
4767 if (pixels->type() != ArrayBufferView::TypeUint8) {
4768 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array");
4772 case GL_UNSIGNED_SHORT_5_6_5:
4773 case GL_UNSIGNED_SHORT_4_4_4_4:
4774 case GL_UNSIGNED_SHORT_5_5_5_1:
4775 if (pixels->type() != ArrayBufferView::TypeUint16) {
4776 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
4780 case GL_FLOAT: // OES_texture_float
4781 if (pixels->type() != ArrayBufferView::TypeFloat32) {
4782 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array");
4786 case GL_HALF_FLOAT_OES: // OES_texture_half_float
4787 // As per the specification, ArrayBufferView should be null or a Uint16Array when
4788 // OES_texture_half_float is enabled.
4789 if (pixels && pixels->type() != ArrayBufferView::TypeUint16) {
4790 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL and not Uint16Array");
4795 ASSERT_NOT_REACHED();
4798 unsigned totalBytesRequired;
4799 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0);
4800 if (error != GL_NO_ERROR) {
4801 synthesizeGLError(error, functionName, "invalid texture dimensions");
4804 if (pixels->byteLength() < totalBytesRequired) {
4805 if (m_unpackAlignment != 1) {
4806 error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0);
4807 if (pixels->byteLength() == totalBytesRequired) {
4808 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1");
4812 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request");
4818 bool WebGLRenderingContextBase::validateCompressedTexFormat(GLenum format)
4820 return m_compressedTextureFormats.contains(format);
4823 bool WebGLRenderingContextBase::validateCompressedTexFuncData(const char* functionName, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* pixels)
4826 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels");
4829 if (width < 0 || height < 0) {
4830 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0");
4834 unsigned bytesRequired = 0;
4837 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4838 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4840 const int kBlockWidth = 4;
4841 const int kBlockHeight = 4;
4842 const int kBlockSize = 8;
4843 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
4844 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
4845 int numBlocks = numBlocksAcross * numBlocksDown;
4846 bytesRequired = numBlocks * kBlockSize;
4849 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4850 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
4852 const int kBlockWidth = 4;
4853 const int kBlockHeight = 4;
4854 const int kBlockSize = 16;
4855 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
4856 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
4857 int numBlocks = numBlocksAcross * numBlocksDown;
4858 bytesRequired = numBlocks * kBlockSize;
4861 case GC3D_COMPRESSED_ATC_RGB_AMD:
4862 case GL_ETC1_RGB8_OES:
4864 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 8;
4867 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
4868 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
4870 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 16;
4873 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
4874 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
4876 bytesRequired = (max(width, 8) * max(height, 8) * 4 + 7) / 8;
4879 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
4880 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
4882 bytesRequired = (max(width, 16) * max(height, 8) * 2 + 7) / 8;
4886 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format");
4890 if (pixels->byteLength() != bytesRequired) {
4891 synthesizeGLError(GL_INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions");
4898 bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format)
4900 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
4903 bool widthValid = false;
4904 bool heightValid = false;
4907 case GC3D_COMPRESSED_ATC_RGB_AMD:
4908 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
4909 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
4910 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4911 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4912 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4913 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
4914 const int kBlockWidth = 4;
4915 const int kBlockHeight = 4;
4916 widthValid = (level && width == 1) || (level && width == 2) || !(width % kBlockWidth);
4917 heightValid = (level && height == 1) || (level && height == 2) || !(height % kBlockHeight);
4920 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
4921 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
4922 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
4923 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
4924 // Must be a power of two
4925 widthValid = (width & (width - 1)) == 0;
4926 heightValid = (height & (height - 1)) == 0;
4929 case GL_ETC1_RGB8_OES: {
4938 if (!widthValid || !heightValid) {
4939 synthesizeGLError(GL_INVALID_OPERATION, functionName, "width or height invalid for level");
4946 bool WebGLRenderingContextBase::validateCompressedTexSubDimensions(const char* functionName, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, WebGLTexture* tex)
4948 if (xoffset < 0 || yoffset < 0) {
4949 synthesizeGLError(GL_INVALID_VALUE, functionName, "xoffset or yoffset < 0");
4954 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4955 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4956 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4957 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
4958 const int kBlockWidth = 4;
4959 const int kBlockHeight = 4;
4960 if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
4961 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4");
4964 if (width - xoffset > tex->getWidth(target, level)
4965 || height - yoffset > tex->getHeight(target, level)) {
4966 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions out of range");
4969 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format);
4971 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
4972 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
4973 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
4974 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
4975 if ((xoffset != 0) || (yoffset != 0)) {
4976 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset and yoffset must be zero");
4979 if (width != tex->getWidth(target, level)
4980 || height != tex->getHeight(target, level)) {
4981 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions must match existing level");
4984 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format);
4986 case GC3D_COMPRESSED_ATC_RGB_AMD:
4987 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD:
4988 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
4989 case GL_ETC1_RGB8_OES: {
4990 synthesizeGLError(GL_INVALID_OPERATION, functionName, "unable to update sub-images with this format");
4998 bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GLenum mode)
5005 case GL_TRIANGLE_STRIP:
5006 case GL_TRIANGLE_FAN:
5010 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid draw mode");
5015 bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName)
5017 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) {
5018 synthesizeGLError(GL_INVALID_OPERATION, functionName, "front and back stencils settings do not match");
5024 bool WebGLRenderingContextBase::validateStencilOrDepthFunc(const char* functionName, GLenum func)
5037 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid function");
5042 void WebGLRenderingContextBase::printGLErrorToConsole(const String& message)
5044 if (!m_numGLErrorsToConsoleAllowed)
5047 --m_numGLErrorsToConsoleAllowed;
5048 printWarningToConsole(message);
5050 if (!m_numGLErrorsToConsoleAllowed)
5051 printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context.");
5056 void WebGLRenderingContextBase::printWarningToConsole(const String& message)
5060 canvas()->document().addConsoleMessage(RenderingMessageSource, WarningMessageLevel, message);
5063 bool WebGLRenderingContextBase::validateFramebufferFuncParameters(const char* functionName, GLenum target, GLenum attachment)
5065 if (target != GL_FRAMEBUFFER) {
5066 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
5069 switch (attachment) {
5070 case GL_COLOR_ATTACHMENT0:
5071 case GL_DEPTH_ATTACHMENT:
5072 case GL_STENCIL_ATTACHMENT:
5073 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
5076 if (extensionEnabled(WebGLDrawBuffersName)
5077 && attachment > GL_COLOR_ATTACHMENT0
5078 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + maxColorAttachments()))
5080 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid attachment");
5086 bool WebGLRenderingContextBase::validateBlendEquation(const char* functionName, GLenum mode)
5090 case GL_FUNC_SUBTRACT:
5091 case GL_FUNC_REVERSE_SUBTRACT:
5094 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid mode");
5099 bool WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GLenum src, GLenum dst)
5101 if (((src == GL_CONSTANT_COLOR || src == GL_ONE_MINUS_CONSTANT_COLOR)
5102 && (dst == GL_CONSTANT_ALPHA || dst == GL_ONE_MINUS_CONSTANT_ALPHA))
5103 || ((dst == GL_CONSTANT_COLOR || dst == GL_ONE_MINUS_CONSTANT_COLOR)
5104 && (src == GL_CONSTANT_ALPHA || src == GL_ONE_MINUS_CONSTANT_ALPHA))) {
5105 synthesizeGLError(GL_INVALID_OPERATION, functionName, "incompatible src and dst");
5111 bool WebGLRenderingContextBase::validateCapability(const char* functionName, GLenum cap)
5118 case GL_POLYGON_OFFSET_FILL:
5119 case GL_SAMPLE_ALPHA_TO_COVERAGE:
5120 case GL_SAMPLE_COVERAGE:
5121 case GL_SCISSOR_TEST:
5122 case GL_STENCIL_TEST:
5125 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid capability");
5130 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GLsizei requiredMinSize)
5133 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5136 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5139 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GLsizei requiredMinSize)
5142 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5145 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize);
5148 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GLsizei size, GLsizei requiredMinSize)
5150 return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize);
5153 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v, GLsizei requiredMinSize)
5156 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5159 return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize);
5162 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, void* v, GLsizei size, GLsizei requiredMinSize)
5166 if (location->program() != m_currentProgram) {
5167 synthesizeGLError(GL_INVALID_OPERATION, functionName, "location is not from current program");
5171 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5175 synthesizeGLError(GL_INVALID_VALUE, functionName, "transpose not FALSE");
5178 if (size < requiredMinSize || (size % requiredMinSize)) {
5179 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size");
5185 WebGLBuffer* WebGLRenderingContextBase::validateBufferDataTarget(const char* functionName, GLenum target)
5187 WebGLBuffer* buffer = 0;
5189 case GL_ELEMENT_ARRAY_BUFFER:
5190 buffer = m_boundVertexArrayObject->boundElementArrayBuffer().get();
5192 case GL_ARRAY_BUFFER:
5193 buffer = m_boundArrayBuffer.get();
5196 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
5200 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no buffer");
5206 bool WebGLRenderingContextBase::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionState& exceptionState)
5208 if (!image || !image->cachedImage()) {
5209 synthesizeGLError(GL_INVALID_VALUE, functionName, "no image");
5212 const KURL& url = image->cachedImage()->response().url();
5213 if (url.isNull() || url.isEmpty() || !url.isValid()) {
5214 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid image");
5217 if (image->wouldTaintOrigin(canvas()->securityOrigin())) {
5218 exceptionState.throwSecurityError("The cross-origin image at " + url.elidedString() + " may not be loaded.");
5224 bool WebGLRenderingContextBase::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionState& exceptionState)
5226 if (!canvas || !canvas->buffer()) {
5227 synthesizeGLError(GL_INVALID_VALUE, functionName, "no canvas");
5230 if (canvas->wouldTaintOrigin(this->canvas()->securityOrigin())) {
5231 exceptionState.throwSecurityError("Tainted canvases may not be loaded.");
5237 bool WebGLRenderingContextBase::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionState& exceptionState)
5239 if (!video || !video->videoWidth() || !video->videoHeight()) {
5240 synthesizeGLError(GL_INVALID_VALUE, functionName, "no video");
5243 if (video->wouldTaintOrigin(canvas()->securityOrigin())) {
5244 exceptionState.throwSecurityError("The video element contains cross-origin data, and may not be loaded.");
5250 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count)
5252 if (isContextLost() || !validateDrawMode(functionName, mode))
5255 if (!validateStencilSettings(functionName))
5258 if (first < 0 || count < 0) {
5259 synthesizeGLError(GL_INVALID_VALUE, functionName, "first or count < 0");
5264 markContextChanged(CanvasChanged);
5268 if (!validateRenderingState(functionName)) {
5272 const char* reason = "framebuffer incomplete";
5273 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
5274 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
5281 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset)
5283 if (isContextLost() || !validateDrawMode(functionName, mode))
5286 if (!validateStencilSettings(functionName))
5290 case GL_UNSIGNED_BYTE:
5291 case GL_UNSIGNED_SHORT:
5293 case GL_UNSIGNED_INT:
5294 if (extensionEnabled(OESElementIndexUintName))
5296 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type");
5299 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type");
5304 synthesizeGLError(GL_INVALID_VALUE, functionName, "count < 0");
5307 if (!validateValueFitNonNegInt32(functionName, "offset", offset))
5311 markContextChanged(CanvasChanged);
5315 if (!m_boundVertexArrayObject->boundElementArrayBuffer()) {
5316 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound");
5320 if (!validateRenderingState(functionName)) {
5324 const char* reason = "framebuffer incomplete";
5325 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) {
5326 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason);
5333 // Helper function to validate draw*Instanced calls
5334 bool WebGLRenderingContextBase::validateDrawInstanced(const char* functionName, GLsizei primcount)
5336 if (primcount < 0) {
5337 synthesizeGLError(GL_INVALID_VALUE, functionName, "primcount < 0");
5341 // Ensure at least one enabled vertex attrib has a divisor of 0.
5342 for (unsigned i = 0; i < m_onePlusMaxEnabledAttribIndex; ++i) {
5343 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i);
5344 if (state.enabled && !state.divisor)
5348 synthesizeGLError(GL_INVALID_OPERATION, functionName, "at least one enabled attribute must have a divisor of 0");
5352 void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GLuint index, GLsizei expectedSize, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
5354 if (isContextLost())
5356 if (index >= m_maxVertexAttribs) {
5357 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range");
5360 // In GL, we skip setting vertexAttrib0 values.
5361 switch (expectedSize) {
5363 webContext()->vertexAttrib1f(index, v0);
5366 webContext()->vertexAttrib2f(index, v0, v1);
5369 webContext()->vertexAttrib3f(index, v0, v1, v2);
5372 webContext()->vertexAttrib4f(index, v0, v1, v2, v3);
5375 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5376 attribValue.value[0] = v0;
5377 attribValue.value[1] = v1;
5378 attribValue.value[2] = v2;
5379 attribValue.value[3] = v3;
5382 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, Float32Array* v, GLsizei expectedSize)
5384 if (isContextLost())
5387 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5390 vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize);
5393 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, GLfloat* v, GLsizei size, GLsizei expectedSize)
5395 if (isContextLost())
5398 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array");
5401 if (size < expectedSize) {
5402 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size");
5405 if (index >= m_maxVertexAttribs) {
5406 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range");
5409 // In GL, we skip setting vertexAttrib0 values.
5410 switch (expectedSize) {
5412 webContext()->vertexAttrib1fv(index, v);
5415 webContext()->vertexAttrib2fv(index, v);
5418 webContext()->vertexAttrib3fv(index, v);
5421 webContext()->vertexAttrib4fv(index, v);
5424 VertexAttribValue& attribValue = m_vertexAttribValue[index];
5425 attribValue.initValue();
5426 for (int ii = 0; ii < expectedSize; ++ii)
5427 attribValue.value[ii] = v[ii];
5430 void WebGLRenderingContextBase::dispatchContextLostEvent(Timer<WebGLRenderingContextBase>*)
5432 RefPtrWillBeRawPtr<WebGLContextEvent> event = WebGLContextEvent::create(EventTypeNames::webglcontextlost, false, true, "");
5433 canvas()->dispatchEvent(event);
5434 m_restoreAllowed = event->defaultPrevented();
5435 deactivateContext(this, m_contextLostMode != RealLostContext && m_restoreAllowed);
5436 if ((m_contextLostMode == RealLostContext || m_contextLostMode == AutoRecoverSyntheticLostContext) && m_restoreAllowed)
5437 m_restoreTimer.startOneShot(0, FROM_HERE);
5440 void WebGLRenderingContextBase::maybeRestoreContext(Timer<WebGLRenderingContextBase>*)
5442 ASSERT(isContextLost());
5444 // The rendering context is not restored unless the default behavior of the
5445 // webglcontextlost event was prevented earlier.
5447 // Because of the way m_restoreTimer is set up for real vs. synthetic lost
5448 // context events, we don't have to worry about this test short-circuiting
5449 // the retry loop for real context lost events.
5450 if (!m_restoreAllowed)
5453 LocalFrame* frame = canvas()->document().frame();
5457 Settings* settings = frame->settings();
5459 if (!frame->loader().client()->allowWebGL(settings && settings->webGLEnabled()))
5462 // If the context was lost due to RealLostContext, we need to destroy the old DrawingBuffer before creating new DrawingBuffer to ensure resource budget enough.
5463 if (m_drawingBuffer) {
5464 m_drawingBuffer->beginDestruction();
5465 m_drawingBuffer.clear();
5468 blink::WebGraphicsContext3D::Attributes attributes = m_requestedAttributes->attributes(canvas()->document().topDocument().url().string(), settings);
5469 OwnPtr<blink::WebGraphicsContext3D> context = adoptPtr(blink::Platform::current()->createOffscreenGraphicsContext3D(attributes, 0));
5470 RefPtr<DrawingBuffer> drawingBuffer;
5471 // Even if a non-null WebGraphicsContext3D is created, until it's made current, it isn't known whether the context is still lost.
5473 RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager());
5475 // Construct a new drawing buffer with the new WebGraphicsContext3D.
5476 DrawingBuffer::PreserveDrawingBuffer preserve = m_requestedAttributes->preserveDrawingBuffer() ? DrawingBuffer::Preserve : DrawingBuffer::Discard;
5477 drawingBuffer = DrawingBuffer::create(context.release(), clampedCanvasSize(), preserve, contextEvictionManager.release());
5478 // If DrawingBuffer::create() fails to allocate a fbo, |drawingBuffer| is set to null.
5480 if (!drawingBuffer) {
5481 if (m_contextLostMode == RealLostContext) {
5482 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts, FROM_HERE);
5484 // This likely shouldn't happen but is the best way to report it to the WebGL app.
5485 synthesizeGLError(GL_INVALID_OPERATION, "", "error restoring context");
5490 m_drawingBuffer = drawingBuffer.release();
5491 m_drawingBuffer->bind();
5492 m_lostContextErrors.clear();
5493 m_contextLost = false;
5496 initializeNewContext();
5497 markContextChanged(CanvasContextChanged);
5498 canvas()->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextrestored, false, true, ""));
5501 String WebGLRenderingContextBase::ensureNotNull(const String& text) const
5504 return WTF::emptyString();
5508 WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(int capacity)
5509 : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity]))
5510 , m_capacity(capacity)
5514 ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer(const IntSize& size)
5517 for (i = 0; i < m_capacity; ++i) {
5518 ImageBuffer* buf = m_buffers[i].get();
5521 if (buf->size() != size)
5527 OwnPtr<ImageBuffer> temp(ImageBuffer::create(size));
5530 i = std::min(m_capacity - 1, i);
5531 m_buffers[i] = temp.release();
5533 ImageBuffer* buf = m_buffers[i].get();
5538 void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx)
5540 for (int i = idx; i > 0; --i)
5541 m_buffers[i].swap(m_buffers[i-1]);
5546 String GetErrorString(GLenum error)
5549 case GL_INVALID_ENUM:
5550 return "INVALID_ENUM";
5551 case GL_INVALID_VALUE:
5552 return "INVALID_VALUE";
5553 case GL_INVALID_OPERATION:
5554 return "INVALID_OPERATION";
5555 case GL_OUT_OF_MEMORY:
5556 return "OUT_OF_MEMORY";
5557 case GL_INVALID_FRAMEBUFFER_OPERATION:
5558 return "INVALID_FRAMEBUFFER_OPERATION";
5559 case GC3D_CONTEXT_LOST_WEBGL:
5560 return "CONTEXT_LOST_WEBGL";
5562 return String::format("WebGL ERROR(0x%04X)", error);
5566 } // namespace anonymous
5568 void WebGLRenderingContextBase::synthesizeGLError(GLenum error, const char* functionName, const char* description, ConsoleDisplayPreference display)
5570 String errorType = GetErrorString(error);
5571 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) {
5572 String message = String("WebGL: ") + errorType + ": " + String(functionName) + ": " + String(description);
5573 printGLErrorToConsole(message);
5575 if (!isContextLost())
5576 webContext()->synthesizeGLError(error);
5578 if (m_lostContextErrors.find(error) == WTF::kNotFound)
5579 m_lostContextErrors.append(error);
5581 InspectorInstrumentation::didFireWebGLError(canvas(), errorType);
5584 void WebGLRenderingContextBase::emitGLWarning(const char* functionName, const char* description)
5586 if (m_synthesizedErrorsToConsole) {
5587 String message = String("WebGL: ") + String(functionName) + ": " + String(description);
5588 printGLErrorToConsole(message);
5590 InspectorInstrumentation::didFireWebGLWarning(canvas());
5593 void WebGLRenderingContextBase::applyStencilTest()
5595 bool haveStencilBuffer = false;
5597 if (m_framebufferBinding)
5598 haveStencilBuffer = m_framebufferBinding->hasStencilBuffer();
5600 RefPtr<WebGLContextAttributes> attributes = getContextAttributes();
5601 haveStencilBuffer = attributes->stencil();
5603 enableOrDisable(GL_STENCIL_TEST,
5604 m_stencilEnabled && haveStencilBuffer);
5607 void WebGLRenderingContextBase::enableOrDisable(GLenum capability, bool enable)
5609 if (isContextLost())
5612 webContext()->enable(capability);
5614 webContext()->disable(capability);
5617 IntSize WebGLRenderingContextBase::clampedCanvasSize()
5619 return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]),
5620 clamp(canvas()->height(), 1, m_maxViewportDims[1]));
5623 GLint WebGLRenderingContextBase::maxDrawBuffers()
5625 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName))
5627 if (!m_maxDrawBuffers)
5628 webContext()->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers);
5629 if (!m_maxColorAttachments)
5630 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
5631 // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
5632 return std::min(m_maxDrawBuffers, m_maxColorAttachments);
5635 GLint WebGLRenderingContextBase::maxColorAttachments()
5637 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName))
5639 if (!m_maxColorAttachments)
5640 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments);
5641 return m_maxColorAttachments;
5644 void WebGLRenderingContextBase::setBackDrawBuffer(GLenum buf)
5646 m_backDrawBuffer = buf;
5649 void WebGLRenderingContextBase::restoreCurrentFramebuffer()
5651 bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding.get());
5654 void WebGLRenderingContextBase::restoreCurrentTexture2D()
5656 bindTexture(GL_TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get());
5659 void WebGLRenderingContextBase::multisamplingChanged(bool enabled)
5661 if (m_multisamplingAllowed != enabled) {
5662 m_multisamplingAllowed = enabled;
5663 forceLostContext(WebGLRenderingContextBase::AutoRecoverSyntheticLostContext);
5667 void WebGLRenderingContextBase::findNewMaxEnabledAttribIndex()
5669 // Trace backwards from the current max to find the new max enabled attrib index
5670 int startIndex = m_onePlusMaxEnabledAttribIndex - 1;
5671 for (int i = startIndex; i >= 0; --i) {
5672 if (m_boundVertexArrayObject->getVertexAttribState(i).enabled) {
5673 m_onePlusMaxEnabledAttribIndex = i + 1;
5677 m_onePlusMaxEnabledAttribIndex = 0;
5680 void WebGLRenderingContextBase::findNewMaxNonDefaultTextureUnit()
5682 // Trace backwards from the current max to find the new max non-default texture unit
5683 int startIndex = m_onePlusMaxNonDefaultTextureUnit - 1;
5684 for (int i = startIndex; i >= 0; --i) {
5685 if (m_textureUnits[i].m_texture2DBinding
5686 || m_textureUnits[i].m_textureCubeMapBinding) {
5687 m_onePlusMaxNonDefaultTextureUnit = i + 1;
5691 m_onePlusMaxNonDefaultTextureUnit = 0;
5694 } // namespace WebCore