1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "core/html/canvas/WebGLRenderingContextBase.h" 28 29 #include "bindings/v8/ExceptionMessages.h" 30 #include "bindings/v8/ExceptionState.h" 31 #include "core/dom/ExceptionCode.h" 32 #include "core/fetch/ImageResource.h" 33 #include "core/frame/LocalFrame.h" 34 #include "core/frame/Settings.h" 35 #include "core/html/HTMLCanvasElement.h" 36 #include "core/html/HTMLImageElement.h" 37 #include "core/html/HTMLVideoElement.h" 38 #include "core/html/ImageData.h" 39 #include "core/html/canvas/ANGLEInstancedArrays.h" 40 #include "core/html/canvas/EXTBlendMinMax.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/RuntimeEnabledFeatures.h" 79 #include "platform/geometry/IntSize.h" 80 #include "platform/graphics/GraphicsContext.h" 81 #include "platform/graphics/UnacceleratedImageBufferSurface.h" 82 #include "platform/graphics/gpu/DrawingBuffer.h" 83 #include "public/platform/Platform.h" 84 85 #include "wtf/PassOwnPtr.h" 86 #include "wtf/Uint32Array.h" 87 #include "wtf/text/StringBuilder.h" 88 89 namespace WebCore { 90 91 const double secondsBetweenRestoreAttempts = 1.0; 92 const int maxGLErrorsAllowedToConsole = 256; 93 const unsigned maxGLActiveContexts = 16; 94 95 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::activeContexts() 96 { 97 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, activeContexts, ()); 98 return activeContexts; 99 } 100 101 Vector<WebGLRenderingContextBase*>& WebGLRenderingContextBase::forciblyEvictedContexts() 102 { 103 DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContextBase*>, forciblyEvictedContexts, ()); 104 return forciblyEvictedContexts; 105 } 106 107 void WebGLRenderingContextBase::forciblyLoseOldestContext(const String& reason) 108 { 109 size_t candidateID = oldestContextIndex(); 110 if (candidateID >= activeContexts().size()) 111 return; 112 113 WebGLRenderingContextBase* candidate = activeContexts()[candidateID]; 114 115 activeContexts().remove(candidateID); 116 117 candidate->printWarningToConsole(reason); 118 InspectorInstrumentation::didFireWebGLWarning(candidate->canvas()); 119 120 // This will call deactivateContext once the context has actually been lost. 121 candidate->forceLostContext(WebGLRenderingContextBase::SyntheticLostContext); 122 } 123 124 size_t WebGLRenderingContextBase::oldestContextIndex() 125 { 126 if (!activeContexts().size()) 127 return maxGLActiveContexts; 128 129 WebGLRenderingContextBase* candidate = activeContexts().first(); 130 blink::WebGraphicsContext3D* candidateWGC3D = candidate->isContextLost() ? 0 : candidate->webContext(); 131 size_t candidateID = 0; 132 for (size_t ii = 1; ii < activeContexts().size(); ++ii) { 133 WebGLRenderingContextBase* context = activeContexts()[ii]; 134 blink::WebGraphicsContext3D* contextWGC3D = context->isContextLost() ? 0 : context->webContext(); 135 if (contextWGC3D && candidateWGC3D && contextWGC3D->lastFlushID() < candidateWGC3D->lastFlushID()) { 136 candidate = context; 137 candidateID = ii; 138 } 139 } 140 141 return candidateID; 142 } 143 144 IntSize WebGLRenderingContextBase::oldestContextSize() 145 { 146 IntSize size; 147 148 size_t candidateID = oldestContextIndex(); 149 if (candidateID < activeContexts().size()) { 150 WebGLRenderingContextBase* candidate = activeContexts()[candidateID]; 151 size.setWidth(candidate->drawingBufferWidth()); 152 size.setHeight(candidate->drawingBufferHeight()); 153 } 154 155 return size; 156 } 157 158 void WebGLRenderingContextBase::activateContext(WebGLRenderingContextBase* context) 159 { 160 unsigned removedContexts = 0; 161 while (activeContexts().size() >= maxGLActiveContexts && removedContexts < maxGLActiveContexts) { 162 forciblyLoseOldestContext("WARNING: Too many active WebGL contexts. Oldest context will be lost."); 163 removedContexts++; 164 } 165 166 if (!activeContexts().contains(context)) 167 activeContexts().append(context); 168 } 169 170 void WebGLRenderingContextBase::deactivateContext(WebGLRenderingContextBase* context, bool addToEvictedList) 171 { 172 size_t position = activeContexts().find(context); 173 if (position != WTF::kNotFound) 174 activeContexts().remove(position); 175 176 if (addToEvictedList && !forciblyEvictedContexts().contains(context)) 177 forciblyEvictedContexts().append(context); 178 } 179 180 void WebGLRenderingContextBase::willDestroyContext(WebGLRenderingContextBase* context) 181 { 182 size_t position = forciblyEvictedContexts().find(context); 183 if (position != WTF::kNotFound) 184 forciblyEvictedContexts().remove(position); 185 186 deactivateContext(context, false); 187 188 // Try to re-enable the oldest inactive contexts. 189 while(activeContexts().size() < maxGLActiveContexts && forciblyEvictedContexts().size()) { 190 WebGLRenderingContextBase* evictedContext = forciblyEvictedContexts().first(); 191 if (!evictedContext->m_restoreAllowed) { 192 forciblyEvictedContexts().remove(0); 193 continue; 194 } 195 196 IntSize desiredSize = DrawingBuffer::adjustSize(evictedContext->clampedCanvasSize(), IntSize(), evictedContext->m_maxTextureSize); 197 198 // If there's room in the pixel budget for this context, restore it. 199 if (!desiredSize.isEmpty()) { 200 forciblyEvictedContexts().remove(0); 201 evictedContext->forceRestoreContext(); 202 activeContexts().append(evictedContext); 203 } 204 break; 205 } 206 } 207 208 class WebGLRenderingContextEvictionManager : public ContextEvictionManager { 209 public: 210 void forciblyLoseOldestContext(const String& reason) { 211 WebGLRenderingContextBase::forciblyLoseOldestContext(reason); 212 }; 213 IntSize oldestContextSize() { 214 return WebGLRenderingContextBase::oldestContextSize(); 215 }; 216 }; 217 218 namespace { 219 220 class ScopedDrawingBufferBinder { 221 public: 222 ScopedDrawingBufferBinder(DrawingBuffer* drawingBuffer, WebGLFramebuffer* framebufferBinding) 223 : m_drawingBuffer(drawingBuffer) 224 , m_framebufferBinding(framebufferBinding) 225 { 226 // Commit DrawingBuffer if needed (e.g., for multisampling) 227 if (!m_framebufferBinding && m_drawingBuffer) 228 m_drawingBuffer->commit(); 229 } 230 231 ~ScopedDrawingBufferBinder() 232 { 233 // Restore DrawingBuffer if needed 234 if (!m_framebufferBinding && m_drawingBuffer) 235 m_drawingBuffer->bind(); 236 } 237 238 private: 239 DrawingBuffer* m_drawingBuffer; 240 WebGLFramebuffer* m_framebufferBinding; 241 }; 242 243 Platform3DObject objectOrZero(WebGLObject* object) 244 { 245 return object ? object->object() : 0; 246 } 247 248 GLint clamp(GLint value, GLint min, GLint max) 249 { 250 if (value < min) 251 value = min; 252 if (value > max) 253 value = max; 254 return value; 255 } 256 257 // Return true if a character belongs to the ASCII subset as defined in 258 // GLSL ES 1.0 spec section 3.1. 259 bool validateCharacter(unsigned char c) 260 { 261 // Printing characters are valid except " $ ` @ \ ' DEL. 262 if (c >= 32 && c <= 126 263 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') 264 return true; 265 // Horizontal tab, line feed, vertical tab, form feed, carriage return 266 // are also valid. 267 if (c >= 9 && c <= 13) 268 return true; 269 return false; 270 } 271 272 bool isPrefixReserved(const String& name) 273 { 274 if (name.startsWith("gl_") || name.startsWith("webgl_") || name.startsWith("_webgl_")) 275 return true; 276 return false; 277 } 278 279 // Strips comments from shader text. This allows non-ASCII characters 280 // to be used in comments without potentially breaking OpenGL 281 // implementations not expecting characters outside the GLSL ES set. 282 class StripComments { 283 public: 284 StripComments(const String& str) 285 : m_parseState(BeginningOfLine) 286 , m_sourceString(str) 287 , m_length(str.length()) 288 , m_position(0) 289 { 290 parse(); 291 } 292 293 String result() 294 { 295 return m_builder.toString(); 296 } 297 298 private: 299 bool hasMoreCharacters() const 300 { 301 return (m_position < m_length); 302 } 303 304 void parse() 305 { 306 while (hasMoreCharacters()) { 307 process(current()); 308 // process() might advance the position. 309 if (hasMoreCharacters()) 310 advance(); 311 } 312 } 313 314 void process(UChar); 315 316 bool peek(UChar& character) const 317 { 318 if (m_position + 1 >= m_length) 319 return false; 320 character = m_sourceString[m_position + 1]; 321 return true; 322 } 323 324 UChar current() 325 { 326 ASSERT_WITH_SECURITY_IMPLICATION(m_position < m_length); 327 return m_sourceString[m_position]; 328 } 329 330 void advance() 331 { 332 ++m_position; 333 } 334 335 static bool isNewline(UChar character) 336 { 337 // Don't attempt to canonicalize newline related characters. 338 return (character == '\n' || character == '\r'); 339 } 340 341 void emit(UChar character) 342 { 343 m_builder.append(character); 344 } 345 346 enum ParseState { 347 // Have not seen an ASCII non-whitespace character yet on 348 // this line. Possible that we might see a preprocessor 349 // directive. 350 BeginningOfLine, 351 352 // Have seen at least one ASCII non-whitespace character 353 // on this line. 354 MiddleOfLine, 355 356 // Handling a preprocessor directive. Passes through all 357 // characters up to the end of the line. Disables comment 358 // processing. 359 InPreprocessorDirective, 360 361 // Handling a single-line comment. The comment text is 362 // replaced with a single space. 363 InSingleLineComment, 364 365 // Handling a multi-line comment. Newlines are passed 366 // through to preserve line numbers. 367 InMultiLineComment 368 }; 369 370 ParseState m_parseState; 371 String m_sourceString; 372 unsigned m_length; 373 unsigned m_position; 374 StringBuilder m_builder; 375 }; 376 377 void StripComments::process(UChar c) 378 { 379 if (isNewline(c)) { 380 // No matter what state we are in, pass through newlines 381 // so we preserve line numbers. 382 emit(c); 383 384 if (m_parseState != InMultiLineComment) 385 m_parseState = BeginningOfLine; 386 387 return; 388 } 389 390 UChar temp = 0; 391 switch (m_parseState) { 392 case BeginningOfLine: 393 if (WTF::isASCIISpace(c)) { 394 emit(c); 395 break; 396 } 397 398 if (c == '#') { 399 m_parseState = InPreprocessorDirective; 400 emit(c); 401 break; 402 } 403 404 // Transition to normal state and re-handle character. 405 m_parseState = MiddleOfLine; 406 process(c); 407 break; 408 409 case MiddleOfLine: 410 if (c == '/' && peek(temp)) { 411 if (temp == '/') { 412 m_parseState = InSingleLineComment; 413 emit(' '); 414 advance(); 415 break; 416 } 417 418 if (temp == '*') { 419 m_parseState = InMultiLineComment; 420 // Emit the comment start in case the user has 421 // an unclosed comment and we want to later 422 // signal an error. 423 emit('/'); 424 emit('*'); 425 advance(); 426 break; 427 } 428 } 429 430 emit(c); 431 break; 432 433 case InPreprocessorDirective: 434 // No matter what the character is, just pass it 435 // through. Do not parse comments in this state. This 436 // might not be the right thing to do long term, but it 437 // should handle the #error preprocessor directive. 438 emit(c); 439 break; 440 441 case InSingleLineComment: 442 // The newline code at the top of this function takes care 443 // of resetting our state when we get out of the 444 // single-line comment. Swallow all other characters. 445 break; 446 447 case InMultiLineComment: 448 if (c == '*' && peek(temp) && temp == '/') { 449 emit('*'); 450 emit('/'); 451 m_parseState = MiddleOfLine; 452 advance(); 453 break; 454 } 455 456 // Swallow all other characters. Unclear whether we may 457 // want or need to just emit a space per character to try 458 // to preserve column numbers for debugging purposes. 459 break; 460 } 461 } 462 } // namespace anonymous 463 464 class ScopedTexture2DRestorer { 465 public: 466 ScopedTexture2DRestorer(WebGLRenderingContextBase* context) 467 : m_context(context) 468 { 469 } 470 471 ~ScopedTexture2DRestorer() 472 { 473 m_context->restoreCurrentTexture2D(); 474 } 475 476 private: 477 WebGLRenderingContextBase* m_context; 478 }; 479 480 class WebGLRenderingContextLostCallback : public blink::WebGraphicsContext3D::WebGraphicsContextLostCallback { 481 WTF_MAKE_FAST_ALLOCATED; 482 public: 483 explicit WebGLRenderingContextLostCallback(WebGLRenderingContextBase* cb) : m_context(cb) { } 484 virtual void onContextLost() { m_context->forceLostContext(WebGLRenderingContextBase::RealLostContext); } 485 virtual ~WebGLRenderingContextLostCallback() {} 486 private: 487 WebGLRenderingContextBase* m_context; 488 }; 489 490 class WebGLRenderingContextErrorMessageCallback : public blink::WebGraphicsContext3D::WebGraphicsErrorMessageCallback { 491 WTF_MAKE_FAST_ALLOCATED; 492 public: 493 explicit WebGLRenderingContextErrorMessageCallback(WebGLRenderingContextBase* cb) : m_context(cb) { } 494 virtual void onErrorMessage(const blink::WebString& message, blink::WGC3Dint) 495 { 496 if (m_context->m_synthesizedErrorsToConsole) 497 m_context->printGLErrorToConsole(message); 498 InspectorInstrumentation::didFireWebGLErrorOrWarning(m_context->canvas(), message); 499 } 500 virtual ~WebGLRenderingContextErrorMessageCallback() { } 501 private: 502 WebGLRenderingContextBase* m_context; 503 }; 504 505 WebGLRenderingContextBase::WebGLRenderingContextBase(HTMLCanvasElement* passedCanvas, PassOwnPtr<blink::WebGraphicsContext3D> context, WebGLContextAttributes* requestedAttributes) 506 : CanvasRenderingContext(passedCanvas) 507 , ActiveDOMObject(&passedCanvas->document()) 508 , m_drawingBuffer(nullptr) 509 , m_dispatchContextLostEventTimer(this, &WebGLRenderingContextBase::dispatchContextLostEvent) 510 , m_restoreAllowed(false) 511 , m_restoreTimer(this, &WebGLRenderingContextBase::maybeRestoreContext) 512 , m_generatedImageCache(4) 513 , m_contextLost(false) 514 , m_contextLostMode(SyntheticLostContext) 515 , m_requestedAttributes(requestedAttributes->clone()) 516 , m_synthesizedErrorsToConsole(true) 517 , m_numGLErrorsToConsoleAllowed(maxGLErrorsAllowedToConsole) 518 , m_multisamplingAllowed(false) 519 , m_multisamplingObserverRegistered(false) 520 , m_onePlusMaxEnabledAttribIndex(0) 521 , m_onePlusMaxNonDefaultTextureUnit(0) 522 , m_savingImage(false) 523 { 524 ASSERT(context); 525 526 m_contextGroup = WebGLContextGroup::create(); 527 m_contextGroup->addContext(this); 528 529 m_maxViewportDims[0] = m_maxViewportDims[1] = 0; 530 context->getIntegerv(GL_MAX_VIEWPORT_DIMS, m_maxViewportDims); 531 532 m_drawingBuffer = createDrawingBuffer(context); 533 if (!m_drawingBuffer) 534 return; 535 536 m_drawingBuffer->bind(); 537 setupFlags(); 538 initializeNewContext(); 539 } 540 541 PassRefPtr<DrawingBuffer> WebGLRenderingContextBase::createDrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context) 542 { 543 RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager()); 544 545 blink::WebGraphicsContext3D::Attributes attrs; 546 attrs.alpha = m_requestedAttributes->alpha(); 547 attrs.depth = m_requestedAttributes->depth(); 548 attrs.stencil = m_requestedAttributes->stencil(); 549 attrs.antialias = m_requestedAttributes->antialias(); 550 attrs.premultipliedAlpha = m_requestedAttributes->premultipliedAlpha(); 551 DrawingBuffer::PreserveDrawingBuffer preserve = m_requestedAttributes->preserveDrawingBuffer() ? DrawingBuffer::Preserve : DrawingBuffer::Discard; 552 return DrawingBuffer::create(context, clampedCanvasSize(), preserve, attrs, contextEvictionManager.release()); 553 } 554 555 void WebGLRenderingContextBase::initializeNewContext() 556 { 557 ASSERT(!isContextLost()); 558 m_needsUpdate = true; 559 m_markedCanvasDirty = false; 560 m_activeTextureUnit = 0; 561 m_packAlignment = 4; 562 m_unpackAlignment = 4; 563 m_unpackFlipY = false; 564 m_unpackPremultiplyAlpha = false; 565 m_unpackColorspaceConversion = GC3D_BROWSER_DEFAULT_WEBGL; 566 m_boundArrayBuffer = nullptr; 567 m_currentProgram = nullptr; 568 m_framebufferBinding = nullptr; 569 m_renderbufferBinding = nullptr; 570 m_depthMask = true; 571 m_stencilEnabled = false; 572 m_stencilMask = 0xFFFFFFFF; 573 m_stencilMaskBack = 0xFFFFFFFF; 574 m_stencilFuncRef = 0; 575 m_stencilFuncRefBack = 0; 576 m_stencilFuncMask = 0xFFFFFFFF; 577 m_stencilFuncMaskBack = 0xFFFFFFFF; 578 m_layerCleared = false; 579 m_numGLErrorsToConsoleAllowed = maxGLErrorsAllowedToConsole; 580 581 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0; 582 m_scissorEnabled = false; 583 m_clearDepth = 1; 584 m_clearStencil = 0; 585 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true; 586 587 GLint numCombinedTextureImageUnits = 0; 588 webContext()->getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits); 589 m_textureUnits.clear(); 590 m_textureUnits.resize(numCombinedTextureImageUnits); 591 592 GLint numVertexAttribs = 0; 593 webContext()->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &numVertexAttribs); 594 m_maxVertexAttribs = numVertexAttribs; 595 596 m_maxTextureSize = 0; 597 webContext()->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); 598 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize); 599 m_maxCubeMapTextureSize = 0; 600 webContext()->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize); 601 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize); 602 m_maxRenderbufferSize = 0; 603 webContext()->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize); 604 605 // These two values from EXT_draw_buffers are lazily queried. 606 m_maxDrawBuffers = 0; 607 m_maxColorAttachments = 0; 608 609 m_backDrawBuffer = GL_BACK; 610 611 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault); 612 addContextObject(m_defaultVertexArrayObject.get()); 613 m_boundVertexArrayObject = m_defaultVertexArrayObject; 614 615 m_vertexAttribValue.resize(m_maxVertexAttribs); 616 617 createFallbackBlackTextures1x1(); 618 619 webContext()->viewport(0, 0, drawingBufferWidth(), drawingBufferHeight()); 620 webContext()->scissor(0, 0, drawingBufferWidth(), drawingBufferHeight()); 621 622 m_contextLostCallbackAdapter = adoptPtr(new WebGLRenderingContextLostCallback(this)); 623 m_errorMessageCallbackAdapter = adoptPtr(new WebGLRenderingContextErrorMessageCallback(this)); 624 625 webContext()->setContextLostCallback(m_contextLostCallbackAdapter.get()); 626 webContext()->setErrorMessageCallback(m_errorMessageCallbackAdapter.get()); 627 628 // This ensures that the context has a valid "lastFlushID" and won't be mistakenly identified as the "least recently used" context. 629 webContext()->flush(); 630 631 for (int i = 0; i < WebGLExtensionNameCount; ++i) 632 m_extensionEnabled[i] = false; 633 634 activateContext(this); 635 } 636 637 void WebGLRenderingContextBase::setupFlags() 638 { 639 ASSERT(m_drawingBuffer); 640 if (Page* p = canvas()->document().page()) { 641 m_synthesizedErrorsToConsole = p->settings().webGLErrorsToConsoleEnabled(); 642 643 if (!m_multisamplingObserverRegistered && m_requestedAttributes->antialias()) { 644 m_multisamplingAllowed = m_drawingBuffer->multisample(); 645 p->addMultisamplingChangedObserver(this); 646 m_multisamplingObserverRegistered = true; 647 } 648 } 649 650 m_isGLES2NPOTStrict = !extensionsUtil()->isExtensionEnabled("GL_OES_texture_npot"); 651 m_isDepthStencilSupported = extensionsUtil()->isExtensionEnabled("GL_OES_packed_depth_stencil"); 652 } 653 654 void WebGLRenderingContextBase::addCompressedTextureFormat(GLenum format) 655 { 656 if (!m_compressedTextureFormats.contains(format)) 657 m_compressedTextureFormats.append(format); 658 } 659 660 void WebGLRenderingContextBase::removeAllCompressedTextureFormats() 661 { 662 m_compressedTextureFormats.clear(); 663 } 664 665 // Helper function for V8 bindings to identify what version of WebGL a CanvasRenderingContext supports. 666 unsigned WebGLRenderingContextBase::getWebGLVersion(const CanvasRenderingContext* context) 667 { 668 if (!context->is3d()) 669 return 0; 670 return static_cast<const WebGLRenderingContextBase*>(context)->version(); 671 } 672 673 WebGLRenderingContextBase::~WebGLRenderingContextBase() 674 { 675 // Remove all references to WebGLObjects so if they are the last reference 676 // they will be freed before the last context is removed from the context group. 677 m_boundArrayBuffer = nullptr; 678 m_defaultVertexArrayObject = nullptr; 679 m_boundVertexArrayObject = nullptr; 680 m_vertexAttrib0Buffer = nullptr; 681 m_currentProgram = nullptr; 682 m_framebufferBinding = nullptr; 683 m_renderbufferBinding = nullptr; 684 685 for (size_t i = 0; i < m_textureUnits.size(); ++i) { 686 m_textureUnits[i].m_texture2DBinding = nullptr; 687 m_textureUnits[i].m_textureCubeMapBinding = nullptr; 688 } 689 690 m_blackTexture2D = nullptr; 691 m_blackTextureCubeMap = nullptr; 692 693 detachAndRemoveAllObjects(); 694 695 // release all extensions 696 for (size_t i = 0; i < m_extensions.size(); ++i) 697 delete m_extensions[i]; 698 699 // Context must be removed from the group prior to the destruction of the 700 // WebGraphicsContext3D, otherwise shared objects may not be properly deleted. 701 m_contextGroup->removeContext(this); 702 703 destroyContext(); 704 705 #if !ENABLE(OILPAN) 706 if (m_multisamplingObserverRegistered) { 707 Page* page = canvas()->document().page(); 708 if (page) 709 page->removeMultisamplingChangedObserver(this); 710 } 711 #endif 712 713 willDestroyContext(this); 714 } 715 716 void WebGLRenderingContextBase::destroyContext() 717 { 718 m_contextLost = true; 719 720 if (!m_drawingBuffer) 721 return; 722 723 m_extensionsUtil.clear(); 724 725 webContext()->setContextLostCallback(0); 726 webContext()->setErrorMessageCallback(0); 727 728 ASSERT(m_drawingBuffer); 729 m_drawingBuffer->beginDestruction(); 730 m_drawingBuffer.clear(); 731 } 732 733 void WebGLRenderingContextBase::markContextChanged(ContentChangeType changeType) 734 { 735 if (m_framebufferBinding || isContextLost()) 736 return; 737 738 m_drawingBuffer->markContentsChanged(); 739 740 m_layerCleared = false; 741 RenderBox* renderBox = canvas()->renderBox(); 742 if (renderBox && renderBox->hasAcceleratedCompositing()) { 743 m_markedCanvasDirty = true; 744 canvas()->clearCopiedImage(); 745 renderBox->contentChanged(changeType); 746 } else { 747 if (!m_markedCanvasDirty) { 748 m_markedCanvasDirty = true; 749 canvas()->didDraw(FloatRect(FloatPoint(0, 0), clampedCanvasSize())); 750 } 751 } 752 } 753 754 bool WebGLRenderingContextBase::clearIfComposited(GLbitfield mask) 755 { 756 if (isContextLost()) 757 return false; 758 759 if (!m_drawingBuffer->layerComposited() || m_layerCleared 760 || m_requestedAttributes->preserveDrawingBuffer() || (mask && m_framebufferBinding)) 761 return false; 762 763 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes(); 764 765 // Determine if it's possible to combine the clear the user asked for and this clear. 766 bool combinedClear = mask && !m_scissorEnabled; 767 768 webContext()->disable(GL_SCISSOR_TEST); 769 if (combinedClear && (mask & GL_COLOR_BUFFER_BIT)) { 770 webContext()->clearColor(m_colorMask[0] ? m_clearColor[0] : 0, 771 m_colorMask[1] ? m_clearColor[1] : 0, 772 m_colorMask[2] ? m_clearColor[2] : 0, 773 m_colorMask[3] ? m_clearColor[3] : 0); 774 } else { 775 webContext()->clearColor(0, 0, 0, 0); 776 } 777 webContext()->colorMask(true, true, true, true); 778 GLbitfield clearMask = GL_COLOR_BUFFER_BIT; 779 if (contextAttributes->depth()) { 780 if (!combinedClear || !m_depthMask || !(mask & GL_DEPTH_BUFFER_BIT)) 781 webContext()->clearDepth(1.0f); 782 clearMask |= GL_DEPTH_BUFFER_BIT; 783 webContext()->depthMask(true); 784 } 785 if (contextAttributes->stencil()) { 786 if (combinedClear && (mask & GL_STENCIL_BUFFER_BIT)) 787 webContext()->clearStencil(m_clearStencil & m_stencilMask); 788 else 789 webContext()->clearStencil(0); 790 clearMask |= GL_STENCIL_BUFFER_BIT; 791 webContext()->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); 792 } 793 794 m_drawingBuffer->clearFramebuffers(clearMask); 795 796 restoreStateAfterClear(); 797 if (m_framebufferBinding) 798 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get())); 799 m_layerCleared = true; 800 801 return combinedClear; 802 } 803 804 void WebGLRenderingContextBase::restoreStateAfterClear() 805 { 806 if (isContextLost()) 807 return; 808 809 // Restore the state that the context set. 810 if (m_scissorEnabled) 811 webContext()->enable(GL_SCISSOR_TEST); 812 webContext()->clearColor(m_clearColor[0], m_clearColor[1], 813 m_clearColor[2], m_clearColor[3]); 814 webContext()->colorMask(m_colorMask[0], m_colorMask[1], 815 m_colorMask[2], m_colorMask[3]); 816 webContext()->clearDepth(m_clearDepth); 817 webContext()->clearStencil(m_clearStencil); 818 webContext()->stencilMaskSeparate(GL_FRONT, m_stencilMask); 819 webContext()->depthMask(m_depthMask); 820 } 821 822 void WebGLRenderingContextBase::markLayerComposited() 823 { 824 if (!isContextLost()) 825 m_drawingBuffer->markLayerComposited(); 826 } 827 828 void WebGLRenderingContextBase::paintRenderingResultsToCanvas() 829 { 830 if (isContextLost()) { 831 canvas()->clearPresentationCopy(); 832 return; 833 } 834 835 if (canvas()->document().printing()) 836 canvas()->clearPresentationCopy(); 837 838 // Until the canvas is written to by the application, the clear that 839 // happened after it was composited should be ignored by the compositor. 840 if (m_drawingBuffer->layerComposited() && !m_requestedAttributes->preserveDrawingBuffer()) { 841 m_drawingBuffer->paintCompositedResultsToCanvas(canvas()->buffer()); 842 843 canvas()->makePresentationCopy(); 844 } else 845 canvas()->clearPresentationCopy(); 846 847 clearIfComposited(); 848 849 if (!m_markedCanvasDirty && !m_layerCleared) 850 return; 851 852 canvas()->clearCopiedImage(); 853 m_markedCanvasDirty = false; 854 855 ScopedTexture2DRestorer restorer(this); 856 857 m_drawingBuffer->commit(); 858 if (!(canvas()->buffer())->copyRenderingResultsFromDrawingBuffer(m_drawingBuffer.get(), m_savingImage)) { 859 canvas()->ensureUnacceleratedImageBuffer(); 860 if (canvas()->hasImageBuffer()) 861 m_drawingBuffer->paintRenderingResultsToCanvas(canvas()->buffer()); 862 } 863 864 if (m_framebufferBinding) 865 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get())); 866 else 867 m_drawingBuffer->bind(); 868 } 869 870 PassRefPtrWillBeRawPtr<ImageData> WebGLRenderingContextBase::paintRenderingResultsToImageData() 871 { 872 if (isContextLost()) 873 return nullptr; 874 875 clearIfComposited(); 876 m_drawingBuffer->commit(); 877 int width, height; 878 RefPtr<Uint8ClampedArray> imageDataPixels = m_drawingBuffer->paintRenderingResultsToImageData(width, height); 879 if (!imageDataPixels) 880 return nullptr; 881 882 if (m_framebufferBinding) 883 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get())); 884 else 885 m_drawingBuffer->bind(); 886 887 return ImageData::create(IntSize(width, height), imageDataPixels); 888 } 889 890 void WebGLRenderingContextBase::reshape(int width, int height) 891 { 892 if (isContextLost()) 893 return; 894 895 // This is an approximation because at WebGLRenderingContextBase level we don't 896 // know if the underlying FBO uses textures or renderbuffers. 897 GLint maxSize = std::min(m_maxTextureSize, m_maxRenderbufferSize); 898 // Limit drawing buffer size to 4k to avoid memory exhaustion. 899 const int sizeUpperLimit = 4096; 900 maxSize = std::min(maxSize, sizeUpperLimit); 901 GLint maxWidth = std::min(maxSize, m_maxViewportDims[0]); 902 GLint maxHeight = std::min(maxSize, m_maxViewportDims[1]); 903 width = clamp(width, 1, maxWidth); 904 height = clamp(height, 1, maxHeight); 905 906 if (m_needsUpdate) { 907 RenderBox* renderBox = canvas()->renderBox(); 908 if (renderBox && renderBox->hasAcceleratedCompositing()) 909 renderBox->contentChanged(CanvasChanged); 910 m_needsUpdate = false; 911 } 912 913 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off 914 // clear (and this matches what reshape will do). 915 m_drawingBuffer->reset(IntSize(width, height)); 916 restoreStateAfterClear(); 917 918 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get())); 919 webContext()->bindRenderbuffer(GL_RENDERBUFFER, objectOrZero(m_renderbufferBinding.get())); 920 if (m_framebufferBinding) 921 webContext()->bindFramebuffer(GL_FRAMEBUFFER, objectOrZero(m_framebufferBinding.get())); 922 } 923 924 int WebGLRenderingContextBase::drawingBufferWidth() const 925 { 926 return isContextLost() ? 0 : m_drawingBuffer->size().width(); 927 } 928 929 int WebGLRenderingContextBase::drawingBufferHeight() const 930 { 931 return isContextLost() ? 0 : m_drawingBuffer->size().height(); 932 } 933 934 unsigned WebGLRenderingContextBase::sizeInBytes(GLenum type) 935 { 936 switch (type) { 937 case GL_BYTE: 938 return sizeof(GLbyte); 939 case GL_UNSIGNED_BYTE: 940 return sizeof(GLubyte); 941 case GL_SHORT: 942 return sizeof(GLshort); 943 case GL_UNSIGNED_SHORT: 944 return sizeof(GLushort); 945 case GL_INT: 946 return sizeof(GLint); 947 case GL_UNSIGNED_INT: 948 return sizeof(GLuint); 949 case GL_FLOAT: 950 return sizeof(GLfloat); 951 } 952 ASSERT_NOT_REACHED(); 953 return 0; 954 } 955 956 void WebGLRenderingContextBase::activeTexture(GLenum texture) 957 { 958 if (isContextLost()) 959 return; 960 if (texture - GL_TEXTURE0 >= m_textureUnits.size()) { 961 synthesizeGLError(GL_INVALID_ENUM, "activeTexture", "texture unit out of range"); 962 return; 963 } 964 m_activeTextureUnit = texture - GL_TEXTURE0; 965 webContext()->activeTexture(texture); 966 967 m_drawingBuffer->setActiveTextureUnit(texture); 968 969 } 970 971 void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader) 972 { 973 if (isContextLost() || !validateWebGLObject("attachShader", program) || !validateWebGLObject("attachShader", shader)) 974 return; 975 if (!program->attachShader(shader)) { 976 synthesizeGLError(GL_INVALID_OPERATION, "attachShader", "shader attachment already has shader"); 977 return; 978 } 979 webContext()->attachShader(objectOrZero(program), objectOrZero(shader)); 980 shader->onAttached(); 981 } 982 983 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name) 984 { 985 if (isContextLost() || !validateWebGLObject("bindAttribLocation", program)) 986 return; 987 if (!validateLocationLength("bindAttribLocation", name)) 988 return; 989 if (!validateString("bindAttribLocation", name)) 990 return; 991 if (isPrefixReserved(name)) { 992 synthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation", "reserved prefix"); 993 return; 994 } 995 if (index >= m_maxVertexAttribs) { 996 synthesizeGLError(GL_INVALID_VALUE, "bindAttribLocation", "index out of range"); 997 return; 998 } 999 webContext()->bindAttribLocation(objectOrZero(program), index, name.utf8().data()); 1000 } 1001 1002 bool WebGLRenderingContextBase::checkObjectToBeBound(const char* functionName, WebGLObject* object, bool& deleted) 1003 { 1004 deleted = false; 1005 if (isContextLost()) 1006 return false; 1007 if (object) { 1008 if (!object->validate(contextGroup(), this)) { 1009 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object not from this context"); 1010 return false; 1011 } 1012 deleted = !object->object(); 1013 } 1014 return true; 1015 } 1016 1017 void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) 1018 { 1019 bool deleted; 1020 if (!checkObjectToBeBound("bindBuffer", buffer, deleted)) 1021 return; 1022 if (deleted) 1023 buffer = 0; 1024 if (buffer && buffer->getTarget() && buffer->getTarget() != target) { 1025 synthesizeGLError(GL_INVALID_OPERATION, "bindBuffer", "buffers can not be used with multiple targets"); 1026 return; 1027 } 1028 if (target == GL_ARRAY_BUFFER) 1029 m_boundArrayBuffer = buffer; 1030 else if (target == GL_ELEMENT_ARRAY_BUFFER) 1031 m_boundVertexArrayObject->setElementArrayBuffer(buffer); 1032 else { 1033 synthesizeGLError(GL_INVALID_ENUM, "bindBuffer", "invalid target"); 1034 return; 1035 } 1036 1037 webContext()->bindBuffer(target, objectOrZero(buffer)); 1038 if (buffer) 1039 buffer->setTarget(target); 1040 } 1041 1042 void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer) 1043 { 1044 bool deleted; 1045 if (!checkObjectToBeBound("bindFramebuffer", buffer, deleted)) 1046 return; 1047 if (deleted) 1048 buffer = 0; 1049 if (target != GL_FRAMEBUFFER) { 1050 synthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target"); 1051 return; 1052 } 1053 m_framebufferBinding = buffer; 1054 m_drawingBuffer->setFramebufferBinding(objectOrZero(m_framebufferBinding.get())); 1055 if (!m_framebufferBinding) { 1056 // Instead of binding fb 0, bind the drawing buffer. 1057 m_drawingBuffer->bind(); 1058 } else { 1059 webContext()->bindFramebuffer(target, objectOrZero(buffer)); 1060 } 1061 if (buffer) 1062 buffer->setHasEverBeenBound(); 1063 applyStencilTest(); 1064 } 1065 1066 void WebGLRenderingContextBase::bindRenderbuffer(GLenum target, WebGLRenderbuffer* renderBuffer) 1067 { 1068 bool deleted; 1069 if (!checkObjectToBeBound("bindRenderbuffer", renderBuffer, deleted)) 1070 return; 1071 if (deleted) 1072 renderBuffer = 0; 1073 if (target != GL_RENDERBUFFER) { 1074 synthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target"); 1075 return; 1076 } 1077 m_renderbufferBinding = renderBuffer; 1078 webContext()->bindRenderbuffer(target, objectOrZero(renderBuffer)); 1079 if (renderBuffer) 1080 renderBuffer->setHasEverBeenBound(); 1081 } 1082 1083 void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture) 1084 { 1085 bool deleted; 1086 if (!checkObjectToBeBound("bindTexture", texture, deleted)) 1087 return; 1088 if (deleted) 1089 texture = 0; 1090 if (texture && texture->getTarget() && texture->getTarget() != target) { 1091 synthesizeGLError(GL_INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets"); 1092 return; 1093 } 1094 GLint maxLevel = 0; 1095 if (target == GL_TEXTURE_2D) { 1096 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture; 1097 maxLevel = m_maxTextureLevel; 1098 1099 if (!m_activeTextureUnit) 1100 m_drawingBuffer->setTexture2DBinding(objectOrZero(texture)); 1101 1102 } else if (target == GL_TEXTURE_CUBE_MAP) { 1103 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture; 1104 maxLevel = m_maxCubeMapTextureLevel; 1105 } else { 1106 synthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target"); 1107 return; 1108 } 1109 1110 webContext()->bindTexture(target, objectOrZero(texture)); 1111 if (texture) { 1112 texture->setTarget(target, maxLevel); 1113 m_onePlusMaxNonDefaultTextureUnit = max(m_activeTextureUnit + 1, m_onePlusMaxNonDefaultTextureUnit); 1114 } else { 1115 // If the disabled index is the current maximum, trace backwards to find the new max enabled texture index 1116 if (m_onePlusMaxNonDefaultTextureUnit == m_activeTextureUnit + 1) { 1117 findNewMaxNonDefaultTextureUnit(); 1118 } 1119 } 1120 1121 // Note: previously we used to automatically set the TEXTURE_WRAP_R 1122 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL 1123 // ES 2.0 doesn't expose this flag (a bug in the specification) and 1124 // otherwise the application has no control over the seams in this 1125 // dimension. However, it appears that supporting this properly on all 1126 // platforms is fairly involved (will require a HashMap from texture ID 1127 // in all ports), and we have not had any complaints, so the logic has 1128 // been removed. 1129 1130 } 1131 1132 void WebGLRenderingContextBase::blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) 1133 { 1134 if (isContextLost()) 1135 return; 1136 webContext()->blendColor(red, green, blue, alpha); 1137 } 1138 1139 void WebGLRenderingContextBase::blendEquation(GLenum mode) 1140 { 1141 if (isContextLost() || !validateBlendEquation("blendEquation", mode)) 1142 return; 1143 webContext()->blendEquation(mode); 1144 } 1145 1146 void WebGLRenderingContextBase::blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) 1147 { 1148 if (isContextLost() || !validateBlendEquation("blendEquationSeparate", modeRGB) || !validateBlendEquation("blendEquationSeparate", modeAlpha)) 1149 return; 1150 webContext()->blendEquationSeparate(modeRGB, modeAlpha); 1151 } 1152 1153 1154 void WebGLRenderingContextBase::blendFunc(GLenum sfactor, GLenum dfactor) 1155 { 1156 if (isContextLost() || !validateBlendFuncFactors("blendFunc", sfactor, dfactor)) 1157 return; 1158 webContext()->blendFunc(sfactor, dfactor); 1159 } 1160 1161 void WebGLRenderingContextBase::blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) 1162 { 1163 // Note: Alpha does not have the same restrictions as RGB. 1164 if (isContextLost() || !validateBlendFuncFactors("blendFuncSeparate", srcRGB, dstRGB)) 1165 return; 1166 webContext()->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 1167 } 1168 1169 void WebGLRenderingContextBase::bufferDataImpl(GLenum target, long long size, const void* data, GLenum usage) 1170 { 1171 WebGLBuffer* buffer = validateBufferDataTarget("bufferData", target); 1172 if (!buffer) 1173 return; 1174 1175 switch (usage) { 1176 case GL_STREAM_DRAW: 1177 case GL_STATIC_DRAW: 1178 case GL_DYNAMIC_DRAW: 1179 break; 1180 default: 1181 synthesizeGLError(GL_INVALID_ENUM, "bufferData", "invalid usage"); 1182 return; 1183 } 1184 1185 if (!validateValueFitNonNegInt32("bufferData", "size", size)) 1186 return; 1187 1188 webContext()->bufferData(target, static_cast<GLsizeiptr>(size), data, usage); 1189 } 1190 1191 void WebGLRenderingContextBase::bufferData(GLenum target, long long size, GLenum usage) 1192 { 1193 if (isContextLost()) 1194 return; 1195 if (!size) { 1196 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "size == 0"); 1197 return; 1198 } 1199 bufferDataImpl(target, size, 0, usage); 1200 } 1201 1202 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBuffer* data, GLenum usage) 1203 { 1204 if (isContextLost()) 1205 return; 1206 if (!data) { 1207 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data"); 1208 return; 1209 } 1210 bufferDataImpl(target, data->byteLength(), data->data(), usage); 1211 } 1212 1213 void WebGLRenderingContextBase::bufferData(GLenum target, ArrayBufferView* data, GLenum usage) 1214 { 1215 if (isContextLost()) 1216 return; 1217 if (!data) { 1218 synthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data"); 1219 return; 1220 } 1221 bufferDataImpl(target, data->byteLength(), data->baseAddress(), usage); 1222 } 1223 1224 void WebGLRenderingContextBase::bufferSubDataImpl(GLenum target, long long offset, GLsizeiptr size, const void* data) 1225 { 1226 WebGLBuffer* buffer = validateBufferDataTarget("bufferSubData", target); 1227 if (!buffer) 1228 return; 1229 if (!validateValueFitNonNegInt32("bufferSubData", "offset", offset)) 1230 return; 1231 if (!data) 1232 return; 1233 1234 webContext()->bufferSubData(target, static_cast<GLintptr>(offset), size, data); 1235 } 1236 1237 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBuffer* data) 1238 { 1239 if (isContextLost()) 1240 return; 1241 if (!data) 1242 return; 1243 bufferSubDataImpl(target, offset, data->byteLength(), data->data()); 1244 } 1245 1246 void WebGLRenderingContextBase::bufferSubData(GLenum target, long long offset, ArrayBufferView* data) 1247 { 1248 if (isContextLost()) 1249 return; 1250 if (!data) 1251 return; 1252 bufferSubDataImpl(target, offset, data->byteLength(), data->baseAddress()); 1253 } 1254 1255 GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target) 1256 { 1257 if (isContextLost()) 1258 return GL_FRAMEBUFFER_UNSUPPORTED; 1259 if (target != GL_FRAMEBUFFER) { 1260 synthesizeGLError(GL_INVALID_ENUM, "checkFramebufferStatus", "invalid target"); 1261 return 0; 1262 } 1263 if (!m_framebufferBinding || !m_framebufferBinding->object()) 1264 return GL_FRAMEBUFFER_COMPLETE; 1265 const char* reason = "framebuffer incomplete"; 1266 GLenum result = m_framebufferBinding->checkStatus(&reason); 1267 if (result != GL_FRAMEBUFFER_COMPLETE) { 1268 emitGLWarning("checkFramebufferStatus", reason); 1269 return result; 1270 } 1271 result = webContext()->checkFramebufferStatus(target); 1272 return result; 1273 } 1274 1275 void WebGLRenderingContextBase::clear(GLbitfield mask) 1276 { 1277 if (isContextLost()) 1278 return; 1279 if (mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { 1280 synthesizeGLError(GL_INVALID_VALUE, "clear", "invalid mask"); 1281 return; 1282 } 1283 const char* reason = "framebuffer incomplete"; 1284 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 1285 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason); 1286 return; 1287 } 1288 if (!clearIfComposited(mask)) 1289 webContext()->clear(mask); 1290 markContextChanged(CanvasChanged); 1291 } 1292 1293 void WebGLRenderingContextBase::clearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) 1294 { 1295 if (isContextLost()) 1296 return; 1297 if (std::isnan(r)) 1298 r = 0; 1299 if (std::isnan(g)) 1300 g = 0; 1301 if (std::isnan(b)) 1302 b = 0; 1303 if (std::isnan(a)) 1304 a = 1; 1305 m_clearColor[0] = r; 1306 m_clearColor[1] = g; 1307 m_clearColor[2] = b; 1308 m_clearColor[3] = a; 1309 webContext()->clearColor(r, g, b, a); 1310 } 1311 1312 void WebGLRenderingContextBase::clearDepth(GLfloat depth) 1313 { 1314 if (isContextLost()) 1315 return; 1316 m_clearDepth = depth; 1317 webContext()->clearDepth(depth); 1318 } 1319 1320 void WebGLRenderingContextBase::clearStencil(GLint s) 1321 { 1322 if (isContextLost()) 1323 return; 1324 m_clearStencil = s; 1325 webContext()->clearStencil(s); 1326 } 1327 1328 void WebGLRenderingContextBase::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) 1329 { 1330 if (isContextLost()) 1331 return; 1332 m_colorMask[0] = red; 1333 m_colorMask[1] = green; 1334 m_colorMask[2] = blue; 1335 m_colorMask[3] = alpha; 1336 webContext()->colorMask(red, green, blue, alpha); 1337 } 1338 1339 void WebGLRenderingContextBase::compileShader(WebGLShader* shader) 1340 { 1341 if (isContextLost() || !validateWebGLObject("compileShader", shader)) 1342 return; 1343 webContext()->compileShader(objectOrZero(shader)); 1344 } 1345 1346 void WebGLRenderingContextBase::compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, ArrayBufferView* data) 1347 { 1348 if (isContextLost()) 1349 return; 1350 if (!validateTexFuncLevel("compressedTexImage2D", target, level)) 1351 return; 1352 1353 if (!validateCompressedTexFormat(internalformat)) { 1354 synthesizeGLError(GL_INVALID_ENUM, "compressedTexImage2D", "invalid internalformat"); 1355 return; 1356 } 1357 if (border) { 1358 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "border not 0"); 1359 return; 1360 } 1361 if (!validateCompressedTexDimensions("compressedTexImage2D", NotTexSubImage2D, target, level, width, height, internalformat)) 1362 return; 1363 if (!validateCompressedTexFuncData("compressedTexImage2D", width, height, internalformat, data)) 1364 return; 1365 1366 WebGLTexture* tex = validateTextureBinding("compressedTexImage2D", target, true); 1367 if (!tex) 1368 return; 1369 if (!isGLES2NPOTStrict()) { 1370 if (level && WebGLTexture::isNPOT(width, height)) { 1371 synthesizeGLError(GL_INVALID_VALUE, "compressedTexImage2D", "level > 0 not power of 2"); 1372 return; 1373 } 1374 } 1375 webContext()->compressedTexImage2D(target, level, internalformat, width, height, 1376 border, data->byteLength(), data->baseAddress()); 1377 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE); 1378 } 1379 1380 void WebGLRenderingContextBase::compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* data) 1381 { 1382 if (isContextLost()) 1383 return; 1384 if (!validateTexFuncLevel("compressedTexSubImage2D", target, level)) 1385 return; 1386 if (!validateCompressedTexFormat(format)) { 1387 synthesizeGLError(GL_INVALID_ENUM, "compressedTexSubImage2D", "invalid format"); 1388 return; 1389 } 1390 if (!validateCompressedTexFuncData("compressedTexSubImage2D", width, height, format, data)) 1391 return; 1392 1393 WebGLTexture* tex = validateTextureBinding("compressedTexSubImage2D", target, true); 1394 if (!tex) 1395 return; 1396 1397 if (format != tex->getInternalFormat(target, level)) { 1398 synthesizeGLError(GL_INVALID_OPERATION, "compressedTexSubImage2D", "format does not match texture format"); 1399 return; 1400 } 1401 1402 if (!validateCompressedTexSubDimensions("compressedTexSubImage2D", target, level, xoffset, yoffset, width, height, format, tex)) 1403 return; 1404 1405 webContext()->compressedTexSubImage2D(target, level, xoffset, yoffset, 1406 width, height, format, data->byteLength(), data->baseAddress()); 1407 } 1408 1409 bool WebGLRenderingContextBase::validateSettableTexFormat(const char* functionName, GLenum format) 1410 { 1411 if (WebGLImageConversion::getClearBitsByFormat(format) & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) { 1412 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format can not be set, only rendered to"); 1413 return false; 1414 } 1415 return true; 1416 } 1417 1418 void WebGLRenderingContextBase::copyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) 1419 { 1420 if (isContextLost()) 1421 return; 1422 if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GL_UNSIGNED_BYTE)) 1423 return; 1424 if (!validateSettableTexFormat("copyTexImage2D", internalformat)) 1425 return; 1426 WebGLTexture* tex = validateTextureBinding("copyTexImage2D", target, true); 1427 if (!tex) 1428 return; 1429 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) { 1430 synthesizeGLError(GL_INVALID_OPERATION, "copyTexImage2D", "framebuffer is incompatible format"); 1431 return; 1432 } 1433 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) { 1434 synthesizeGLError(GL_INVALID_VALUE, "copyTexImage2D", "level > 0 not power of 2"); 1435 return; 1436 } 1437 const char* reason = "framebuffer incomplete"; 1438 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 1439 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexImage2D", reason); 1440 return; 1441 } 1442 clearIfComposited(); 1443 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get()); 1444 webContext()->copyTexImage2D(target, level, internalformat, x, y, width, height, border); 1445 // FIXME: if the framebuffer is not complete, none of the below should be executed. 1446 tex->setLevelInfo(target, level, internalformat, width, height, GL_UNSIGNED_BYTE); 1447 } 1448 1449 void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) 1450 { 1451 if (isContextLost()) 1452 return; 1453 if (!validateTexFuncLevel("copyTexSubImage2D", target, level)) 1454 return; 1455 WebGLTexture* tex = validateTextureBinding("copyTexSubImage2D", target, true); 1456 if (!tex) 1457 return; 1458 if (!validateSize("copyTexSubImage2D", xoffset, yoffset) || !validateSize("copyTexSubImage2D", width, height)) 1459 return; 1460 // Before checking if it is in the range, check if overflow happens first. 1461 Checked<GLint, RecordOverflow> maxX = xoffset; 1462 maxX += width; 1463 Checked<GLint, RecordOverflow> maxY = yoffset; 1464 maxY += height; 1465 if (maxX.hasOverflowed() || maxY.hasOverflowed()) { 1466 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "bad dimensions"); 1467 return; 1468 } 1469 if (maxX.unsafeGet() > tex->getWidth(target, level) || maxY.unsafeGet() > tex->getHeight(target, level)) { 1470 synthesizeGLError(GL_INVALID_VALUE, "copyTexSubImage2D", "rectangle out of range"); 1471 return; 1472 } 1473 GLenum internalformat = tex->getInternalFormat(target, level); 1474 if (!validateSettableTexFormat("copyTexSubImage2D", internalformat)) 1475 return; 1476 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, boundFramebufferColorFormat())) { 1477 synthesizeGLError(GL_INVALID_OPERATION, "copyTexSubImage2D", "framebuffer is incompatible format"); 1478 return; 1479 } 1480 const char* reason = "framebuffer incomplete"; 1481 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 1482 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "copyTexSubImage2D", reason); 1483 return; 1484 } 1485 clearIfComposited(); 1486 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get()); 1487 webContext()->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); 1488 } 1489 1490 PassRefPtr<WebGLBuffer> WebGLRenderingContextBase::createBuffer() 1491 { 1492 if (isContextLost()) 1493 return nullptr; 1494 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this); 1495 addSharedObject(o.get()); 1496 return o; 1497 } 1498 1499 PassRefPtr<WebGLFramebuffer> WebGLRenderingContextBase::createFramebuffer() 1500 { 1501 if (isContextLost()) 1502 return nullptr; 1503 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this); 1504 addContextObject(o.get()); 1505 return o; 1506 } 1507 1508 PassRefPtr<WebGLTexture> WebGLRenderingContextBase::createTexture() 1509 { 1510 if (isContextLost()) 1511 return nullptr; 1512 RefPtr<WebGLTexture> o = WebGLTexture::create(this); 1513 addSharedObject(o.get()); 1514 return o; 1515 } 1516 1517 PassRefPtr<WebGLProgram> WebGLRenderingContextBase::createProgram() 1518 { 1519 if (isContextLost()) 1520 return nullptr; 1521 RefPtr<WebGLProgram> o = WebGLProgram::create(this); 1522 addSharedObject(o.get()); 1523 return o; 1524 } 1525 1526 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContextBase::createRenderbuffer() 1527 { 1528 if (isContextLost()) 1529 return nullptr; 1530 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this); 1531 addSharedObject(o.get()); 1532 return o; 1533 } 1534 1535 WebGLRenderbuffer* WebGLRenderingContextBase::ensureEmulatedStencilBuffer(GLenum target, WebGLRenderbuffer* renderbuffer) 1536 { 1537 if (isContextLost()) 1538 return 0; 1539 if (!renderbuffer->emulatedStencilBuffer()) { 1540 renderbuffer->setEmulatedStencilBuffer(createRenderbuffer()); 1541 webContext()->bindRenderbuffer(target, objectOrZero(renderbuffer->emulatedStencilBuffer())); 1542 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get())); 1543 } 1544 return renderbuffer->emulatedStencilBuffer(); 1545 } 1546 1547 PassRefPtr<WebGLShader> WebGLRenderingContextBase::createShader(GLenum type) 1548 { 1549 if (isContextLost()) 1550 return nullptr; 1551 if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) { 1552 synthesizeGLError(GL_INVALID_ENUM, "createShader", "invalid shader type"); 1553 return nullptr; 1554 } 1555 1556 RefPtr<WebGLShader> o = WebGLShader::create(this, type); 1557 addSharedObject(o.get()); 1558 return o; 1559 } 1560 1561 void WebGLRenderingContextBase::cullFace(GLenum mode) 1562 { 1563 if (isContextLost()) 1564 return; 1565 switch (mode) { 1566 case GL_FRONT_AND_BACK: 1567 case GL_FRONT: 1568 case GL_BACK: 1569 break; 1570 default: 1571 synthesizeGLError(GL_INVALID_ENUM, "cullFace", "invalid mode"); 1572 return; 1573 } 1574 webContext()->cullFace(mode); 1575 } 1576 1577 bool WebGLRenderingContextBase::deleteObject(WebGLObject* object) 1578 { 1579 if (isContextLost() || !object) 1580 return false; 1581 if (!object->validate(contextGroup(), this)) { 1582 synthesizeGLError(GL_INVALID_OPERATION, "delete", "object does not belong to this context"); 1583 return false; 1584 } 1585 if (object->object()) { 1586 // We need to pass in context here because we want 1587 // things in this context unbound. 1588 object->deleteObject(webContext()); 1589 } 1590 return true; 1591 } 1592 1593 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer) 1594 { 1595 if (!deleteObject(buffer)) 1596 return; 1597 if (m_boundArrayBuffer == buffer) 1598 m_boundArrayBuffer = nullptr; 1599 1600 m_boundVertexArrayObject->unbindBuffer(buffer); 1601 } 1602 1603 void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer) 1604 { 1605 if (!deleteObject(framebuffer)) 1606 return; 1607 if (framebuffer == m_framebufferBinding) { 1608 m_framebufferBinding = nullptr; 1609 m_drawingBuffer->setFramebufferBinding(0); 1610 // Have to call bindFramebuffer here to bind back to internal fbo. 1611 m_drawingBuffer->bind(); 1612 } 1613 } 1614 1615 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program) 1616 { 1617 deleteObject(program); 1618 // We don't reset m_currentProgram to 0 here because the deletion of the 1619 // current program is delayed. 1620 } 1621 1622 void WebGLRenderingContextBase::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer) 1623 { 1624 if (!deleteObject(renderbuffer)) 1625 return; 1626 if (renderbuffer == m_renderbufferBinding) 1627 m_renderbufferBinding = nullptr; 1628 if (m_framebufferBinding) 1629 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(renderbuffer); 1630 } 1631 1632 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader) 1633 { 1634 deleteObject(shader); 1635 } 1636 1637 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture) 1638 { 1639 if (!deleteObject(texture)) 1640 return; 1641 1642 int maxBoundTextureIndex = -1; 1643 for (size_t i = 0; i < m_onePlusMaxNonDefaultTextureUnit; ++i) { 1644 if (texture == m_textureUnits[i].m_texture2DBinding) { 1645 m_textureUnits[i].m_texture2DBinding = nullptr; 1646 maxBoundTextureIndex = i; 1647 if (!i) 1648 m_drawingBuffer->setTexture2DBinding(0); 1649 } 1650 if (texture == m_textureUnits[i].m_textureCubeMapBinding) { 1651 m_textureUnits[i].m_textureCubeMapBinding = nullptr; 1652 maxBoundTextureIndex = i; 1653 } 1654 } 1655 if (m_framebufferBinding) 1656 m_framebufferBinding->removeAttachmentFromBoundFramebuffer(texture); 1657 1658 // If the deleted was bound to the the current maximum index, trace backwards to find the new max texture index 1659 if (m_onePlusMaxNonDefaultTextureUnit == static_cast<unsigned long>(maxBoundTextureIndex + 1)) { 1660 findNewMaxNonDefaultTextureUnit(); 1661 } 1662 } 1663 1664 void WebGLRenderingContextBase::depthFunc(GLenum func) 1665 { 1666 if (isContextLost()) 1667 return; 1668 if (!validateStencilOrDepthFunc("depthFunc", func)) 1669 return; 1670 webContext()->depthFunc(func); 1671 } 1672 1673 void WebGLRenderingContextBase::depthMask(GLboolean flag) 1674 { 1675 if (isContextLost()) 1676 return; 1677 m_depthMask = flag; 1678 webContext()->depthMask(flag); 1679 } 1680 1681 void WebGLRenderingContextBase::depthRange(GLfloat zNear, GLfloat zFar) 1682 { 1683 if (isContextLost()) 1684 return; 1685 if (zNear > zFar) { 1686 synthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar"); 1687 return; 1688 } 1689 webContext()->depthRange(zNear, zFar); 1690 } 1691 1692 void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader) 1693 { 1694 if (isContextLost() || !validateWebGLObject("detachShader", program) || !validateWebGLObject("detachShader", shader)) 1695 return; 1696 if (!program->detachShader(shader)) { 1697 synthesizeGLError(GL_INVALID_OPERATION, "detachShader", "shader not attached"); 1698 return; 1699 } 1700 webContext()->detachShader(objectOrZero(program), objectOrZero(shader)); 1701 shader->onDetached(webContext()); 1702 } 1703 1704 void WebGLRenderingContextBase::disable(GLenum cap) 1705 { 1706 if (isContextLost() || !validateCapability("disable", cap)) 1707 return; 1708 if (cap == GL_STENCIL_TEST) { 1709 m_stencilEnabled = false; 1710 applyStencilTest(); 1711 return; 1712 } 1713 if (cap == GL_SCISSOR_TEST) { 1714 m_scissorEnabled = false; 1715 m_drawingBuffer->setScissorEnabled(m_scissorEnabled); 1716 } 1717 webContext()->disable(cap); 1718 } 1719 1720 void WebGLRenderingContextBase::disableVertexAttribArray(GLuint index) 1721 { 1722 if (isContextLost()) 1723 return; 1724 if (index >= m_maxVertexAttribs) { 1725 synthesizeGLError(GL_INVALID_VALUE, "disableVertexAttribArray", "index out of range"); 1726 return; 1727 } 1728 1729 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 1730 state.enabled = false; 1731 1732 // If the disabled index is the current maximum, trace backwards to find the new max enabled attrib index 1733 if (m_onePlusMaxEnabledAttribIndex == index + 1) { 1734 findNewMaxEnabledAttribIndex(); 1735 } 1736 1737 webContext()->disableVertexAttribArray(index); 1738 } 1739 1740 bool WebGLRenderingContextBase::validateRenderingState(const char* functionName) 1741 { 1742 if (!m_currentProgram) { 1743 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no valid shader program in use"); 1744 return false; 1745 } 1746 1747 // Look in each enabled vertex attrib and check if they've been bound to a buffer. 1748 for (unsigned i = 0; i < m_onePlusMaxEnabledAttribIndex; ++i) { 1749 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i); 1750 if (state.enabled 1751 && (!state.bufferBinding || !state.bufferBinding->object())) { 1752 synthesizeGLError(GL_INVALID_OPERATION, functionName, String::format("attribute %d is enabled but has no buffer bound", i).utf8().data()); 1753 return false; 1754 } 1755 } 1756 1757 return true; 1758 } 1759 1760 bool WebGLRenderingContextBase::validateWebGLObject(const char* functionName, WebGLObject* object) 1761 { 1762 if (!object || !object->object()) { 1763 synthesizeGLError(GL_INVALID_VALUE, functionName, "no object or object deleted"); 1764 return false; 1765 } 1766 if (!object->validate(contextGroup(), this)) { 1767 synthesizeGLError(GL_INVALID_OPERATION, functionName, "object does not belong to this context"); 1768 return false; 1769 } 1770 return true; 1771 } 1772 1773 void WebGLRenderingContextBase::drawArrays(GLenum mode, GLint first, GLsizei count) 1774 { 1775 if (!validateDrawArrays("drawArrays", mode, first, count)) 1776 return; 1777 1778 clearIfComposited(); 1779 1780 handleTextureCompleteness("drawArrays", true); 1781 webContext()->drawArrays(mode, first, count); 1782 handleTextureCompleteness("drawArrays", false); 1783 markContextChanged(CanvasChanged); 1784 } 1785 1786 void WebGLRenderingContextBase::drawElements(GLenum mode, GLsizei count, GLenum type, long long offset) 1787 { 1788 if (!validateDrawElements("drawElements", mode, count, type, offset)) 1789 return; 1790 1791 clearIfComposited(); 1792 1793 handleTextureCompleteness("drawElements", true); 1794 webContext()->drawElements(mode, count, type, static_cast<GLintptr>(offset)); 1795 handleTextureCompleteness("drawElements", false); 1796 markContextChanged(CanvasChanged); 1797 } 1798 1799 void WebGLRenderingContextBase::drawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei primcount) 1800 { 1801 if (!validateDrawArrays("drawArraysInstancedANGLE", mode, first, count)) 1802 return; 1803 1804 if (!validateDrawInstanced("drawArraysInstancedANGLE", primcount)) 1805 return; 1806 1807 clearIfComposited(); 1808 1809 handleTextureCompleteness("drawArraysInstancedANGLE", true); 1810 webContext()->drawArraysInstancedANGLE(mode, first, count, primcount); 1811 handleTextureCompleteness("drawArraysInstancedANGLE", false); 1812 markContextChanged(CanvasChanged); 1813 } 1814 1815 void WebGLRenderingContextBase::drawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, long long offset, GLsizei primcount) 1816 { 1817 if (!validateDrawElements("drawElementsInstancedANGLE", mode, count, type, offset)) 1818 return; 1819 1820 if (!validateDrawInstanced("drawElementsInstancedANGLE", primcount)) 1821 return; 1822 1823 clearIfComposited(); 1824 1825 handleTextureCompleteness("drawElementsInstancedANGLE", true); 1826 webContext()->drawElementsInstancedANGLE(mode, count, type, static_cast<GLintptr>(offset), primcount); 1827 handleTextureCompleteness("drawElementsInstancedANGLE", false); 1828 markContextChanged(CanvasChanged); 1829 } 1830 1831 void WebGLRenderingContextBase::enable(GLenum cap) 1832 { 1833 if (isContextLost() || !validateCapability("enable", cap)) 1834 return; 1835 if (cap == GL_STENCIL_TEST) { 1836 m_stencilEnabled = true; 1837 applyStencilTest(); 1838 return; 1839 } 1840 if (cap == GL_SCISSOR_TEST) { 1841 m_scissorEnabled = true; 1842 m_drawingBuffer->setScissorEnabled(m_scissorEnabled); 1843 } 1844 webContext()->enable(cap); 1845 } 1846 1847 void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index) 1848 { 1849 if (isContextLost()) 1850 return; 1851 if (index >= m_maxVertexAttribs) { 1852 synthesizeGLError(GL_INVALID_VALUE, "enableVertexAttribArray", "index out of range"); 1853 return; 1854 } 1855 1856 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 1857 state.enabled = true; 1858 1859 m_onePlusMaxEnabledAttribIndex = max(index + 1, m_onePlusMaxEnabledAttribIndex); 1860 1861 webContext()->enableVertexAttribArray(index); 1862 } 1863 1864 void WebGLRenderingContextBase::finish() 1865 { 1866 if (isContextLost()) 1867 return; 1868 webContext()->flush(); // Intentionally a flush, not a finish. 1869 } 1870 1871 void WebGLRenderingContextBase::flush() 1872 { 1873 if (isContextLost()) 1874 return; 1875 webContext()->flush(); 1876 } 1877 1878 void WebGLRenderingContextBase::framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer* buffer) 1879 { 1880 if (isContextLost() || !validateFramebufferFuncParameters("framebufferRenderbuffer", target, attachment)) 1881 return; 1882 if (renderbuffertarget != GL_RENDERBUFFER) { 1883 synthesizeGLError(GL_INVALID_ENUM, "framebufferRenderbuffer", "invalid target"); 1884 return; 1885 } 1886 if (buffer && !buffer->validate(contextGroup(), this)) { 1887 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no buffer or buffer not from this context"); 1888 return; 1889 } 1890 // Don't allow the default framebuffer to be mutated; all current 1891 // implementations use an FBO internally in place of the default 1892 // FBO. 1893 if (!m_framebufferBinding || !m_framebufferBinding->object()) { 1894 synthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound"); 1895 return; 1896 } 1897 Platform3DObject bufferObject = objectOrZero(buffer); 1898 switch (attachment) { 1899 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 1900 if (isDepthStencilSupported() || !buffer) { 1901 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject); 1902 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, bufferObject); 1903 } else { 1904 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(renderbuffertarget, buffer); 1905 if (!emulatedStencilBuffer) { 1906 synthesizeGLError(GL_OUT_OF_MEMORY, "framebufferRenderbuffer", "out of memory"); 1907 return; 1908 } 1909 webContext()->framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, bufferObject); 1910 webContext()->framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, objectOrZero(emulatedStencilBuffer)); 1911 } 1912 break; 1913 default: 1914 webContext()->framebufferRenderbuffer(target, attachment, renderbuffertarget, bufferObject); 1915 } 1916 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, buffer); 1917 applyStencilTest(); 1918 } 1919 1920 void WebGLRenderingContextBase::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture* texture, GLint level) 1921 { 1922 if (isContextLost() || !validateFramebufferFuncParameters("framebufferTexture2D", target, attachment)) 1923 return; 1924 if (level) { 1925 synthesizeGLError(GL_INVALID_VALUE, "framebufferTexture2D", "level not 0"); 1926 return; 1927 } 1928 if (texture && !texture->validate(contextGroup(), this)) { 1929 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no texture or texture not from this context"); 1930 return; 1931 } 1932 // Don't allow the default framebuffer to be mutated; all current 1933 // implementations use an FBO internally in place of the default 1934 // FBO. 1935 if (!m_framebufferBinding || !m_framebufferBinding->object()) { 1936 synthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound"); 1937 return; 1938 } 1939 Platform3DObject textureObject = objectOrZero(texture); 1940 switch (attachment) { 1941 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 1942 webContext()->framebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, textureObject, level); 1943 webContext()->framebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, textureObject, level); 1944 break; 1945 case GL_DEPTH_ATTACHMENT: 1946 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level); 1947 break; 1948 case GL_STENCIL_ATTACHMENT: 1949 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level); 1950 break; 1951 default: 1952 webContext()->framebufferTexture2D(target, attachment, textarget, textureObject, level); 1953 } 1954 m_framebufferBinding->setAttachmentForBoundFramebuffer(attachment, textarget, texture, level); 1955 applyStencilTest(); 1956 } 1957 1958 void WebGLRenderingContextBase::frontFace(GLenum mode) 1959 { 1960 if (isContextLost()) 1961 return; 1962 switch (mode) { 1963 case GL_CW: 1964 case GL_CCW: 1965 break; 1966 default: 1967 synthesizeGLError(GL_INVALID_ENUM, "frontFace", "invalid mode"); 1968 return; 1969 } 1970 webContext()->frontFace(mode); 1971 } 1972 1973 void WebGLRenderingContextBase::generateMipmap(GLenum target) 1974 { 1975 if (isContextLost()) 1976 return; 1977 WebGLTexture* tex = validateTextureBinding("generateMipmap", target, false); 1978 if (!tex) 1979 return; 1980 if (!tex->canGenerateMipmaps()) { 1981 synthesizeGLError(GL_INVALID_OPERATION, "generateMipmap", "level 0 not power of 2 or not all the same size"); 1982 return; 1983 } 1984 if (!validateSettableTexFormat("generateMipmap", tex->getInternalFormat(target, 0))) 1985 return; 1986 1987 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR 1988 // on Mac. Remove the hack once this driver bug is fixed. 1989 #if OS(MACOSX) 1990 bool needToResetMinFilter = false; 1991 if (tex->getMinFilter() != GL_NEAREST_MIPMAP_LINEAR) { 1992 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); 1993 needToResetMinFilter = true; 1994 } 1995 #endif 1996 webContext()->generateMipmap(target); 1997 #if OS(MACOSX) 1998 if (needToResetMinFilter) 1999 webContext()->texParameteri(target, GL_TEXTURE_MIN_FILTER, tex->getMinFilter()); 2000 #endif 2001 tex->generateMipmapLevelInfo(); 2002 } 2003 2004 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveAttrib(WebGLProgram* program, GLuint index) 2005 { 2006 if (isContextLost() || !validateWebGLObject("getActiveAttrib", program)) 2007 return nullptr; 2008 blink::WebGraphicsContext3D::ActiveInfo info; 2009 if (!webContext()->getActiveAttrib(objectOrZero(program), index, info)) 2010 return nullptr; 2011 return WebGLActiveInfo::create(info.name, info.type, info.size); 2012 } 2013 2014 PassRefPtr<WebGLActiveInfo> WebGLRenderingContextBase::getActiveUniform(WebGLProgram* program, GLuint index) 2015 { 2016 if (isContextLost() || !validateWebGLObject("getActiveUniform", program)) 2017 return nullptr; 2018 blink::WebGraphicsContext3D::ActiveInfo info; 2019 if (!webContext()->getActiveUniform(objectOrZero(program), index, info)) 2020 return nullptr; 2021 return WebGLActiveInfo::create(info.name, info.type, info.size); 2022 } 2023 2024 bool WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program, Vector<RefPtr<WebGLShader> >& shaderObjects) 2025 { 2026 shaderObjects.clear(); 2027 if (isContextLost() || !validateWebGLObject("getAttachedShaders", program)) 2028 return false; 2029 2030 const GLenum shaderType[] = { 2031 GL_VERTEX_SHADER, 2032 GL_FRAGMENT_SHADER 2033 }; 2034 for (unsigned i = 0; i < sizeof(shaderType) / sizeof(GLenum); ++i) { 2035 WebGLShader* shader = program->getAttachedShader(shaderType[i]); 2036 if (shader) 2037 shaderObjects.append(shader); 2038 } 2039 return true; 2040 } 2041 2042 GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name) 2043 { 2044 if (isContextLost() || !validateWebGLObject("getAttribLocation", program)) 2045 return -1; 2046 if (!validateLocationLength("getAttribLocation", name)) 2047 return -1; 2048 if (!validateString("getAttribLocation", name)) 2049 return -1; 2050 if (isPrefixReserved(name)) 2051 return -1; 2052 if (!program->linkStatus()) { 2053 synthesizeGLError(GL_INVALID_OPERATION, "getAttribLocation", "program not linked"); 2054 return 0; 2055 } 2056 return webContext()->getAttribLocation(objectOrZero(program), name.utf8().data()); 2057 } 2058 2059 WebGLGetInfo WebGLRenderingContextBase::getBufferParameter(GLenum target, GLenum pname) 2060 { 2061 if (isContextLost()) 2062 return WebGLGetInfo(); 2063 if (target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER) { 2064 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid target"); 2065 return WebGLGetInfo(); 2066 } 2067 2068 if (pname != GL_BUFFER_SIZE && pname != GL_BUFFER_USAGE) { 2069 synthesizeGLError(GL_INVALID_ENUM, "getBufferParameter", "invalid parameter name"); 2070 return WebGLGetInfo(); 2071 } 2072 2073 GLint value = 0; 2074 webContext()->getBufferParameteriv(target, pname, &value); 2075 if (pname == GL_BUFFER_SIZE) 2076 return WebGLGetInfo(value); 2077 return WebGLGetInfo(static_cast<unsigned>(value)); 2078 } 2079 2080 PassRefPtr<WebGLContextAttributes> WebGLRenderingContextBase::getContextAttributes() 2081 { 2082 if (isContextLost()) 2083 return nullptr; 2084 // We always need to return a new WebGLContextAttributes object to 2085 // prevent the user from mutating any cached version. 2086 blink::WebGraphicsContext3D::Attributes attrs = m_drawingBuffer->getActualAttributes(); 2087 RefPtr<WebGLContextAttributes> attributes = m_requestedAttributes->clone(); 2088 // Some requested attributes may not be honored, so we need to query the underlying 2089 // context/drawing buffer and adjust accordingly. 2090 if (m_requestedAttributes->depth() && !attrs.depth) 2091 attributes->setDepth(false); 2092 if (m_requestedAttributes->stencil() && !attrs.stencil) 2093 attributes->setStencil(false); 2094 attributes->setAntialias(m_drawingBuffer->multisample()); 2095 return attributes.release(); 2096 } 2097 2098 GLenum WebGLRenderingContextBase::getError() 2099 { 2100 if (m_lostContextErrors.size()) { 2101 GLenum err = m_lostContextErrors.first(); 2102 m_lostContextErrors.remove(0); 2103 return err; 2104 } 2105 2106 if (isContextLost()) 2107 return GL_NO_ERROR; 2108 2109 return webContext()->getError(); 2110 } 2111 2112 const char* const* WebGLRenderingContextBase::ExtensionTracker::prefixes() const 2113 { 2114 static const char* const unprefixed[] = { "", 0, }; 2115 return m_prefixes ? m_prefixes : unprefixed; 2116 } 2117 2118 bool WebGLRenderingContextBase::ExtensionTracker::matchesNameWithPrefixes(const String& name) const 2119 { 2120 const char* const* prefixSet = prefixes(); 2121 for (; *prefixSet; ++prefixSet) { 2122 String prefixedName = String(*prefixSet) + extensionName(); 2123 if (equalIgnoringCase(prefixedName, name)) { 2124 return true; 2125 } 2126 } 2127 return false; 2128 } 2129 2130 bool WebGLRenderingContextBase::extensionSupportedAndAllowed(const ExtensionTracker* tracker) 2131 { 2132 if (tracker->draft() && !RuntimeEnabledFeatures::webGLDraftExtensionsEnabled()) 2133 return false; 2134 if (!tracker->supported(this)) 2135 return false; 2136 return true; 2137 } 2138 2139 2140 PassRefPtr<WebGLExtension> WebGLRenderingContextBase::getExtension(const String& name) 2141 { 2142 if (isContextLost()) 2143 return nullptr; 2144 2145 for (size_t i = 0; i < m_extensions.size(); ++i) { 2146 ExtensionTracker* tracker = m_extensions[i]; 2147 if (tracker->matchesNameWithPrefixes(name)) { 2148 if (!extensionSupportedAndAllowed(tracker)) 2149 return nullptr; 2150 2151 RefPtr<WebGLExtension> extension = tracker->getExtension(this); 2152 if (extension) 2153 m_extensionEnabled[extension->name()] = true; 2154 return extension.release(); 2155 } 2156 } 2157 2158 return nullptr; 2159 } 2160 2161 WebGLGetInfo WebGLRenderingContextBase::getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname) 2162 { 2163 if (isContextLost() || !validateFramebufferFuncParameters("getFramebufferAttachmentParameter", target, attachment)) 2164 return WebGLGetInfo(); 2165 2166 if (!m_framebufferBinding || !m_framebufferBinding->object()) { 2167 synthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter", "no framebuffer bound"); 2168 return WebGLGetInfo(); 2169 } 2170 2171 WebGLSharedObject* object = m_framebufferBinding->getAttachmentObject(attachment); 2172 if (!object) { 2173 if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) 2174 return WebGLGetInfo(GL_NONE); 2175 // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL 2176 // specifies INVALID_OPERATION. 2177 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name"); 2178 return WebGLGetInfo(); 2179 } 2180 2181 ASSERT(object->isTexture() || object->isRenderbuffer()); 2182 if (object->isTexture()) { 2183 switch (pname) { 2184 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 2185 return WebGLGetInfo(GL_TEXTURE); 2186 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 2187 return WebGLGetInfo(PassRefPtr<WebGLTexture>(static_cast<WebGLTexture*>(object))); 2188 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 2189 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 2190 { 2191 GLint value = 0; 2192 webContext()->getFramebufferAttachmentParameteriv(target, attachment, pname, &value); 2193 return WebGLGetInfo(value); 2194 } 2195 default: 2196 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for texture attachment"); 2197 return WebGLGetInfo(); 2198 } 2199 } else { 2200 switch (pname) { 2201 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 2202 return WebGLGetInfo(GL_RENDERBUFFER); 2203 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 2204 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(static_cast<WebGLRenderbuffer*>(object))); 2205 default: 2206 synthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter", "invalid parameter name for renderbuffer attachment"); 2207 return WebGLGetInfo(); 2208 } 2209 } 2210 } 2211 2212 WebGLGetInfo WebGLRenderingContextBase::getParameter(GLenum pname) 2213 { 2214 if (isContextLost()) 2215 return WebGLGetInfo(); 2216 const int intZero = 0; 2217 switch (pname) { 2218 case GL_ACTIVE_TEXTURE: 2219 return getUnsignedIntParameter(pname); 2220 case GL_ALIASED_LINE_WIDTH_RANGE: 2221 return getWebGLFloatArrayParameter(pname); 2222 case GL_ALIASED_POINT_SIZE_RANGE: 2223 return getWebGLFloatArrayParameter(pname); 2224 case GL_ALPHA_BITS: 2225 return getIntParameter(pname); 2226 case GL_ARRAY_BUFFER_BINDING: 2227 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer)); 2228 case GL_BLEND: 2229 return getBooleanParameter(pname); 2230 case GL_BLEND_COLOR: 2231 return getWebGLFloatArrayParameter(pname); 2232 case GL_BLEND_DST_ALPHA: 2233 return getUnsignedIntParameter(pname); 2234 case GL_BLEND_DST_RGB: 2235 return getUnsignedIntParameter(pname); 2236 case GL_BLEND_EQUATION_ALPHA: 2237 return getUnsignedIntParameter(pname); 2238 case GL_BLEND_EQUATION_RGB: 2239 return getUnsignedIntParameter(pname); 2240 case GL_BLEND_SRC_ALPHA: 2241 return getUnsignedIntParameter(pname); 2242 case GL_BLEND_SRC_RGB: 2243 return getUnsignedIntParameter(pname); 2244 case GL_BLUE_BITS: 2245 return getIntParameter(pname); 2246 case GL_COLOR_CLEAR_VALUE: 2247 return getWebGLFloatArrayParameter(pname); 2248 case GL_COLOR_WRITEMASK: 2249 return getBooleanArrayParameter(pname); 2250 case GL_COMPRESSED_TEXTURE_FORMATS: 2251 return WebGLGetInfo(Uint32Array::create(m_compressedTextureFormats.data(), m_compressedTextureFormats.size())); 2252 case GL_CULL_FACE: 2253 return getBooleanParameter(pname); 2254 case GL_CULL_FACE_MODE: 2255 return getUnsignedIntParameter(pname); 2256 case GL_CURRENT_PROGRAM: 2257 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram)); 2258 case GL_DEPTH_BITS: 2259 if (!m_framebufferBinding && !m_requestedAttributes->depth()) 2260 return WebGLGetInfo(intZero); 2261 return getIntParameter(pname); 2262 case GL_DEPTH_CLEAR_VALUE: 2263 return getFloatParameter(pname); 2264 case GL_DEPTH_FUNC: 2265 return getUnsignedIntParameter(pname); 2266 case GL_DEPTH_RANGE: 2267 return getWebGLFloatArrayParameter(pname); 2268 case GL_DEPTH_TEST: 2269 return getBooleanParameter(pname); 2270 case GL_DEPTH_WRITEMASK: 2271 return getBooleanParameter(pname); 2272 case GL_DITHER: 2273 return getBooleanParameter(pname); 2274 case GL_ELEMENT_ARRAY_BUFFER_BINDING: 2275 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->boundElementArrayBuffer())); 2276 case GL_FRAMEBUFFER_BINDING: 2277 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding)); 2278 case GL_FRONT_FACE: 2279 return getUnsignedIntParameter(pname); 2280 case GL_GENERATE_MIPMAP_HINT: 2281 return getUnsignedIntParameter(pname); 2282 case GL_GREEN_BITS: 2283 return getIntParameter(pname); 2284 case GL_IMPLEMENTATION_COLOR_READ_FORMAT: 2285 return getIntParameter(pname); 2286 case GL_IMPLEMENTATION_COLOR_READ_TYPE: 2287 return getIntParameter(pname); 2288 case GL_LINE_WIDTH: 2289 return getFloatParameter(pname); 2290 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: 2291 return getIntParameter(pname); 2292 case GL_MAX_CUBE_MAP_TEXTURE_SIZE: 2293 return getIntParameter(pname); 2294 case GL_MAX_FRAGMENT_UNIFORM_VECTORS: 2295 return getIntParameter(pname); 2296 case GL_MAX_RENDERBUFFER_SIZE: 2297 return getIntParameter(pname); 2298 case GL_MAX_TEXTURE_IMAGE_UNITS: 2299 return getIntParameter(pname); 2300 case GL_MAX_TEXTURE_SIZE: 2301 return getIntParameter(pname); 2302 case GL_MAX_VARYING_VECTORS: 2303 return getIntParameter(pname); 2304 case GL_MAX_VERTEX_ATTRIBS: 2305 return getIntParameter(pname); 2306 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: 2307 return getIntParameter(pname); 2308 case GL_MAX_VERTEX_UNIFORM_VECTORS: 2309 return getIntParameter(pname); 2310 case GL_MAX_VIEWPORT_DIMS: 2311 return getWebGLIntArrayParameter(pname); 2312 case GL_NUM_SHADER_BINARY_FORMATS: 2313 // FIXME: should we always return 0 for this? 2314 return getIntParameter(pname); 2315 case GL_PACK_ALIGNMENT: 2316 return getIntParameter(pname); 2317 case GL_POLYGON_OFFSET_FACTOR: 2318 return getFloatParameter(pname); 2319 case GL_POLYGON_OFFSET_FILL: 2320 return getBooleanParameter(pname); 2321 case GL_POLYGON_OFFSET_UNITS: 2322 return getFloatParameter(pname); 2323 case GL_RED_BITS: 2324 return getIntParameter(pname); 2325 case GL_RENDERBUFFER_BINDING: 2326 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding)); 2327 case GL_RENDERER: 2328 return WebGLGetInfo(String("WebKit WebGL")); 2329 case GL_SAMPLE_BUFFERS: 2330 return getIntParameter(pname); 2331 case GL_SAMPLE_COVERAGE_INVERT: 2332 return getBooleanParameter(pname); 2333 case GL_SAMPLE_COVERAGE_VALUE: 2334 return getFloatParameter(pname); 2335 case GL_SAMPLES: 2336 return getIntParameter(pname); 2337 case GL_SCISSOR_BOX: 2338 return getWebGLIntArrayParameter(pname); 2339 case GL_SCISSOR_TEST: 2340 return getBooleanParameter(pname); 2341 case GL_SHADING_LANGUAGE_VERSION: 2342 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + String(webContext()->getString(GL_SHADING_LANGUAGE_VERSION)) + ")"); 2343 case GL_STENCIL_BACK_FAIL: 2344 return getUnsignedIntParameter(pname); 2345 case GL_STENCIL_BACK_FUNC: 2346 return getUnsignedIntParameter(pname); 2347 case GL_STENCIL_BACK_PASS_DEPTH_FAIL: 2348 return getUnsignedIntParameter(pname); 2349 case GL_STENCIL_BACK_PASS_DEPTH_PASS: 2350 return getUnsignedIntParameter(pname); 2351 case GL_STENCIL_BACK_REF: 2352 return getIntParameter(pname); 2353 case GL_STENCIL_BACK_VALUE_MASK: 2354 return getUnsignedIntParameter(pname); 2355 case GL_STENCIL_BACK_WRITEMASK: 2356 return getUnsignedIntParameter(pname); 2357 case GL_STENCIL_BITS: 2358 if (!m_framebufferBinding && !m_requestedAttributes->stencil()) 2359 return WebGLGetInfo(intZero); 2360 return getIntParameter(pname); 2361 case GL_STENCIL_CLEAR_VALUE: 2362 return getIntParameter(pname); 2363 case GL_STENCIL_FAIL: 2364 return getUnsignedIntParameter(pname); 2365 case GL_STENCIL_FUNC: 2366 return getUnsignedIntParameter(pname); 2367 case GL_STENCIL_PASS_DEPTH_FAIL: 2368 return getUnsignedIntParameter(pname); 2369 case GL_STENCIL_PASS_DEPTH_PASS: 2370 return getUnsignedIntParameter(pname); 2371 case GL_STENCIL_REF: 2372 return getIntParameter(pname); 2373 case GL_STENCIL_TEST: 2374 return getBooleanParameter(pname); 2375 case GL_STENCIL_VALUE_MASK: 2376 return getUnsignedIntParameter(pname); 2377 case GL_STENCIL_WRITEMASK: 2378 return getUnsignedIntParameter(pname); 2379 case GL_SUBPIXEL_BITS: 2380 return getIntParameter(pname); 2381 case GL_TEXTURE_BINDING_2D: 2382 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding)); 2383 case GL_TEXTURE_BINDING_CUBE_MAP: 2384 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding)); 2385 case GL_UNPACK_ALIGNMENT: 2386 return getIntParameter(pname); 2387 case GC3D_UNPACK_FLIP_Y_WEBGL: 2388 return WebGLGetInfo(m_unpackFlipY); 2389 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL: 2390 return WebGLGetInfo(m_unpackPremultiplyAlpha); 2391 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL: 2392 return WebGLGetInfo(m_unpackColorspaceConversion); 2393 case GL_VENDOR: 2394 return WebGLGetInfo(String("WebKit")); 2395 case GL_VERSION: 2396 return WebGLGetInfo("WebGL 1.0 (" + String(webContext()->getString(GL_VERSION)) + ")"); 2397 case GL_VIEWPORT: 2398 return getWebGLIntArrayParameter(pname); 2399 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives 2400 if (extensionEnabled(OESStandardDerivativesName)) 2401 return getUnsignedIntParameter(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES); 2402 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_standard_derivatives not enabled"); 2403 return WebGLGetInfo(); 2404 case WebGLDebugRendererInfo::UNMASKED_RENDERER_WEBGL: 2405 if (extensionEnabled(WebGLDebugRendererInfoName)) 2406 return WebGLGetInfo(webContext()->getString(GL_RENDERER)); 2407 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled"); 2408 return WebGLGetInfo(); 2409 case WebGLDebugRendererInfo::UNMASKED_VENDOR_WEBGL: 2410 if (extensionEnabled(WebGLDebugRendererInfoName)) 2411 return WebGLGetInfo(webContext()->getString(GL_VENDOR)); 2412 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_debug_renderer_info not enabled"); 2413 return WebGLGetInfo(); 2414 case GL_VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object 2415 if (extensionEnabled(OESVertexArrayObjectName)) { 2416 if (!m_boundVertexArrayObject->isDefaultObject()) 2417 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject)); 2418 return WebGLGetInfo(); 2419 } 2420 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, OES_vertex_array_object not enabled"); 2421 return WebGLGetInfo(); 2422 case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic 2423 if (extensionEnabled(EXTTextureFilterAnisotropicName)) 2424 return getUnsignedIntParameter(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT); 2425 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled"); 2426 return WebGLGetInfo(); 2427 case GL_MAX_COLOR_ATTACHMENTS_EXT: // EXT_draw_buffers BEGIN 2428 if (extensionEnabled(WebGLDrawBuffersName)) 2429 return WebGLGetInfo(maxColorAttachments()); 2430 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled"); 2431 return WebGLGetInfo(); 2432 case GL_MAX_DRAW_BUFFERS_EXT: 2433 if (extensionEnabled(WebGLDrawBuffersName)) 2434 return WebGLGetInfo(maxDrawBuffers()); 2435 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name, WEBGL_draw_buffers not enabled"); 2436 return WebGLGetInfo(); 2437 default: 2438 if (extensionEnabled(WebGLDrawBuffersName) 2439 && pname >= GL_DRAW_BUFFER0_EXT 2440 && pname < static_cast<GLenum>(GL_DRAW_BUFFER0_EXT + maxDrawBuffers())) { 2441 GLint value = GL_NONE; 2442 if (m_framebufferBinding) 2443 value = m_framebufferBinding->getDrawBuffer(pname); 2444 else // emulated backbuffer 2445 value = m_backDrawBuffer; 2446 return WebGLGetInfo(value); 2447 } 2448 synthesizeGLError(GL_INVALID_ENUM, "getParameter", "invalid parameter name"); 2449 return WebGLGetInfo(); 2450 } 2451 } 2452 2453 WebGLGetInfo WebGLRenderingContextBase::getProgramParameter(WebGLProgram* program, GLenum pname) 2454 { 2455 if (isContextLost() || !validateWebGLObject("getProgramParameter", program)) 2456 return WebGLGetInfo(); 2457 2458 GLint value = 0; 2459 switch (pname) { 2460 case GL_DELETE_STATUS: 2461 return WebGLGetInfo(program->isDeleted()); 2462 case GL_VALIDATE_STATUS: 2463 webContext()->getProgramiv(objectOrZero(program), pname, &value); 2464 return WebGLGetInfo(static_cast<bool>(value)); 2465 case GL_LINK_STATUS: 2466 return WebGLGetInfo(program->linkStatus()); 2467 case GL_ATTACHED_SHADERS: 2468 case GL_ACTIVE_ATTRIBUTES: 2469 case GL_ACTIVE_UNIFORMS: 2470 webContext()->getProgramiv(objectOrZero(program), pname, &value); 2471 return WebGLGetInfo(value); 2472 default: 2473 synthesizeGLError(GL_INVALID_ENUM, "getProgramParameter", "invalid parameter name"); 2474 return WebGLGetInfo(); 2475 } 2476 } 2477 2478 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) 2479 { 2480 if (isContextLost()) 2481 return String(); 2482 if (!validateWebGLObject("getProgramInfoLog", program)) 2483 return ""; 2484 return ensureNotNull(webContext()->getProgramInfoLog(objectOrZero(program))); 2485 } 2486 2487 WebGLGetInfo WebGLRenderingContextBase::getRenderbufferParameter(GLenum target, GLenum pname) 2488 { 2489 if (isContextLost()) 2490 return WebGLGetInfo(); 2491 if (target != GL_RENDERBUFFER) { 2492 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid target"); 2493 return WebGLGetInfo(); 2494 } 2495 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { 2496 synthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter", "no renderbuffer bound"); 2497 return WebGLGetInfo(); 2498 } 2499 2500 GLint value = 0; 2501 switch (pname) { 2502 case GL_RENDERBUFFER_WIDTH: 2503 case GL_RENDERBUFFER_HEIGHT: 2504 case GL_RENDERBUFFER_RED_SIZE: 2505 case GL_RENDERBUFFER_GREEN_SIZE: 2506 case GL_RENDERBUFFER_BLUE_SIZE: 2507 case GL_RENDERBUFFER_ALPHA_SIZE: 2508 case GL_RENDERBUFFER_DEPTH_SIZE: 2509 webContext()->getRenderbufferParameteriv(target, pname, &value); 2510 return WebGLGetInfo(value); 2511 case GL_RENDERBUFFER_STENCIL_SIZE: 2512 if (m_renderbufferBinding->emulatedStencilBuffer()) { 2513 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding->emulatedStencilBuffer())); 2514 webContext()->getRenderbufferParameteriv(target, pname, &value); 2515 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get())); 2516 } else { 2517 webContext()->getRenderbufferParameteriv(target, pname, &value); 2518 } 2519 return WebGLGetInfo(value); 2520 case GL_RENDERBUFFER_INTERNAL_FORMAT: 2521 return WebGLGetInfo(m_renderbufferBinding->internalFormat()); 2522 default: 2523 synthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter", "invalid parameter name"); 2524 return WebGLGetInfo(); 2525 } 2526 } 2527 2528 WebGLGetInfo WebGLRenderingContextBase::getShaderParameter(WebGLShader* shader, GLenum pname) 2529 { 2530 if (isContextLost() || !validateWebGLObject("getShaderParameter", shader)) 2531 return WebGLGetInfo(); 2532 GLint value = 0; 2533 switch (pname) { 2534 case GL_DELETE_STATUS: 2535 return WebGLGetInfo(shader->isDeleted()); 2536 case GL_COMPILE_STATUS: 2537 webContext()->getShaderiv(objectOrZero(shader), pname, &value); 2538 return WebGLGetInfo(static_cast<bool>(value)); 2539 case GL_SHADER_TYPE: 2540 webContext()->getShaderiv(objectOrZero(shader), pname, &value); 2541 return WebGLGetInfo(static_cast<unsigned>(value)); 2542 default: 2543 synthesizeGLError(GL_INVALID_ENUM, "getShaderParameter", "invalid parameter name"); 2544 return WebGLGetInfo(); 2545 } 2546 } 2547 2548 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) 2549 { 2550 if (isContextLost()) 2551 return String(); 2552 if (!validateWebGLObject("getShaderInfoLog", shader)) 2553 return ""; 2554 return ensureNotNull(webContext()->getShaderInfoLog(objectOrZero(shader))); 2555 } 2556 2557 PassRefPtr<WebGLShaderPrecisionFormat> WebGLRenderingContextBase::getShaderPrecisionFormat(GLenum shaderType, GLenum precisionType) 2558 { 2559 if (isContextLost()) 2560 return nullptr; 2561 switch (shaderType) { 2562 case GL_VERTEX_SHADER: 2563 case GL_FRAGMENT_SHADER: 2564 break; 2565 default: 2566 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid shader type"); 2567 return nullptr; 2568 } 2569 switch (precisionType) { 2570 case GL_LOW_FLOAT: 2571 case GL_MEDIUM_FLOAT: 2572 case GL_HIGH_FLOAT: 2573 case GL_LOW_INT: 2574 case GL_MEDIUM_INT: 2575 case GL_HIGH_INT: 2576 break; 2577 default: 2578 synthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat", "invalid precision type"); 2579 return nullptr; 2580 } 2581 2582 GLint range[2] = {0, 0}; 2583 GLint precision = 0; 2584 webContext()->getShaderPrecisionFormat(shaderType, precisionType, range, &precision); 2585 return WebGLShaderPrecisionFormat::create(range[0], range[1], precision); 2586 } 2587 2588 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) 2589 { 2590 if (isContextLost()) 2591 return String(); 2592 if (!validateWebGLObject("getShaderSource", shader)) 2593 return ""; 2594 return ensureNotNull(shader->source()); 2595 } 2596 2597 Vector<String> WebGLRenderingContextBase::getSupportedExtensions() 2598 { 2599 Vector<String> result; 2600 if (isContextLost()) 2601 return result; 2602 2603 for (size_t i = 0; i < m_extensions.size(); ++i) { 2604 ExtensionTracker* tracker = m_extensions[i]; 2605 if (extensionSupportedAndAllowed(tracker)) { 2606 const char* const* prefixes = tracker->prefixes(); 2607 for (; *prefixes; ++prefixes) { 2608 String prefixedName = String(*prefixes) + tracker->extensionName(); 2609 result.append(prefixedName); 2610 } 2611 } 2612 } 2613 2614 return result; 2615 } 2616 2617 WebGLGetInfo WebGLRenderingContextBase::getTexParameter(GLenum target, GLenum pname) 2618 { 2619 if (isContextLost()) 2620 return WebGLGetInfo(); 2621 WebGLTexture* tex = validateTextureBinding("getTexParameter", target, false); 2622 if (!tex) 2623 return WebGLGetInfo(); 2624 switch (pname) { 2625 case GL_TEXTURE_MAG_FILTER: 2626 case GL_TEXTURE_MIN_FILTER: 2627 case GL_TEXTURE_WRAP_S: 2628 case GL_TEXTURE_WRAP_T: 2629 { 2630 GLint value = 0; 2631 webContext()->getTexParameteriv(target, pname, &value); 2632 return WebGLGetInfo(static_cast<unsigned>(value)); 2633 } 2634 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic 2635 if (extensionEnabled(EXTTextureFilterAnisotropicName)) { 2636 GLfloat value = 0.f; 2637 webContext()->getTexParameterfv(target, pname, &value); 2638 return WebGLGetInfo(value); 2639 } 2640 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name, EXT_texture_filter_anisotropic not enabled"); 2641 return WebGLGetInfo(); 2642 default: 2643 synthesizeGLError(GL_INVALID_ENUM, "getTexParameter", "invalid parameter name"); 2644 return WebGLGetInfo(); 2645 } 2646 } 2647 2648 WebGLGetInfo WebGLRenderingContextBase::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation) 2649 { 2650 if (isContextLost() || !validateWebGLObject("getUniform", program)) 2651 return WebGLGetInfo(); 2652 if (!uniformLocation || uniformLocation->program() != program) { 2653 synthesizeGLError(GL_INVALID_OPERATION, "getUniform", "no uniformlocation or not valid for this program"); 2654 return WebGLGetInfo(); 2655 } 2656 GLint location = uniformLocation->location(); 2657 2658 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it 2659 GLint activeUniforms = 0; 2660 webContext()->getProgramiv(objectOrZero(program), GL_ACTIVE_UNIFORMS, &activeUniforms); 2661 for (GLint i = 0; i < activeUniforms; i++) { 2662 blink::WebGraphicsContext3D::ActiveInfo info; 2663 if (!webContext()->getActiveUniform(objectOrZero(program), i, info)) 2664 return WebGLGetInfo(); 2665 String name = info.name; 2666 StringBuilder nameBuilder; 2667 // Strip "[0]" from the name if it's an array. 2668 if (info.size > 1 && name.endsWith("[0]")) 2669 info.name = name.left(name.length() - 3); 2670 // If it's an array, we need to iterate through each element, appending "[index]" to the name. 2671 for (GLint index = 0; index < info.size; ++index) { 2672 nameBuilder.clear(); 2673 nameBuilder.append(info.name); 2674 if (info.size > 1 && index >= 1) { 2675 nameBuilder.append('['); 2676 nameBuilder.append(String::number(index)); 2677 nameBuilder.append(']'); 2678 } 2679 // Now need to look this up by name again to find its location 2680 GLint loc = webContext()->getUniformLocation(objectOrZero(program), nameBuilder.toString().utf8().data()); 2681 if (loc == location) { 2682 // Found it. Use the type in the ActiveInfo to determine the return type. 2683 GLenum baseType; 2684 unsigned length; 2685 switch (info.type) { 2686 case GL_BOOL: 2687 baseType = GL_BOOL; 2688 length = 1; 2689 break; 2690 case GL_BOOL_VEC2: 2691 baseType = GL_BOOL; 2692 length = 2; 2693 break; 2694 case GL_BOOL_VEC3: 2695 baseType = GL_BOOL; 2696 length = 3; 2697 break; 2698 case GL_BOOL_VEC4: 2699 baseType = GL_BOOL; 2700 length = 4; 2701 break; 2702 case GL_INT: 2703 baseType = GL_INT; 2704 length = 1; 2705 break; 2706 case GL_INT_VEC2: 2707 baseType = GL_INT; 2708 length = 2; 2709 break; 2710 case GL_INT_VEC3: 2711 baseType = GL_INT; 2712 length = 3; 2713 break; 2714 case GL_INT_VEC4: 2715 baseType = GL_INT; 2716 length = 4; 2717 break; 2718 case GL_FLOAT: 2719 baseType = GL_FLOAT; 2720 length = 1; 2721 break; 2722 case GL_FLOAT_VEC2: 2723 baseType = GL_FLOAT; 2724 length = 2; 2725 break; 2726 case GL_FLOAT_VEC3: 2727 baseType = GL_FLOAT; 2728 length = 3; 2729 break; 2730 case GL_FLOAT_VEC4: 2731 baseType = GL_FLOAT; 2732 length = 4; 2733 break; 2734 case GL_FLOAT_MAT2: 2735 baseType = GL_FLOAT; 2736 length = 4; 2737 break; 2738 case GL_FLOAT_MAT3: 2739 baseType = GL_FLOAT; 2740 length = 9; 2741 break; 2742 case GL_FLOAT_MAT4: 2743 baseType = GL_FLOAT; 2744 length = 16; 2745 break; 2746 case GL_SAMPLER_2D: 2747 case GL_SAMPLER_CUBE: 2748 baseType = GL_INT; 2749 length = 1; 2750 break; 2751 default: 2752 // Can't handle this type 2753 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unhandled type"); 2754 return WebGLGetInfo(); 2755 } 2756 switch (baseType) { 2757 case GL_FLOAT: { 2758 GLfloat value[16] = {0}; 2759 webContext()->getUniformfv(objectOrZero(program), location, value); 2760 if (length == 1) 2761 return WebGLGetInfo(value[0]); 2762 return WebGLGetInfo(Float32Array::create(value, length)); 2763 } 2764 case GL_INT: { 2765 GLint value[4] = {0}; 2766 webContext()->getUniformiv(objectOrZero(program), location, value); 2767 if (length == 1) 2768 return WebGLGetInfo(value[0]); 2769 return WebGLGetInfo(Int32Array::create(value, length)); 2770 } 2771 case GL_BOOL: { 2772 GLint value[4] = {0}; 2773 webContext()->getUniformiv(objectOrZero(program), location, value); 2774 if (length > 1) { 2775 bool boolValue[16] = {0}; 2776 for (unsigned j = 0; j < length; j++) 2777 boolValue[j] = static_cast<bool>(value[j]); 2778 return WebGLGetInfo(boolValue, length); 2779 } 2780 return WebGLGetInfo(static_cast<bool>(value[0])); 2781 } 2782 default: 2783 notImplemented(); 2784 } 2785 } 2786 } 2787 } 2788 // If we get here, something went wrong in our unfortunately complex logic above 2789 synthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error"); 2790 return WebGLGetInfo(); 2791 } 2792 2793 PassRefPtr<WebGLUniformLocation> WebGLRenderingContextBase::getUniformLocation(WebGLProgram* program, const String& name) 2794 { 2795 if (isContextLost() || !validateWebGLObject("getUniformLocation", program)) 2796 return nullptr; 2797 if (!validateLocationLength("getUniformLocation", name)) 2798 return nullptr; 2799 if (!validateString("getUniformLocation", name)) 2800 return nullptr; 2801 if (isPrefixReserved(name)) 2802 return nullptr; 2803 if (!program->linkStatus()) { 2804 synthesizeGLError(GL_INVALID_OPERATION, "getUniformLocation", "program not linked"); 2805 return nullptr; 2806 } 2807 GLint uniformLocation = webContext()->getUniformLocation(objectOrZero(program), name.utf8().data()); 2808 if (uniformLocation == -1) 2809 return nullptr; 2810 return WebGLUniformLocation::create(program, uniformLocation); 2811 } 2812 2813 WebGLGetInfo WebGLRenderingContextBase::getVertexAttrib(GLuint index, GLenum pname) 2814 { 2815 if (isContextLost()) 2816 return WebGLGetInfo(); 2817 if (index >= m_maxVertexAttribs) { 2818 synthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib", "index out of range"); 2819 return WebGLGetInfo(); 2820 } 2821 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 2822 2823 if (extensionEnabled(ANGLEInstancedArraysName) && pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE) 2824 return WebGLGetInfo(state.divisor); 2825 2826 switch (pname) { 2827 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 2828 if (!state.bufferBinding || !state.bufferBinding->object()) 2829 return WebGLGetInfo(); 2830 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding)); 2831 case GL_VERTEX_ATTRIB_ARRAY_ENABLED: 2832 return WebGLGetInfo(state.enabled); 2833 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: 2834 return WebGLGetInfo(state.normalized); 2835 case GL_VERTEX_ATTRIB_ARRAY_SIZE: 2836 return WebGLGetInfo(state.size); 2837 case GL_VERTEX_ATTRIB_ARRAY_STRIDE: 2838 return WebGLGetInfo(state.originalStride); 2839 case GL_VERTEX_ATTRIB_ARRAY_TYPE: 2840 return WebGLGetInfo(state.type); 2841 case GL_CURRENT_VERTEX_ATTRIB: 2842 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4)); 2843 default: 2844 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib", "invalid parameter name"); 2845 return WebGLGetInfo(); 2846 } 2847 } 2848 2849 long long WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, GLenum pname) 2850 { 2851 if (isContextLost()) 2852 return 0; 2853 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER) { 2854 synthesizeGLError(GL_INVALID_ENUM, "getVertexAttribOffset", "invalid parameter name"); 2855 return 0; 2856 } 2857 GLsizeiptr result = webContext()->getVertexAttribOffset(index, pname); 2858 return static_cast<long long>(result); 2859 } 2860 2861 void WebGLRenderingContextBase::hint(GLenum target, GLenum mode) 2862 { 2863 if (isContextLost()) 2864 return; 2865 bool isValid = false; 2866 switch (target) { 2867 case GL_GENERATE_MIPMAP_HINT: 2868 isValid = true; 2869 break; 2870 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives 2871 if (extensionEnabled(OESStandardDerivativesName)) 2872 isValid = true; 2873 break; 2874 } 2875 if (!isValid) { 2876 synthesizeGLError(GL_INVALID_ENUM, "hint", "invalid target"); 2877 return; 2878 } 2879 webContext()->hint(target, mode); 2880 } 2881 2882 GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer) 2883 { 2884 if (!buffer || isContextLost()) 2885 return 0; 2886 2887 if (!buffer->hasEverBeenBound()) 2888 return 0; 2889 2890 return webContext()->isBuffer(buffer->object()); 2891 } 2892 2893 bool WebGLRenderingContextBase::isContextLost() const 2894 { 2895 return m_contextLost; 2896 } 2897 2898 GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap) 2899 { 2900 if (isContextLost() || !validateCapability("isEnabled", cap)) 2901 return 0; 2902 if (cap == GL_STENCIL_TEST) 2903 return m_stencilEnabled; 2904 return webContext()->isEnabled(cap); 2905 } 2906 2907 GLboolean WebGLRenderingContextBase::isFramebuffer(WebGLFramebuffer* framebuffer) 2908 { 2909 if (!framebuffer || isContextLost()) 2910 return 0; 2911 2912 if (!framebuffer->hasEverBeenBound()) 2913 return 0; 2914 2915 return webContext()->isFramebuffer(framebuffer->object()); 2916 } 2917 2918 GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program) 2919 { 2920 if (!program || isContextLost()) 2921 return 0; 2922 2923 return webContext()->isProgram(program->object()); 2924 } 2925 2926 GLboolean WebGLRenderingContextBase::isRenderbuffer(WebGLRenderbuffer* renderbuffer) 2927 { 2928 if (!renderbuffer || isContextLost()) 2929 return 0; 2930 2931 if (!renderbuffer->hasEverBeenBound()) 2932 return 0; 2933 2934 return webContext()->isRenderbuffer(renderbuffer->object()); 2935 } 2936 2937 GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader) 2938 { 2939 if (!shader || isContextLost()) 2940 return 0; 2941 2942 return webContext()->isShader(shader->object()); 2943 } 2944 2945 GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture) 2946 { 2947 if (!texture || isContextLost()) 2948 return 0; 2949 2950 if (!texture->hasEverBeenBound()) 2951 return 0; 2952 2953 return webContext()->isTexture(texture->object()); 2954 } 2955 2956 void WebGLRenderingContextBase::lineWidth(GLfloat width) 2957 { 2958 if (isContextLost()) 2959 return; 2960 webContext()->lineWidth(width); 2961 } 2962 2963 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program) 2964 { 2965 if (isContextLost() || !validateWebGLObject("linkProgram", program)) 2966 return; 2967 2968 webContext()->linkProgram(objectOrZero(program)); 2969 program->increaseLinkCount(); 2970 } 2971 2972 void WebGLRenderingContextBase::pixelStorei(GLenum pname, GLint param) 2973 { 2974 if (isContextLost()) 2975 return; 2976 switch (pname) { 2977 case GC3D_UNPACK_FLIP_Y_WEBGL: 2978 m_unpackFlipY = param; 2979 break; 2980 case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL: 2981 m_unpackPremultiplyAlpha = param; 2982 break; 2983 case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL: 2984 if (static_cast<GLenum>(param) == GC3D_BROWSER_DEFAULT_WEBGL || param == GL_NONE) { 2985 m_unpackColorspaceConversion = static_cast<GLenum>(param); 2986 } else { 2987 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL"); 2988 return; 2989 } 2990 break; 2991 case GL_PACK_ALIGNMENT: 2992 case GL_UNPACK_ALIGNMENT: 2993 if (param == 1 || param == 2 || param == 4 || param == 8) { 2994 if (pname == GL_PACK_ALIGNMENT) { 2995 m_packAlignment = param; 2996 m_drawingBuffer->setPackAlignment(param); 2997 } else { // GL_UNPACK_ALIGNMENT: 2998 m_unpackAlignment = param; 2999 } 3000 webContext()->pixelStorei(pname, param); 3001 } else { 3002 synthesizeGLError(GL_INVALID_VALUE, "pixelStorei", "invalid parameter for alignment"); 3003 return; 3004 } 3005 break; 3006 default: 3007 synthesizeGLError(GL_INVALID_ENUM, "pixelStorei", "invalid parameter name"); 3008 return; 3009 } 3010 } 3011 3012 void WebGLRenderingContextBase::polygonOffset(GLfloat factor, GLfloat units) 3013 { 3014 if (isContextLost()) 3015 return; 3016 webContext()->polygonOffset(factor, units); 3017 } 3018 3019 void WebGLRenderingContextBase::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels) 3020 { 3021 if (isContextLost()) 3022 return; 3023 // Due to WebGL's same-origin restrictions, it is not possible to 3024 // taint the origin using the WebGL API. 3025 ASSERT(canvas()->originClean()); 3026 // Validate input parameters. 3027 if (!pixels) { 3028 synthesizeGLError(GL_INVALID_VALUE, "readPixels", "no destination ArrayBufferView"); 3029 return; 3030 } 3031 switch (format) { 3032 case GL_ALPHA: 3033 case GL_RGB: 3034 case GL_RGBA: 3035 break; 3036 default: 3037 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid format"); 3038 return; 3039 } 3040 3041 ArrayBufferView::ViewType expectedViewType; 3042 3043 switch (type) { 3044 case GL_UNSIGNED_BYTE: 3045 expectedViewType = ArrayBufferView::TypeUint8; 3046 break; 3047 case GL_UNSIGNED_SHORT_5_6_5: 3048 case GL_UNSIGNED_SHORT_4_4_4_4: 3049 case GL_UNSIGNED_SHORT_5_5_5_1: 3050 expectedViewType = ArrayBufferView::TypeUint16; 3051 break; 3052 case GL_FLOAT: 3053 expectedViewType = ArrayBufferView::TypeFloat32; 3054 break; 3055 case GL_HALF_FLOAT_OES: 3056 expectedViewType = ArrayBufferView::TypeUint16; 3057 break; 3058 default: 3059 synthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type"); 3060 return; 3061 } 3062 if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) { 3063 // Check against the implementation color read format and type. 3064 blink::WGC3Dint implFormat = 0, implType = 0; 3065 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &implFormat); 3066 webContext()->getIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &implType); 3067 if (!implFormat || !implType || format != static_cast<GLenum>(implFormat) || type != static_cast<GLenum>(implType)) { 3068 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "format/type not RGBA/UNSIGNED_BYTE or implementation-defined values"); 3069 return; 3070 } 3071 } 3072 // Validate array type against pixel type. 3073 if (pixels->type() != expectedViewType) { 3074 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView was the wrong type for the pixel format"); 3075 return; 3076 } 3077 const char* reason = "framebuffer incomplete"; 3078 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 3079 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason); 3080 return; 3081 } 3082 // Calculate array size, taking into consideration of PACK_ALIGNMENT. 3083 unsigned totalBytesRequired = 0; 3084 unsigned padding = 0; 3085 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding); 3086 if (error != GL_NO_ERROR) { 3087 synthesizeGLError(error, "readPixels", "invalid dimensions"); 3088 return; 3089 } 3090 if (pixels->byteLength() < totalBytesRequired) { 3091 synthesizeGLError(GL_INVALID_OPERATION, "readPixels", "ArrayBufferView not large enough for dimensions"); 3092 return; 3093 } 3094 3095 clearIfComposited(); 3096 void* data = pixels->baseAddress(); 3097 3098 { 3099 ScopedDrawingBufferBinder binder(m_drawingBuffer.get(), m_framebufferBinding.get()); 3100 webContext()->readPixels(x, y, width, height, format, type, data); 3101 } 3102 3103 #if OS(MACOSX) 3104 // FIXME: remove this section when GL driver bug on Mac is fixed, i.e., 3105 // when alpha is off, readPixels should set alpha to 255 instead of 0. 3106 if (!m_framebufferBinding && !m_drawingBuffer->getActualAttributes().alpha) { 3107 unsigned char* pixels = reinterpret_cast<unsigned char*>(data); 3108 for (GLsizei iy = 0; iy < height; ++iy) { 3109 for (GLsizei ix = 0; ix < width; ++ix) { 3110 pixels[3] = 255; 3111 pixels += 4; 3112 } 3113 pixels += padding; 3114 } 3115 } 3116 #endif 3117 } 3118 3119 void WebGLRenderingContextBase::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) 3120 { 3121 if (isContextLost()) 3122 return; 3123 if (target != GL_RENDERBUFFER) { 3124 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid target"); 3125 return; 3126 } 3127 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { 3128 synthesizeGLError(GL_INVALID_OPERATION, "renderbufferStorage", "no bound renderbuffer"); 3129 return; 3130 } 3131 if (!validateSize("renderbufferStorage", width, height)) 3132 return; 3133 switch (internalformat) { 3134 case GL_DEPTH_COMPONENT16: 3135 case GL_RGBA4: 3136 case GL_RGB5_A1: 3137 case GL_RGB565: 3138 case GL_STENCIL_INDEX8: 3139 webContext()->renderbufferStorage(target, internalformat, width, height); 3140 m_renderbufferBinding->setInternalFormat(internalformat); 3141 m_renderbufferBinding->setSize(width, height); 3142 m_renderbufferBinding->deleteEmulatedStencilBuffer(webContext()); 3143 break; 3144 case GL_DEPTH_STENCIL_OES: 3145 if (isDepthStencilSupported()) { 3146 webContext()->renderbufferStorage(target, GL_DEPTH24_STENCIL8_OES, width, height); 3147 } else { 3148 WebGLRenderbuffer* emulatedStencilBuffer = ensureEmulatedStencilBuffer(target, m_renderbufferBinding.get()); 3149 if (!emulatedStencilBuffer) { 3150 synthesizeGLError(GL_OUT_OF_MEMORY, "renderbufferStorage", "out of memory"); 3151 return; 3152 } 3153 webContext()->renderbufferStorage(target, GL_DEPTH_COMPONENT16, width, height); 3154 webContext()->bindRenderbuffer(target, objectOrZero(emulatedStencilBuffer)); 3155 webContext()->renderbufferStorage(target, GL_STENCIL_INDEX8, width, height); 3156 webContext()->bindRenderbuffer(target, objectOrZero(m_renderbufferBinding.get())); 3157 emulatedStencilBuffer->setSize(width, height); 3158 emulatedStencilBuffer->setInternalFormat(GL_STENCIL_INDEX8); 3159 } 3160 m_renderbufferBinding->setSize(width, height); 3161 m_renderbufferBinding->setInternalFormat(internalformat); 3162 break; 3163 default: 3164 synthesizeGLError(GL_INVALID_ENUM, "renderbufferStorage", "invalid internalformat"); 3165 return; 3166 } 3167 applyStencilTest(); 3168 } 3169 3170 void WebGLRenderingContextBase::sampleCoverage(GLfloat value, GLboolean invert) 3171 { 3172 if (isContextLost()) 3173 return; 3174 webContext()->sampleCoverage(value, invert); 3175 } 3176 3177 void WebGLRenderingContextBase::scissor(GLint x, GLint y, GLsizei width, GLsizei height) 3178 { 3179 if (isContextLost()) 3180 return; 3181 if (!validateSize("scissor", width, height)) 3182 return; 3183 webContext()->scissor(x, y, width, height); 3184 } 3185 3186 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string) 3187 { 3188 if (isContextLost() || !validateWebGLObject("shaderSource", shader)) 3189 return; 3190 String stringWithoutComments = StripComments(string).result(); 3191 if (!validateString("shaderSource", stringWithoutComments)) 3192 return; 3193 shader->setSource(string); 3194 webContext()->shaderSource(objectOrZero(shader), stringWithoutComments.utf8().data()); 3195 } 3196 3197 void WebGLRenderingContextBase::stencilFunc(GLenum func, GLint ref, GLuint mask) 3198 { 3199 if (isContextLost()) 3200 return; 3201 if (!validateStencilOrDepthFunc("stencilFunc", func)) 3202 return; 3203 m_stencilFuncRef = ref; 3204 m_stencilFuncRefBack = ref; 3205 m_stencilFuncMask = mask; 3206 m_stencilFuncMaskBack = mask; 3207 webContext()->stencilFunc(func, ref, mask); 3208 } 3209 3210 void WebGLRenderingContextBase::stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) 3211 { 3212 if (isContextLost()) 3213 return; 3214 if (!validateStencilOrDepthFunc("stencilFuncSeparate", func)) 3215 return; 3216 switch (face) { 3217 case GL_FRONT_AND_BACK: 3218 m_stencilFuncRef = ref; 3219 m_stencilFuncRefBack = ref; 3220 m_stencilFuncMask = mask; 3221 m_stencilFuncMaskBack = mask; 3222 break; 3223 case GL_FRONT: 3224 m_stencilFuncRef = ref; 3225 m_stencilFuncMask = mask; 3226 break; 3227 case GL_BACK: 3228 m_stencilFuncRefBack = ref; 3229 m_stencilFuncMaskBack = mask; 3230 break; 3231 default: 3232 synthesizeGLError(GL_INVALID_ENUM, "stencilFuncSeparate", "invalid face"); 3233 return; 3234 } 3235 webContext()->stencilFuncSeparate(face, func, ref, mask); 3236 } 3237 3238 void WebGLRenderingContextBase::stencilMask(GLuint mask) 3239 { 3240 if (isContextLost()) 3241 return; 3242 m_stencilMask = mask; 3243 m_stencilMaskBack = mask; 3244 webContext()->stencilMask(mask); 3245 } 3246 3247 void WebGLRenderingContextBase::stencilMaskSeparate(GLenum face, GLuint mask) 3248 { 3249 if (isContextLost()) 3250 return; 3251 switch (face) { 3252 case GL_FRONT_AND_BACK: 3253 m_stencilMask = mask; 3254 m_stencilMaskBack = mask; 3255 break; 3256 case GL_FRONT: 3257 m_stencilMask = mask; 3258 break; 3259 case GL_BACK: 3260 m_stencilMaskBack = mask; 3261 break; 3262 default: 3263 synthesizeGLError(GL_INVALID_ENUM, "stencilMaskSeparate", "invalid face"); 3264 return; 3265 } 3266 webContext()->stencilMaskSeparate(face, mask); 3267 } 3268 3269 void WebGLRenderingContextBase::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) 3270 { 3271 if (isContextLost()) 3272 return; 3273 webContext()->stencilOp(fail, zfail, zpass); 3274 } 3275 3276 void WebGLRenderingContextBase::stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) 3277 { 3278 if (isContextLost()) 3279 return; 3280 webContext()->stencilOpSeparate(face, fail, zfail, zpass); 3281 } 3282 3283 GLenum WebGLRenderingContextBase::convertTexInternalFormat(GLenum internalformat, GLenum type) 3284 { 3285 // Convert to sized internal formats that are renderable with GL_CHROMIUM_color_buffer_float_rgb(a). 3286 if (type == GL_FLOAT && internalformat == GL_RGBA 3287 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgba")) 3288 return GL_RGBA32F_EXT; 3289 if (type == GL_FLOAT && internalformat == GL_RGB 3290 && extensionsUtil()->isExtensionEnabled("GL_CHROMIUM_color_buffer_float_rgb")) 3291 return GL_RGB32F_EXT; 3292 return internalformat; 3293 } 3294 3295 void WebGLRenderingContextBase::texImage2DBase(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState) 3296 { 3297 // All calling functions check isContextLost, so a duplicate check is not needed here. 3298 // FIXME: Handle errors. 3299 WebGLTexture* tex = validateTextureBinding("texImage2D", target, true); 3300 ASSERT(validateTexFuncParameters("texImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, format, type)); 3301 ASSERT(tex); 3302 ASSERT(!level || !WebGLTexture::isNPOT(width, height)); 3303 ASSERT(!pixels || validateSettableTexFormat("texImage2D", internalformat)); 3304 webContext()->texImage2D(target, level, convertTexInternalFormat(internalformat, type), width, height, border, format, type, pixels); 3305 tex->setLevelInfo(target, level, internalformat, width, height, type); 3306 } 3307 3308 void WebGLRenderingContextBase::texImage2DImpl(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, Image* image, WebGLImageConversion::ImageHtmlDomSource domSource, bool flipY, bool premultiplyAlpha, ExceptionState& exceptionState) 3309 { 3310 // All calling functions check isContextLost, so a duplicate check is not needed here. 3311 Vector<uint8_t> data; 3312 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE); 3313 if (!imageExtractor.extractSucceeded()) { 3314 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data"); 3315 return; 3316 } 3317 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat(); 3318 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp(); 3319 const void* imagePixelData = imageExtractor.imagePixelData(); 3320 3321 bool needConversion = true; 3322 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY) 3323 needConversion = false; 3324 else { 3325 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) { 3326 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "packImage error"); 3327 return; 3328 } 3329 } 3330 3331 if (m_unpackAlignment != 1) 3332 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3333 texImage2DBase(target, level, internalformat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), 0, format, type, needConversion ? data.data() : imagePixelData, exceptionState); 3334 if (m_unpackAlignment != 1) 3335 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3336 } 3337 3338 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) 3339 { 3340 if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type)) 3341 return false; 3342 3343 WebGLTexture* texture = validateTextureBinding(functionName, target, true); 3344 if (!texture) 3345 return false; 3346 3347 if (functionType == NotTexSubImage2D) { 3348 if (level && WebGLTexture::isNPOT(width, height)) { 3349 synthesizeGLError(GL_INVALID_VALUE, functionName, "level > 0 not power of 2"); 3350 return false; 3351 } 3352 // For SourceArrayBufferView, function validateTexFuncData() would handle whether to validate the SettableTexFormat 3353 // by checking if the ArrayBufferView is null or not. 3354 if (sourceType != SourceArrayBufferView) { 3355 if (!validateSettableTexFormat(functionName, format)) 3356 return false; 3357 } 3358 } else { 3359 if (!validateSettableTexFormat(functionName, format)) 3360 return false; 3361 if (!validateSize(functionName, xoffset, yoffset)) 3362 return false; 3363 // Before checking if it is in the range, check if overflow happens first. 3364 if (xoffset + width < 0 || yoffset + height < 0) { 3365 synthesizeGLError(GL_INVALID_VALUE, functionName, "bad dimensions"); 3366 return false; 3367 } 3368 if (xoffset + width > texture->getWidth(target, level) || yoffset + height > texture->getHeight(target, level)) { 3369 synthesizeGLError(GL_INVALID_VALUE, functionName, "dimensions out of range"); 3370 return false; 3371 } 3372 if (texture->getInternalFormat(target, level) != format || texture->getType(target, level) != type) { 3373 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type and format do not match texture"); 3374 return false; 3375 } 3376 } 3377 3378 return true; 3379 } 3380 3381 bool WebGLRenderingContextBase::validateValueFitNonNegInt32(const char* functionName, const char* paramName, long long value) 3382 { 3383 if (value < 0) { 3384 String errorMsg = String(paramName) + " < 0"; 3385 synthesizeGLError(GL_INVALID_VALUE, functionName, errorMsg.ascii().data()); 3386 return false; 3387 } 3388 if (value > static_cast<long long>(std::numeric_limits<int>::max())) { 3389 String errorMsg = String(paramName) + " more than 32-bit"; 3390 synthesizeGLError(GL_INVALID_OPERATION, functionName, errorMsg.ascii().data()); 3391 return false; 3392 } 3393 return true; 3394 } 3395 3396 PassRefPtr<Image> WebGLRenderingContextBase::drawImageIntoBuffer(Image* image, int width, int height, const char* functionName) 3397 { 3398 IntSize size(width, height); 3399 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size); 3400 if (!buf) { 3401 synthesizeGLError(GL_OUT_OF_MEMORY, functionName, "out of memory"); 3402 return nullptr; 3403 } 3404 3405 IntRect srcRect(IntPoint(), image->size()); 3406 IntRect destRect(0, 0, size.width(), size.height()); 3407 buf->context()->drawImage(image, destRect, srcRect); 3408 return buf->copyImage(ImageBuffer::fastCopyImageMode()); 3409 } 3410 3411 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, 3412 GLsizei width, GLsizei height, GLint border, 3413 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState) 3414 { 3415 if (isContextLost() || !validateTexFuncData("texImage2D", level, width, height, format, type, pixels, NullAllowed) 3416 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceArrayBufferView, target, level, internalformat, width, height, border, format, type, 0, 0)) 3417 return; 3418 void* data = pixels ? pixels->baseAddress() : 0; 3419 Vector<uint8_t> tempData; 3420 bool changeUnpackAlignment = false; 3421 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) { 3422 if (!WebGLImageConversion::extractTextureData(width, height, format, type, m_unpackAlignment, m_unpackFlipY, m_unpackPremultiplyAlpha, data, tempData)) 3423 return; 3424 data = tempData.data(); 3425 changeUnpackAlignment = true; 3426 } 3427 if (changeUnpackAlignment) 3428 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3429 texImage2DBase(target, level, internalformat, width, height, border, format, type, data, exceptionState); 3430 if (changeUnpackAlignment) 3431 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3432 } 3433 3434 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, 3435 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState) 3436 { 3437 if (isContextLost() || !pixels || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceImageData, target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, 0, 0)) 3438 return; 3439 Vector<uint8_t> data; 3440 bool needConversion = true; 3441 // The data from ImageData is always of format RGBA8. 3442 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required. 3443 if (!m_unpackFlipY && !m_unpackPremultiplyAlpha && format == GL_RGBA && type == GL_UNSIGNED_BYTE) 3444 needConversion = false; 3445 else { 3446 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { 3447 synthesizeGLError(GL_INVALID_VALUE, "texImage2D", "bad image data"); 3448 return; 3449 } 3450 } 3451 if (m_unpackAlignment != 1) 3452 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3453 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState); 3454 if (m_unpackAlignment != 1) 3455 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3456 } 3457 3458 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, 3459 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState) 3460 { 3461 if (isContextLost() || !validateHTMLImageElement("texImage2D", image, exceptionState)) 3462 return; 3463 3464 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer()); 3465 if (imageForRender->isSVGImage()) 3466 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texImage2D"); 3467 3468 if (!imageForRender || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLImageElement, target, level, internalformat, imageForRender->width(), imageForRender->height(), 0, format, type, 0, 0)) 3469 return; 3470 3471 texImage2DImpl(target, level, internalformat, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3472 } 3473 3474 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, 3475 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState) 3476 { 3477 if (isContextLost() || !validateHTMLCanvasElement("texImage2D", canvas, exceptionState) || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLCanvasElement, target, level, internalformat, canvas->width(), canvas->height(), 0, format, type, 0, 0)) 3478 return; 3479 3480 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true); 3481 3482 // If possible, copy from the canvas element directly to the texture 3483 // via the GPU, without a read-back to system memory. 3484 if (GL_TEXTURE_2D == target && texture) { 3485 ScopedTexture2DRestorer restorer(this); 3486 3487 if (!canvas->is3D()) { 3488 ImageBuffer* buffer = canvas->buffer(); 3489 if (buffer && buffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type, 3490 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) { 3491 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type); 3492 return; 3493 } 3494 } else { 3495 WebGLRenderingContextBase* gl = toWebGLRenderingContextBase(canvas->renderingContext()); 3496 ScopedTexture2DRestorer restorer(gl); 3497 if (gl && gl->m_drawingBuffer->copyToPlatformTexture(webContext(), texture->object(), internalformat, type, 3498 level, m_unpackPremultiplyAlpha, m_unpackFlipY)) { 3499 texture->setLevelInfo(target, level, internalformat, canvas->width(), canvas->height(), type); 3500 return; 3501 } 3502 } 3503 } 3504 3505 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData(); 3506 if (imageData) 3507 texImage2D(target, level, internalformat, format, type, imageData.get(), exceptionState); 3508 else 3509 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3510 } 3511 3512 PassRefPtr<Image> WebGLRenderingContextBase::videoFrameToImage(HTMLVideoElement* video, BackingStoreCopy backingStoreCopy) 3513 { 3514 IntSize size(video->videoWidth(), video->videoHeight()); 3515 ImageBuffer* buf = m_generatedImageCache.imageBuffer(size); 3516 if (!buf) { 3517 synthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory"); 3518 return nullptr; 3519 } 3520 IntRect destRect(0, 0, size.width(), size.height()); 3521 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback. 3522 video->paintCurrentFrameInContext(buf->context(), destRect); 3523 return buf->copyImage(backingStoreCopy); 3524 } 3525 3526 void WebGLRenderingContextBase::texImage2D(GLenum target, GLint level, GLenum internalformat, 3527 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState) 3528 { 3529 if (isContextLost() || !validateHTMLVideoElement("texImage2D", video, exceptionState) 3530 || !validateTexFunc("texImage2D", NotTexSubImage2D, SourceHTMLVideoElement, target, level, internalformat, video->videoWidth(), video->videoHeight(), 0, format, type, 0, 0)) 3531 return; 3532 3533 // Go through the fast path doing a GPU-GPU textures copy without a readback to system memory if possible. 3534 // Otherwise, it will fall back to the normal SW path. 3535 WebGLTexture* texture = validateTextureBinding("texImage2D", target, true); 3536 if (GL_TEXTURE_2D == target && texture) { 3537 if (video->copyVideoTextureToPlatformTexture(webContext(), texture->object(), level, type, internalformat, m_unpackPremultiplyAlpha, m_unpackFlipY)) { 3538 texture->setLevelInfo(target, level, internalformat, video->videoWidth(), video->videoHeight(), type); 3539 return; 3540 } 3541 } 3542 3543 // Normal pure SW path. 3544 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode()); 3545 if (!image) 3546 return; 3547 texImage2DImpl(target, level, internalformat, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3548 } 3549 3550 void WebGLRenderingContextBase::texParameter(GLenum target, GLenum pname, GLfloat paramf, GLint parami, bool isFloat) 3551 { 3552 if (isContextLost()) 3553 return; 3554 WebGLTexture* tex = validateTextureBinding("texParameter", target, false); 3555 if (!tex) 3556 return; 3557 switch (pname) { 3558 case GL_TEXTURE_MIN_FILTER: 3559 case GL_TEXTURE_MAG_FILTER: 3560 break; 3561 case GL_TEXTURE_WRAP_S: 3562 case GL_TEXTURE_WRAP_T: 3563 if ((isFloat && paramf != GL_CLAMP_TO_EDGE && paramf != GL_MIRRORED_REPEAT && paramf != GL_REPEAT) 3564 || (!isFloat && parami != GL_CLAMP_TO_EDGE && parami != GL_MIRRORED_REPEAT && parami != GL_REPEAT)) { 3565 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter"); 3566 return; 3567 } 3568 break; 3569 case GL_TEXTURE_MAX_ANISOTROPY_EXT: // EXT_texture_filter_anisotropic 3570 if (!extensionEnabled(EXTTextureFilterAnisotropicName)) { 3571 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter, EXT_texture_filter_anisotropic not enabled"); 3572 return; 3573 } 3574 break; 3575 default: 3576 synthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter name"); 3577 return; 3578 } 3579 if (isFloat) { 3580 tex->setParameterf(pname, paramf); 3581 webContext()->texParameterf(target, pname, paramf); 3582 } else { 3583 tex->setParameteri(pname, parami); 3584 webContext()->texParameteri(target, pname, parami); 3585 } 3586 } 3587 3588 void WebGLRenderingContextBase::texParameterf(GLenum target, GLenum pname, GLfloat param) 3589 { 3590 texParameter(target, pname, param, 0, true); 3591 } 3592 3593 void WebGLRenderingContextBase::texParameteri(GLenum target, GLenum pname, GLint param) 3594 { 3595 texParameter(target, pname, 0, param, false); 3596 } 3597 3598 void WebGLRenderingContextBase::texSubImage2DBase(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels, ExceptionState& exceptionState) 3599 { 3600 // FIXME: Handle errors. 3601 ASSERT(!isContextLost()); 3602 ASSERT(validateTexFuncParameters("texSubImage2D", TexSubImage2D, target, level, format, width, height, 0, format, type)); 3603 ASSERT(validateSize("texSubImage2D", xoffset, yoffset)); 3604 ASSERT(validateSettableTexFormat("texSubImage2D", format)); 3605 WebGLTexture* tex = validateTextureBinding("texSubImage2D", target, true); 3606 if (!tex) { 3607 ASSERT_NOT_REACHED(); 3608 return; 3609 } 3610 ASSERT((xoffset + width) >= 0); 3611 ASSERT((yoffset + height) >= 0); 3612 ASSERT(tex->getWidth(target, level) >= (xoffset + width)); 3613 ASSERT(tex->getHeight(target, level) >= (yoffset + height)); 3614 ASSERT(tex->getInternalFormat(target, level) == format); 3615 ASSERT(tex->getType(target, level) == type); 3616 webContext()->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); 3617 } 3618 3619 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) 3620 { 3621 // All calling functions check isContextLost, so a duplicate check is not needed here. 3622 Vector<uint8_t> data; 3623 WebGLImageConversion::ImageExtractor imageExtractor(image, domSource, premultiplyAlpha, m_unpackColorspaceConversion == GL_NONE); 3624 if (!imageExtractor.extractSucceeded()) { 3625 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image"); 3626 return; 3627 } 3628 WebGLImageConversion::DataFormat sourceDataFormat = imageExtractor.imageSourceFormat(); 3629 WebGLImageConversion::AlphaOp alphaOp = imageExtractor.imageAlphaOp(); 3630 const void* imagePixelData = imageExtractor.imagePixelData(); 3631 3632 bool needConversion = true; 3633 if (type == GL_UNSIGNED_BYTE && sourceDataFormat == WebGLImageConversion::DataFormatRGBA8 && format == GL_RGBA && alphaOp == WebGLImageConversion::AlphaDoNothing && !flipY) 3634 needConversion = false; 3635 else { 3636 if (!WebGLImageConversion::packImageData(image, imagePixelData, format, type, flipY, alphaOp, sourceDataFormat, imageExtractor.imageWidth(), imageExtractor.imageHeight(), imageExtractor.imageSourceUnpackAlignment(), data)) { 3637 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data"); 3638 return; 3639 } 3640 } 3641 3642 if (m_unpackAlignment != 1) 3643 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3644 texSubImage2DBase(target, level, xoffset, yoffset, imageExtractor.imageWidth(), imageExtractor.imageHeight(), format, type, needConversion ? data.data() : imagePixelData, exceptionState); 3645 if (m_unpackAlignment != 1) 3646 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3647 } 3648 3649 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 3650 GLsizei width, GLsizei height, 3651 GLenum format, GLenum type, ArrayBufferView* pixels, ExceptionState& exceptionState) 3652 { 3653 if (isContextLost() || !validateTexFuncData("texSubImage2D", level, width, height, format, type, pixels, NullNotAllowed) 3654 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceArrayBufferView, target, level, format, width, height, 0, format, type, xoffset, yoffset)) 3655 return; 3656 void* data = pixels->baseAddress(); 3657 Vector<uint8_t> tempData; 3658 bool changeUnpackAlignment = false; 3659 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) { 3660 if (!WebGLImageConversion::extractTextureData(width, height, format, type, 3661 m_unpackAlignment, 3662 m_unpackFlipY, m_unpackPremultiplyAlpha, 3663 data, 3664 tempData)) 3665 return; 3666 data = tempData.data(); 3667 changeUnpackAlignment = true; 3668 } 3669 if (changeUnpackAlignment) 3670 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3671 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, exceptionState); 3672 if (changeUnpackAlignment) 3673 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3674 } 3675 3676 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 3677 GLenum format, GLenum type, ImageData* pixels, ExceptionState& exceptionState) 3678 { 3679 if (isContextLost() || !pixels || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceImageData, target, level, format, pixels->width(), pixels->height(), 0, format, type, xoffset, yoffset)) 3680 return; 3681 3682 Vector<uint8_t> data; 3683 bool needConversion = true; 3684 // The data from ImageData is always of format RGBA8. 3685 // No conversion is needed if destination format is RGBA and type is USIGNED_BYTE and no Flip or Premultiply operation is required. 3686 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE && !m_unpackFlipY && !m_unpackPremultiplyAlpha) 3687 needConversion = false; 3688 else { 3689 if (!WebGLImageConversion::extractImageData(pixels->data()->data(), pixels->size(), format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { 3690 synthesizeGLError(GL_INVALID_VALUE, "texSubImage2D", "bad image data"); 3691 return; 3692 } 3693 } 3694 if (m_unpackAlignment != 1) 3695 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, 1); 3696 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), format, type, needConversion ? data.data() : pixels->data()->data(), exceptionState); 3697 if (m_unpackAlignment != 1) 3698 webContext()->pixelStorei(GL_UNPACK_ALIGNMENT, m_unpackAlignment); 3699 } 3700 3701 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 3702 GLenum format, GLenum type, HTMLImageElement* image, ExceptionState& exceptionState) 3703 { 3704 if (isContextLost() || !validateHTMLImageElement("texSubImage2D", image, exceptionState)) 3705 return; 3706 3707 RefPtr<Image> imageForRender = image->cachedImage()->imageForRenderer(image->renderer()); 3708 if (imageForRender->isSVGImage()) 3709 imageForRender = drawImageIntoBuffer(imageForRender.get(), image->width(), image->height(), "texSubImage2D"); 3710 3711 if (!imageForRender || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLImageElement, target, level, format, imageForRender->width(), imageForRender->height(), 0, format, type, xoffset, yoffset)) 3712 return; 3713 3714 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, imageForRender.get(), WebGLImageConversion::HtmlDomImage, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3715 } 3716 3717 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 3718 GLenum format, GLenum type, HTMLCanvasElement* canvas, ExceptionState& exceptionState) 3719 { 3720 if (isContextLost() || !validateHTMLCanvasElement("texSubImage2D", canvas, exceptionState) 3721 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLCanvasElement, target, level, format, canvas->width(), canvas->height(), 0, format, type, xoffset, yoffset)) 3722 return; 3723 3724 RefPtrWillBeRawPtr<ImageData> imageData = canvas->getImageData(); 3725 if (imageData) 3726 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), exceptionState); 3727 else 3728 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), WebGLImageConversion::HtmlDomCanvas, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3729 } 3730 3731 void WebGLRenderingContextBase::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, 3732 GLenum format, GLenum type, HTMLVideoElement* video, ExceptionState& exceptionState) 3733 { 3734 if (isContextLost() || !validateHTMLVideoElement("texSubImage2D", video, exceptionState) 3735 || !validateTexFunc("texSubImage2D", TexSubImage2D, SourceHTMLVideoElement, target, level, format, video->videoWidth(), video->videoHeight(), 0, format, type, xoffset, yoffset)) 3736 return; 3737 3738 RefPtr<Image> image = videoFrameToImage(video, ImageBuffer::fastCopyImageMode()); 3739 if (!image) 3740 return; 3741 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), WebGLImageConversion::HtmlDomVideo, m_unpackFlipY, m_unpackPremultiplyAlpha, exceptionState); 3742 } 3743 3744 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location, GLfloat x) 3745 { 3746 if (isContextLost() || !location) 3747 return; 3748 3749 if (location->program() != m_currentProgram) { 3750 synthesizeGLError(GL_INVALID_OPERATION, "uniform1f", "location not for current program"); 3751 return; 3752 } 3753 3754 webContext()->uniform1f(location->location(), x); 3755 } 3756 3757 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, Float32Array* v) 3758 { 3759 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, 1)) 3760 return; 3761 3762 webContext()->uniform1fv(location->location(), v->length(), v->data()); 3763 } 3764 3765 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size) 3766 { 3767 if (isContextLost() || !validateUniformParameters("uniform1fv", location, v, size, 1)) 3768 return; 3769 3770 webContext()->uniform1fv(location->location(), size, v); 3771 } 3772 3773 void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location, GLint x) 3774 { 3775 if (isContextLost() || !location) 3776 return; 3777 3778 if (location->program() != m_currentProgram) { 3779 synthesizeGLError(GL_INVALID_OPERATION, "uniform1i", "location not for current program"); 3780 return; 3781 } 3782 3783 webContext()->uniform1i(location->location(), x); 3784 } 3785 3786 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, Int32Array* v) 3787 { 3788 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, 1)) 3789 return; 3790 3791 webContext()->uniform1iv(location->location(), v->length(), v->data()); 3792 } 3793 3794 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location, GLint* v, GLsizei size) 3795 { 3796 if (isContextLost() || !validateUniformParameters("uniform1iv", location, v, size, 1)) 3797 return; 3798 3799 webContext()->uniform1iv(location->location(), size, v); 3800 } 3801 3802 void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location, GLfloat x, GLfloat y) 3803 { 3804 if (isContextLost() || !location) 3805 return; 3806 3807 if (location->program() != m_currentProgram) { 3808 synthesizeGLError(GL_INVALID_OPERATION, "uniform2f", "location not for current program"); 3809 return; 3810 } 3811 3812 webContext()->uniform2f(location->location(), x, y); 3813 } 3814 3815 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, Float32Array* v) 3816 { 3817 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, 2)) 3818 return; 3819 3820 webContext()->uniform2fv(location->location(), v->length() / 2, v->data()); 3821 } 3822 3823 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size) 3824 { 3825 if (isContextLost() || !validateUniformParameters("uniform2fv", location, v, size, 2)) 3826 return; 3827 3828 webContext()->uniform2fv(location->location(), size / 2, v); 3829 } 3830 3831 void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location, GLint x, GLint y) 3832 { 3833 if (isContextLost() || !location) 3834 return; 3835 3836 if (location->program() != m_currentProgram) { 3837 synthesizeGLError(GL_INVALID_OPERATION, "uniform2i", "location not for current program"); 3838 return; 3839 } 3840 3841 webContext()->uniform2i(location->location(), x, y); 3842 } 3843 3844 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, Int32Array* v) 3845 { 3846 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, 2)) 3847 return; 3848 3849 webContext()->uniform2iv(location->location(), v->length() / 2, v->data()); 3850 } 3851 3852 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location, GLint* v, GLsizei size) 3853 { 3854 if (isContextLost() || !validateUniformParameters("uniform2iv", location, v, size, 2)) 3855 return; 3856 3857 webContext()->uniform2iv(location->location(), size / 2, v); 3858 } 3859 3860 void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z) 3861 { 3862 if (isContextLost() || !location) 3863 return; 3864 3865 if (location->program() != m_currentProgram) { 3866 synthesizeGLError(GL_INVALID_OPERATION, "uniform3f", "location not for current program"); 3867 return; 3868 } 3869 3870 webContext()->uniform3f(location->location(), x, y, z); 3871 } 3872 3873 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, Float32Array* v) 3874 { 3875 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, 3)) 3876 return; 3877 3878 webContext()->uniform3fv(location->location(), v->length() / 3, v->data()); 3879 } 3880 3881 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size) 3882 { 3883 if (isContextLost() || !validateUniformParameters("uniform3fv", location, v, size, 3)) 3884 return; 3885 3886 webContext()->uniform3fv(location->location(), size / 3, v); 3887 } 3888 3889 void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z) 3890 { 3891 if (isContextLost() || !location) 3892 return; 3893 3894 if (location->program() != m_currentProgram) { 3895 synthesizeGLError(GL_INVALID_OPERATION, "uniform3i", "location not for current program"); 3896 return; 3897 } 3898 3899 webContext()->uniform3i(location->location(), x, y, z); 3900 } 3901 3902 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, Int32Array* v) 3903 { 3904 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, 3)) 3905 return; 3906 3907 webContext()->uniform3iv(location->location(), v->length() / 3, v->data()); 3908 } 3909 3910 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location, GLint* v, GLsizei size) 3911 { 3912 if (isContextLost() || !validateUniformParameters("uniform3iv", location, v, size, 3)) 3913 return; 3914 3915 webContext()->uniform3iv(location->location(), size / 3, v); 3916 } 3917 3918 void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) 3919 { 3920 if (isContextLost() || !location) 3921 return; 3922 3923 if (location->program() != m_currentProgram) { 3924 synthesizeGLError(GL_INVALID_OPERATION, "uniform4f", "location not for current program"); 3925 return; 3926 } 3927 3928 webContext()->uniform4f(location->location(), x, y, z, w); 3929 } 3930 3931 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, Float32Array* v) 3932 { 3933 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, 4)) 3934 return; 3935 3936 webContext()->uniform4fv(location->location(), v->length() / 4, v->data()); 3937 } 3938 3939 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location, GLfloat* v, GLsizei size) 3940 { 3941 if (isContextLost() || !validateUniformParameters("uniform4fv", location, v, size, 4)) 3942 return; 3943 3944 webContext()->uniform4fv(location->location(), size / 4, v); 3945 } 3946 3947 void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location, GLint x, GLint y, GLint z, GLint w) 3948 { 3949 if (isContextLost() || !location) 3950 return; 3951 3952 if (location->program() != m_currentProgram) { 3953 synthesizeGLError(GL_INVALID_OPERATION, "uniform4i", "location not for current program"); 3954 return; 3955 } 3956 3957 webContext()->uniform4i(location->location(), x, y, z, w); 3958 } 3959 3960 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, Int32Array* v) 3961 { 3962 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, 4)) 3963 return; 3964 3965 webContext()->uniform4iv(location->location(), v->length() / 4, v->data()); 3966 } 3967 3968 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location, GLint* v, GLsizei size) 3969 { 3970 if (isContextLost() || !validateUniformParameters("uniform4iv", location, v, size, 4)) 3971 return; 3972 3973 webContext()->uniform4iv(location->location(), size / 4, v); 3974 } 3975 3976 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v) 3977 { 3978 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, 4)) 3979 return; 3980 webContext()->uniformMatrix2fv(location->location(), v->length() / 4, transpose, v->data()); 3981 } 3982 3983 void WebGLRenderingContextBase::uniformMatrix2fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size) 3984 { 3985 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix2fv", location, transpose, v, size, 4)) 3986 return; 3987 webContext()->uniformMatrix2fv(location->location(), size / 4, transpose, v); 3988 } 3989 3990 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v) 3991 { 3992 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, 9)) 3993 return; 3994 webContext()->uniformMatrix3fv(location->location(), v->length() / 9, transpose, v->data()); 3995 } 3996 3997 void WebGLRenderingContextBase::uniformMatrix3fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size) 3998 { 3999 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix3fv", location, transpose, v, size, 9)) 4000 return; 4001 webContext()->uniformMatrix3fv(location->location(), size / 9, transpose, v); 4002 } 4003 4004 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v) 4005 { 4006 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, 16)) 4007 return; 4008 webContext()->uniformMatrix4fv(location->location(), v->length() / 16, transpose, v->data()); 4009 } 4010 4011 void WebGLRenderingContextBase::uniformMatrix4fv(const WebGLUniformLocation* location, GLboolean transpose, GLfloat* v, GLsizei size) 4012 { 4013 if (isContextLost() || !validateUniformMatrixParameters("uniformMatrix4fv", location, transpose, v, size, 16)) 4014 return; 4015 webContext()->uniformMatrix4fv(location->location(), size / 16, transpose, v); 4016 } 4017 4018 void WebGLRenderingContextBase::useProgram(WebGLProgram* program) 4019 { 4020 bool deleted; 4021 if (!checkObjectToBeBound("useProgram", program, deleted)) 4022 return; 4023 if (deleted) 4024 program = 0; 4025 if (program && !program->linkStatus()) { 4026 synthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid"); 4027 return; 4028 } 4029 if (m_currentProgram != program) { 4030 if (m_currentProgram) 4031 m_currentProgram->onDetached(webContext()); 4032 m_currentProgram = program; 4033 webContext()->useProgram(objectOrZero(program)); 4034 if (program) 4035 program->onAttached(); 4036 } 4037 } 4038 4039 void WebGLRenderingContextBase::validateProgram(WebGLProgram* program) 4040 { 4041 if (isContextLost() || !validateWebGLObject("validateProgram", program)) 4042 return; 4043 webContext()->validateProgram(objectOrZero(program)); 4044 } 4045 4046 void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0) 4047 { 4048 vertexAttribfImpl("vertexAttrib1f", index, 1, v0, 0.0f, 0.0f, 1.0f); 4049 } 4050 4051 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, Float32Array* v) 4052 { 4053 vertexAttribfvImpl("vertexAttrib1fv", index, v, 1); 4054 } 4055 4056 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index, GLfloat* v, GLsizei size) 4057 { 4058 vertexAttribfvImpl("vertexAttrib1fv", index, v, size, 1); 4059 } 4060 4061 void WebGLRenderingContextBase::vertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) 4062 { 4063 vertexAttribfImpl("vertexAttrib2f", index, 2, v0, v1, 0.0f, 1.0f); 4064 } 4065 4066 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, Float32Array* v) 4067 { 4068 vertexAttribfvImpl("vertexAttrib2fv", index, v, 2); 4069 } 4070 4071 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index, GLfloat* v, GLsizei size) 4072 { 4073 vertexAttribfvImpl("vertexAttrib2fv", index, v, size, 2); 4074 } 4075 4076 void WebGLRenderingContextBase::vertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) 4077 { 4078 vertexAttribfImpl("vertexAttrib3f", index, 3, v0, v1, v2, 1.0f); 4079 } 4080 4081 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, Float32Array* v) 4082 { 4083 vertexAttribfvImpl("vertexAttrib3fv", index, v, 3); 4084 } 4085 4086 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index, GLfloat* v, GLsizei size) 4087 { 4088 vertexAttribfvImpl("vertexAttrib3fv", index, v, size, 3); 4089 } 4090 4091 void WebGLRenderingContextBase::vertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) 4092 { 4093 vertexAttribfImpl("vertexAttrib4f", index, 4, v0, v1, v2, v3); 4094 } 4095 4096 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, Float32Array* v) 4097 { 4098 vertexAttribfvImpl("vertexAttrib4fv", index, v, 4); 4099 } 4100 4101 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index, GLfloat* v, GLsizei size) 4102 { 4103 vertexAttribfvImpl("vertexAttrib4fv", index, v, size, 4); 4104 } 4105 4106 void WebGLRenderingContextBase::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, long long offset) 4107 { 4108 if (isContextLost()) 4109 return; 4110 switch (type) { 4111 case GL_BYTE: 4112 case GL_UNSIGNED_BYTE: 4113 case GL_SHORT: 4114 case GL_UNSIGNED_SHORT: 4115 case GL_FLOAT: 4116 break; 4117 default: 4118 synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type"); 4119 return; 4120 } 4121 if (index >= m_maxVertexAttribs) { 4122 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "index out of range"); 4123 return; 4124 } 4125 if (size < 1 || size > 4 || stride < 0 || stride > 255) { 4126 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer", "bad size or stride"); 4127 return; 4128 } 4129 if (!validateValueFitNonNegInt32("vertexAttribPointer", "offset", offset)) 4130 return; 4131 if (!m_boundArrayBuffer) { 4132 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "no bound ARRAY_BUFFER"); 4133 return; 4134 } 4135 // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride 4136 unsigned typeSize = sizeInBytes(type); 4137 if (!typeSize) { 4138 synthesizeGLError(GL_INVALID_ENUM, "vertexAttribPointer", "invalid type"); 4139 return; 4140 } 4141 if ((stride % typeSize) || (static_cast<GLintptr>(offset) % typeSize)) { 4142 synthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer", "stride or offset not valid for type"); 4143 return; 4144 } 4145 GLsizei bytesPerElement = size * typeSize; 4146 4147 m_boundVertexArrayObject->setVertexAttribState(index, bytesPerElement, size, type, normalized, stride, static_cast<GLintptr>(offset), m_boundArrayBuffer); 4148 webContext()->vertexAttribPointer(index, size, type, normalized, stride, static_cast<GLintptr>(offset)); 4149 } 4150 4151 void WebGLRenderingContextBase::vertexAttribDivisorANGLE(GLuint index, GLuint divisor) 4152 { 4153 if (isContextLost()) 4154 return; 4155 4156 if (index >= m_maxVertexAttribs) { 4157 synthesizeGLError(GL_INVALID_VALUE, "vertexAttribDivisorANGLE", "index out of range"); 4158 return; 4159 } 4160 4161 m_boundVertexArrayObject->setVertexAttribDivisor(index, divisor); 4162 webContext()->vertexAttribDivisorANGLE(index, divisor); 4163 } 4164 4165 void WebGLRenderingContextBase::viewport(GLint x, GLint y, GLsizei width, GLsizei height) 4166 { 4167 if (isContextLost()) 4168 return; 4169 if (!validateSize("viewport", width, height)) 4170 return; 4171 webContext()->viewport(x, y, width, height); 4172 } 4173 4174 void WebGLRenderingContextBase::forceLostContext(WebGLRenderingContextBase::LostContextMode mode) 4175 { 4176 if (isContextLost()) { 4177 synthesizeGLError(GL_INVALID_OPERATION, "loseContext", "context already lost"); 4178 return; 4179 } 4180 4181 m_contextGroup->loseContextGroup(mode); 4182 } 4183 4184 void WebGLRenderingContextBase::loseContextImpl(WebGLRenderingContextBase::LostContextMode mode) 4185 { 4186 #ifndef NDEBUG 4187 printWarningToConsole("loseContextImpl(): begin"); 4188 #endif 4189 4190 if (isContextLost()) 4191 return; 4192 4193 m_contextLost = true; 4194 m_contextLostMode = mode; 4195 4196 if (mode == RealLostContext) { 4197 // Inform the embedder that a lost context was received. In response, the embedder might 4198 // decide to take action such as asking the user for permission to use WebGL again. 4199 if (LocalFrame* frame = canvas()->document().frame()) 4200 frame->loader().client()->didLoseWebGLContext(webContext()->getGraphicsResetStatusARB()); 4201 } 4202 4203 // Make absolutely sure we do not refer to an already-deleted texture or framebuffer. 4204 m_drawingBuffer->setTexture2DBinding(0); 4205 m_drawingBuffer->setFramebufferBinding(0); 4206 4207 detachAndRemoveAllObjects(); 4208 4209 #ifndef NDEBUG 4210 printWarningToConsole("loseContextImpl(): after detachAndRemoveAllObjects()"); 4211 #endif 4212 4213 // Lose all the extensions. 4214 for (size_t i = 0; i < m_extensions.size(); ++i) { 4215 ExtensionTracker* tracker = m_extensions[i]; 4216 tracker->loseExtension(); 4217 } 4218 4219 for (size_t i = 0; i < WebGLExtensionNameCount; ++i) 4220 m_extensionEnabled[i] = false; 4221 4222 removeAllCompressedTextureFormats(); 4223 4224 if (mode != RealLostContext) 4225 destroyContext(); 4226 4227 #ifndef NDEBUG 4228 printWarningToConsole("loseContextImpl(): after destroyContext()"); 4229 #endif 4230 4231 ConsoleDisplayPreference display = (mode == RealLostContext) ? DisplayInConsole: DontDisplayInConsole; 4232 synthesizeGLError(GC3D_CONTEXT_LOST_WEBGL, "loseContext", "context lost", display); 4233 4234 // Don't allow restoration unless the context lost event has both been 4235 // dispatched and its default behavior prevented. 4236 m_restoreAllowed = false; 4237 4238 // Always defer the dispatch of the context lost event, to implement 4239 // the spec behavior of queueing a task. 4240 m_dispatchContextLostEventTimer.startOneShot(0, FROM_HERE); 4241 4242 #ifndef NDEBUG 4243 printWarningToConsole("loseContextImpl(): end"); 4244 #endif 4245 } 4246 4247 void WebGLRenderingContextBase::forceRestoreContext() 4248 { 4249 if (!isContextLost()) { 4250 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context not lost"); 4251 return; 4252 } 4253 4254 if (!m_restoreAllowed) { 4255 if (m_contextLostMode == SyntheticLostContext) 4256 synthesizeGLError(GL_INVALID_OPERATION, "restoreContext", "context restoration not allowed"); 4257 return; 4258 } 4259 4260 if (!m_restoreTimer.isActive()) 4261 m_restoreTimer.startOneShot(0, FROM_HERE); 4262 } 4263 4264 blink::WebLayer* WebGLRenderingContextBase::platformLayer() const 4265 { 4266 return isContextLost() ? 0 : m_drawingBuffer->platformLayer(); 4267 } 4268 4269 Extensions3DUtil* WebGLRenderingContextBase::extensionsUtil() 4270 { 4271 ASSERT(!isContextLost()); 4272 if (!m_extensionsUtil) 4273 m_extensionsUtil = Extensions3DUtil::create(webContext()); 4274 return m_extensionsUtil.get(); 4275 } 4276 4277 void WebGLRenderingContextBase::removeSharedObject(WebGLSharedObject* object) 4278 { 4279 m_contextGroup->removeObject(object); 4280 } 4281 4282 void WebGLRenderingContextBase::addSharedObject(WebGLSharedObject* object) 4283 { 4284 ASSERT(!isContextLost()); 4285 m_contextGroup->addObject(object); 4286 } 4287 4288 void WebGLRenderingContextBase::removeContextObject(WebGLContextObject* object) 4289 { 4290 m_contextObjects.remove(object); 4291 } 4292 4293 void WebGLRenderingContextBase::addContextObject(WebGLContextObject* object) 4294 { 4295 ASSERT(!isContextLost()); 4296 m_contextObjects.add(object); 4297 } 4298 4299 void WebGLRenderingContextBase::detachAndRemoveAllObjects() 4300 { 4301 while (m_contextObjects.size() > 0) { 4302 HashSet<WebGLContextObject*>::iterator it = m_contextObjects.begin(); 4303 (*it)->detachContext(); 4304 } 4305 } 4306 4307 bool WebGLRenderingContextBase::hasPendingActivity() const 4308 { 4309 return false; 4310 } 4311 4312 void WebGLRenderingContextBase::stop() 4313 { 4314 if (!isContextLost()) { 4315 forceLostContext(SyntheticLostContext); 4316 destroyContext(); 4317 } 4318 } 4319 4320 WebGLGetInfo WebGLRenderingContextBase::getBooleanParameter(GLenum pname) 4321 { 4322 GLboolean value = 0; 4323 if (!isContextLost()) 4324 webContext()->getBooleanv(pname, &value); 4325 return WebGLGetInfo(static_cast<bool>(value)); 4326 } 4327 4328 WebGLGetInfo WebGLRenderingContextBase::getBooleanArrayParameter(GLenum pname) 4329 { 4330 if (pname != GL_COLOR_WRITEMASK) { 4331 notImplemented(); 4332 return WebGLGetInfo(0, 0); 4333 } 4334 GLboolean value[4] = {0}; 4335 if (!isContextLost()) 4336 webContext()->getBooleanv(pname, value); 4337 bool boolValue[4]; 4338 for (int ii = 0; ii < 4; ++ii) 4339 boolValue[ii] = static_cast<bool>(value[ii]); 4340 return WebGLGetInfo(boolValue, 4); 4341 } 4342 4343 WebGLGetInfo WebGLRenderingContextBase::getFloatParameter(GLenum pname) 4344 { 4345 GLfloat value = 0; 4346 if (!isContextLost()) 4347 webContext()->getFloatv(pname, &value); 4348 return WebGLGetInfo(value); 4349 } 4350 4351 WebGLGetInfo WebGLRenderingContextBase::getIntParameter(GLenum pname) 4352 { 4353 GLint value = 0; 4354 if (!isContextLost()) 4355 webContext()->getIntegerv(pname, &value); 4356 return WebGLGetInfo(value); 4357 } 4358 4359 WebGLGetInfo WebGLRenderingContextBase::getUnsignedIntParameter(GLenum pname) 4360 { 4361 GLint value = 0; 4362 if (!isContextLost()) 4363 webContext()->getIntegerv(pname, &value); 4364 return WebGLGetInfo(static_cast<unsigned>(value)); 4365 } 4366 4367 WebGLGetInfo WebGLRenderingContextBase::getWebGLFloatArrayParameter(GLenum pname) 4368 { 4369 GLfloat value[4] = {0}; 4370 if (!isContextLost()) 4371 webContext()->getFloatv(pname, value); 4372 unsigned length = 0; 4373 switch (pname) { 4374 case GL_ALIASED_POINT_SIZE_RANGE: 4375 case GL_ALIASED_LINE_WIDTH_RANGE: 4376 case GL_DEPTH_RANGE: 4377 length = 2; 4378 break; 4379 case GL_BLEND_COLOR: 4380 case GL_COLOR_CLEAR_VALUE: 4381 length = 4; 4382 break; 4383 default: 4384 notImplemented(); 4385 } 4386 return WebGLGetInfo(Float32Array::create(value, length)); 4387 } 4388 4389 WebGLGetInfo WebGLRenderingContextBase::getWebGLIntArrayParameter(GLenum pname) 4390 { 4391 GLint value[4] = {0}; 4392 if (!isContextLost()) 4393 webContext()->getIntegerv(pname, value); 4394 unsigned length = 0; 4395 switch (pname) { 4396 case GL_MAX_VIEWPORT_DIMS: 4397 length = 2; 4398 break; 4399 case GL_SCISSOR_BOX: 4400 case GL_VIEWPORT: 4401 length = 4; 4402 break; 4403 default: 4404 notImplemented(); 4405 } 4406 return WebGLGetInfo(Int32Array::create(value, length)); 4407 } 4408 4409 void WebGLRenderingContextBase::handleTextureCompleteness(const char* functionName, bool prepareToDraw) 4410 { 4411 // All calling functions check isContextLost, so a duplicate check is not needed here. 4412 bool resetActiveUnit = false; 4413 WebGLTexture::TextureExtensionFlag flag = static_cast<WebGLTexture::TextureExtensionFlag>((extensionEnabled(OESTextureFloatLinearName) ? WebGLTexture::TextureFloatLinearExtensionEnabled : 0) 4414 | (extensionEnabled(OESTextureHalfFloatLinearName) ? WebGLTexture::TextureHalfFloatLinearExtensionEnabled : 0)); 4415 for (unsigned ii = 0; ii < m_onePlusMaxNonDefaultTextureUnit; ++ii) { 4416 if ((m_textureUnits[ii].m_texture2DBinding.get() && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag)) 4417 || (m_textureUnits[ii].m_textureCubeMapBinding.get() && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag))) { 4418 if (ii != m_activeTextureUnit) { 4419 webContext()->activeTexture(ii); 4420 resetActiveUnit = true; 4421 } else if (resetActiveUnit) { 4422 webContext()->activeTexture(ii); 4423 resetActiveUnit = false; 4424 } 4425 WebGLTexture* tex2D; 4426 WebGLTexture* texCubeMap; 4427 if (prepareToDraw) { 4428 String msg(String("texture bound to texture unit ") + String::number(ii) 4429 + " is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'." 4430 + " 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."); 4431 emitGLWarning(functionName, msg.utf8().data()); 4432 tex2D = m_blackTexture2D.get(); 4433 texCubeMap = m_blackTextureCubeMap.get(); 4434 } else { 4435 tex2D = m_textureUnits[ii].m_texture2DBinding.get(); 4436 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get(); 4437 } 4438 if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture(flag)) 4439 webContext()->bindTexture(GL_TEXTURE_2D, objectOrZero(tex2D)); 4440 if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture(flag)) 4441 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, objectOrZero(texCubeMap)); 4442 } 4443 } 4444 if (resetActiveUnit) 4445 webContext()->activeTexture(m_activeTextureUnit); 4446 } 4447 4448 void WebGLRenderingContextBase::createFallbackBlackTextures1x1() 4449 { 4450 // All calling functions check isContextLost, so a duplicate check is not needed here. 4451 unsigned char black[] = {0, 0, 0, 255}; 4452 m_blackTexture2D = createTexture(); 4453 webContext()->bindTexture(GL_TEXTURE_2D, m_blackTexture2D->object()); 4454 webContext()->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 4455 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4456 webContext()->bindTexture(GL_TEXTURE_2D, 0); 4457 m_blackTextureCubeMap = createTexture(); 4458 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object()); 4459 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA, 1, 1, 4460 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4461 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA, 1, 1, 4462 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4463 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA, 1, 1, 4464 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4465 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, 1, 1, 4466 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4467 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA, 1, 1, 4468 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4469 webContext()->texImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA, 1, 1, 4470 0, GL_RGBA, GL_UNSIGNED_BYTE, black); 4471 webContext()->bindTexture(GL_TEXTURE_CUBE_MAP, 0); 4472 } 4473 4474 bool WebGLRenderingContextBase::isTexInternalFormatColorBufferCombinationValid(GLenum texInternalFormat, GLenum colorBufferFormat) 4475 { 4476 unsigned need = WebGLImageConversion::getChannelBitsByFormat(texInternalFormat); 4477 unsigned have = WebGLImageConversion::getChannelBitsByFormat(colorBufferFormat); 4478 return (need & have) == need; 4479 } 4480 4481 GLenum WebGLRenderingContextBase::boundFramebufferColorFormat() 4482 { 4483 if (m_framebufferBinding && m_framebufferBinding->object()) 4484 return m_framebufferBinding->colorBufferFormat(); 4485 if (m_requestedAttributes->alpha()) 4486 return GL_RGBA; 4487 return GL_RGB; 4488 } 4489 4490 WebGLTexture* WebGLRenderingContextBase::validateTextureBinding(const char* functionName, GLenum target, bool useSixEnumsForCubeMap) 4491 { 4492 WebGLTexture* tex = 0; 4493 switch (target) { 4494 case GL_TEXTURE_2D: 4495 tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get(); 4496 break; 4497 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 4498 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 4499 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 4500 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 4501 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4502 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 4503 if (!useSixEnumsForCubeMap) { 4504 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target"); 4505 return 0; 4506 } 4507 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get(); 4508 break; 4509 case GL_TEXTURE_CUBE_MAP: 4510 if (useSixEnumsForCubeMap) { 4511 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target"); 4512 return 0; 4513 } 4514 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get(); 4515 break; 4516 default: 4517 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture target"); 4518 return 0; 4519 } 4520 if (!tex) 4521 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no texture"); 4522 return tex; 4523 } 4524 4525 bool WebGLRenderingContextBase::validateLocationLength(const char* functionName, const String& string) 4526 { 4527 const unsigned maxWebGLLocationLength = 256; 4528 if (string.length() > maxWebGLLocationLength) { 4529 synthesizeGLError(GL_INVALID_VALUE, functionName, "location length > 256"); 4530 return false; 4531 } 4532 return true; 4533 } 4534 4535 bool WebGLRenderingContextBase::validateSize(const char* functionName, GLint x, GLint y) 4536 { 4537 if (x < 0 || y < 0) { 4538 synthesizeGLError(GL_INVALID_VALUE, functionName, "size < 0"); 4539 return false; 4540 } 4541 return true; 4542 } 4543 4544 bool WebGLRenderingContextBase::validateString(const char* functionName, const String& string) 4545 { 4546 for (size_t i = 0; i < string.length(); ++i) { 4547 if (!validateCharacter(string[i])) { 4548 synthesizeGLError(GL_INVALID_VALUE, functionName, "string not ASCII"); 4549 return false; 4550 } 4551 } 4552 return true; 4553 } 4554 4555 bool WebGLRenderingContextBase::validateTexFuncFormatAndType(const char* functionName, GLenum format, GLenum type, GLint level) 4556 { 4557 switch (format) { 4558 case GL_ALPHA: 4559 case GL_LUMINANCE: 4560 case GL_LUMINANCE_ALPHA: 4561 case GL_RGB: 4562 case GL_RGBA: 4563 break; 4564 case GL_DEPTH_STENCIL_OES: 4565 case GL_DEPTH_COMPONENT: 4566 if (extensionEnabled(WebGLDepthTextureName)) 4567 break; 4568 synthesizeGLError(GL_INVALID_ENUM, functionName, "depth texture formats not enabled"); 4569 return false; 4570 default: 4571 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture format"); 4572 return false; 4573 } 4574 4575 switch (type) { 4576 case GL_UNSIGNED_BYTE: 4577 case GL_UNSIGNED_SHORT_5_6_5: 4578 case GL_UNSIGNED_SHORT_4_4_4_4: 4579 case GL_UNSIGNED_SHORT_5_5_5_1: 4580 break; 4581 case GL_FLOAT: 4582 if (extensionEnabled(OESTextureFloatName)) 4583 break; 4584 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type"); 4585 return false; 4586 case GL_HALF_FLOAT_OES: 4587 if (extensionEnabled(OESTextureHalfFloatName)) 4588 break; 4589 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type"); 4590 return false; 4591 case GL_UNSIGNED_INT: 4592 case GL_UNSIGNED_INT_24_8_OES: 4593 case GL_UNSIGNED_SHORT: 4594 if (extensionEnabled(WebGLDepthTextureName)) 4595 break; 4596 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type"); 4597 return false; 4598 default: 4599 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid texture type"); 4600 return false; 4601 } 4602 4603 // Verify that the combination of format and type is supported. 4604 switch (format) { 4605 case GL_ALPHA: 4606 case GL_LUMINANCE: 4607 case GL_LUMINANCE_ALPHA: 4608 if (type != GL_UNSIGNED_BYTE 4609 && type != GL_FLOAT 4610 && type != GL_HALF_FLOAT_OES) { 4611 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for format"); 4612 return false; 4613 } 4614 break; 4615 case GL_RGB: 4616 if (type != GL_UNSIGNED_BYTE 4617 && type != GL_UNSIGNED_SHORT_5_6_5 4618 && type != GL_FLOAT 4619 && type != GL_HALF_FLOAT_OES) { 4620 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGB format"); 4621 return false; 4622 } 4623 break; 4624 case GL_RGBA: 4625 if (type != GL_UNSIGNED_BYTE 4626 && type != GL_UNSIGNED_SHORT_4_4_4_4 4627 && type != GL_UNSIGNED_SHORT_5_5_5_1 4628 && type != GL_FLOAT 4629 && type != GL_HALF_FLOAT_OES) { 4630 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for RGBA format"); 4631 return false; 4632 } 4633 break; 4634 case GL_DEPTH_COMPONENT: 4635 if (!extensionEnabled(WebGLDepthTextureName)) { 4636 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_COMPONENT not enabled"); 4637 return false; 4638 } 4639 if (type != GL_UNSIGNED_SHORT 4640 && type != GL_UNSIGNED_INT) { 4641 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_COMPONENT format"); 4642 return false; 4643 } 4644 if (level > 0) { 4645 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_COMPONENT format"); 4646 return false; 4647 } 4648 break; 4649 case GL_DEPTH_STENCIL_OES: 4650 if (!extensionEnabled(WebGLDepthTextureName)) { 4651 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format. DEPTH_STENCIL not enabled"); 4652 return false; 4653 } 4654 if (type != GL_UNSIGNED_INT_24_8_OES) { 4655 synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid type for DEPTH_STENCIL format"); 4656 return false; 4657 } 4658 if (level > 0) { 4659 synthesizeGLError(GL_INVALID_OPERATION, functionName, "level must be 0 for DEPTH_STENCIL format"); 4660 return false; 4661 } 4662 break; 4663 default: 4664 ASSERT_NOT_REACHED(); 4665 } 4666 4667 return true; 4668 } 4669 4670 bool WebGLRenderingContextBase::validateTexFuncLevel(const char* functionName, GLenum target, GLint level) 4671 { 4672 if (level < 0) { 4673 synthesizeGLError(GL_INVALID_VALUE, functionName, "level < 0"); 4674 return false; 4675 } 4676 switch (target) { 4677 case GL_TEXTURE_2D: 4678 if (level >= m_maxTextureLevel) { 4679 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range"); 4680 return false; 4681 } 4682 break; 4683 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 4684 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 4685 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 4686 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 4687 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4688 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 4689 if (level >= m_maxCubeMapTextureLevel) { 4690 synthesizeGLError(GL_INVALID_VALUE, functionName, "level out of range"); 4691 return false; 4692 } 4693 break; 4694 } 4695 // This function only checks if level is legal, so we return true and don't 4696 // generate INVALID_ENUM if target is illegal. 4697 return true; 4698 } 4699 4700 bool WebGLRenderingContextBase::validateTexFuncDimensions(const char* functionName, TexFuncValidationFunctionType functionType, 4701 GLenum target, GLint level, GLsizei width, GLsizei height) 4702 { 4703 if (width < 0 || height < 0) { 4704 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0"); 4705 return false; 4706 } 4707 4708 switch (target) { 4709 case GL_TEXTURE_2D: 4710 if (width > (m_maxTextureSize >> level) || height > (m_maxTextureSize >> level)) { 4711 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range"); 4712 return false; 4713 } 4714 break; 4715 case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 4716 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 4717 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 4718 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 4719 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4720 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 4721 if (functionType != TexSubImage2D && width != height) { 4722 synthesizeGLError(GL_INVALID_VALUE, functionName, "width != height for cube map"); 4723 return false; 4724 } 4725 // No need to check height here. For texImage width == height. 4726 // For texSubImage that will be checked when checking yoffset + height is in range. 4727 if (width > (m_maxCubeMapTextureSize >> level)) { 4728 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height out of range for cube map"); 4729 return false; 4730 } 4731 break; 4732 default: 4733 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target"); 4734 return false; 4735 } 4736 return true; 4737 } 4738 4739 bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target, 4740 GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type) 4741 { 4742 // We absolutely have to validate the format and type combination. 4743 // The texImage2D entry points taking HTMLImage, etc. will produce 4744 // temporary data based on this combination, so it must be legal. 4745 if (!validateTexFuncFormatAndType(functionName, format, type, level) || !validateTexFuncLevel(functionName, target, level)) 4746 return false; 4747 4748 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height)) 4749 return false; 4750 4751 if (format != internalformat) { 4752 synthesizeGLError(GL_INVALID_OPERATION, functionName, "format != internalformat"); 4753 return false; 4754 } 4755 4756 if (border) { 4757 synthesizeGLError(GL_INVALID_VALUE, functionName, "border != 0"); 4758 return false; 4759 } 4760 4761 return true; 4762 } 4763 4764 bool WebGLRenderingContextBase::validateTexFuncData(const char* functionName, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, ArrayBufferView* pixels, NullDisposition disposition) 4765 { 4766 // All calling functions check isContextLost, so a duplicate check is not needed here. 4767 if (!pixels) { 4768 if (disposition == NullAllowed) 4769 return true; 4770 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels"); 4771 return false; 4772 } 4773 4774 if (!validateTexFuncFormatAndType(functionName, format, type, level)) 4775 return false; 4776 if (!validateSettableTexFormat(functionName, format)) 4777 return false; 4778 4779 switch (type) { 4780 case GL_UNSIGNED_BYTE: 4781 if (pixels->type() != ArrayBufferView::TypeUint8) { 4782 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array"); 4783 return false; 4784 } 4785 break; 4786 case GL_UNSIGNED_SHORT_5_6_5: 4787 case GL_UNSIGNED_SHORT_4_4_4_4: 4788 case GL_UNSIGNED_SHORT_5_5_5_1: 4789 if (pixels->type() != ArrayBufferView::TypeUint16) { 4790 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array"); 4791 return false; 4792 } 4793 break; 4794 case GL_FLOAT: // OES_texture_float 4795 if (pixels->type() != ArrayBufferView::TypeFloat32) { 4796 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type FLOAT but ArrayBufferView not Float32Array"); 4797 return false; 4798 } 4799 break; 4800 case GL_HALF_FLOAT_OES: // OES_texture_half_float 4801 // As per the specification, ArrayBufferView should be null or a Uint16Array when 4802 // OES_texture_half_float is enabled. 4803 if (pixels && pixels->type() != ArrayBufferView::TypeUint16) { 4804 synthesizeGLError(GL_INVALID_OPERATION, functionName, "type HALF_FLOAT_OES but ArrayBufferView is not NULL and not Uint16Array"); 4805 return false; 4806 } 4807 break; 4808 default: 4809 ASSERT_NOT_REACHED(); 4810 } 4811 4812 unsigned totalBytesRequired; 4813 GLenum error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0); 4814 if (error != GL_NO_ERROR) { 4815 synthesizeGLError(error, functionName, "invalid texture dimensions"); 4816 return false; 4817 } 4818 if (pixels->byteLength() < totalBytesRequired) { 4819 if (m_unpackAlignment != 1) { 4820 error = WebGLImageConversion::computeImageSizeInBytes(format, type, width, height, 1, &totalBytesRequired, 0); 4821 if (pixels->byteLength() == totalBytesRequired) { 4822 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request with UNPACK_ALIGNMENT > 1"); 4823 return false; 4824 } 4825 } 4826 synthesizeGLError(GL_INVALID_OPERATION, functionName, "ArrayBufferView not big enough for request"); 4827 return false; 4828 } 4829 return true; 4830 } 4831 4832 bool WebGLRenderingContextBase::validateCompressedTexFormat(GLenum format) 4833 { 4834 return m_compressedTextureFormats.contains(format); 4835 } 4836 4837 bool WebGLRenderingContextBase::validateCompressedTexFuncData(const char* functionName, GLsizei width, GLsizei height, GLenum format, ArrayBufferView* pixels) 4838 { 4839 if (!pixels) { 4840 synthesizeGLError(GL_INVALID_VALUE, functionName, "no pixels"); 4841 return false; 4842 } 4843 if (width < 0 || height < 0) { 4844 synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0"); 4845 return false; 4846 } 4847 4848 unsigned bytesRequired = 0; 4849 4850 switch (format) { 4851 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 4852 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 4853 { 4854 const int kBlockWidth = 4; 4855 const int kBlockHeight = 4; 4856 const int kBlockSize = 8; 4857 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth; 4858 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight; 4859 int numBlocks = numBlocksAcross * numBlocksDown; 4860 bytesRequired = numBlocks * kBlockSize; 4861 } 4862 break; 4863 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 4864 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: 4865 { 4866 const int kBlockWidth = 4; 4867 const int kBlockHeight = 4; 4868 const int kBlockSize = 16; 4869 int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth; 4870 int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight; 4871 int numBlocks = numBlocksAcross * numBlocksDown; 4872 bytesRequired = numBlocks * kBlockSize; 4873 } 4874 break; 4875 case GC3D_COMPRESSED_ATC_RGB_AMD: 4876 case GL_ETC1_RGB8_OES: 4877 { 4878 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 8; 4879 } 4880 break; 4881 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD: 4882 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD: 4883 { 4884 bytesRequired = floor(static_cast<double>((width + 3) / 4)) * floor(static_cast<double>((height + 3) / 4)) * 16; 4885 } 4886 break; 4887 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 4888 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 4889 { 4890 bytesRequired = (max(width, 8) * max(height, 8) * 4 + 7) / 8; 4891 } 4892 break; 4893 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 4894 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: 4895 { 4896 bytesRequired = (max(width, 16) * max(height, 8) * 2 + 7) / 8; 4897 } 4898 break; 4899 default: 4900 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid format"); 4901 return false; 4902 } 4903 4904 if (pixels->byteLength() != bytesRequired) { 4905 synthesizeGLError(GL_INVALID_VALUE, functionName, "length of ArrayBufferView is not correct for dimensions"); 4906 return false; 4907 } 4908 4909 return true; 4910 } 4911 4912 bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, TexFuncValidationFunctionType functionType, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format) 4913 { 4914 if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height)) 4915 return false; 4916 4917 bool widthValid = false; 4918 bool heightValid = false; 4919 4920 switch (format) { 4921 case GC3D_COMPRESSED_ATC_RGB_AMD: 4922 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD: 4923 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD: 4924 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 4925 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 4926 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 4927 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: { 4928 const int kBlockWidth = 4; 4929 const int kBlockHeight = 4; 4930 widthValid = (level && width == 1) || (level && width == 2) || !(width % kBlockWidth); 4931 heightValid = (level && height == 1) || (level && height == 2) || !(height % kBlockHeight); 4932 break; 4933 } 4934 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 4935 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 4936 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 4937 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { 4938 // Must be a power of two 4939 widthValid = (width & (width - 1)) == 0; 4940 heightValid = (height & (height - 1)) == 0; 4941 break; 4942 } 4943 case GL_ETC1_RGB8_OES: { 4944 widthValid = true; 4945 heightValid = true; 4946 break; 4947 } 4948 default: 4949 return false; 4950 } 4951 4952 if (!widthValid || !heightValid) { 4953 synthesizeGLError(GL_INVALID_OPERATION, functionName, "width or height invalid for level"); 4954 return false; 4955 } 4956 4957 return true; 4958 } 4959 4960 bool WebGLRenderingContextBase::validateCompressedTexSubDimensions(const char* functionName, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, WebGLTexture* tex) 4961 { 4962 if (xoffset < 0 || yoffset < 0) { 4963 synthesizeGLError(GL_INVALID_VALUE, functionName, "xoffset or yoffset < 0"); 4964 return false; 4965 } 4966 4967 switch (format) { 4968 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 4969 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 4970 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 4971 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: { 4972 const int kBlockWidth = 4; 4973 const int kBlockHeight = 4; 4974 if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) { 4975 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset or yoffset not multiple of 4"); 4976 return false; 4977 } 4978 if (width - xoffset > tex->getWidth(target, level) 4979 || height - yoffset > tex->getHeight(target, level)) { 4980 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions out of range"); 4981 return false; 4982 } 4983 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format); 4984 } 4985 case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 4986 case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 4987 case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 4988 case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { 4989 if ((xoffset != 0) || (yoffset != 0)) { 4990 synthesizeGLError(GL_INVALID_OPERATION, functionName, "xoffset and yoffset must be zero"); 4991 return false; 4992 } 4993 if (width != tex->getWidth(target, level) 4994 || height != tex->getHeight(target, level)) { 4995 synthesizeGLError(GL_INVALID_OPERATION, functionName, "dimensions must match existing level"); 4996 return false; 4997 } 4998 return validateCompressedTexDimensions(functionName, TexSubImage2D, target, level, width, height, format); 4999 } 5000 case GC3D_COMPRESSED_ATC_RGB_AMD: 5001 case GC3D_COMPRESSED_ATC_RGBA_EXPLICIT_ALPHA_AMD: 5002 case GC3D_COMPRESSED_ATC_RGBA_INTERPOLATED_ALPHA_AMD: 5003 case GL_ETC1_RGB8_OES: { 5004 synthesizeGLError(GL_INVALID_OPERATION, functionName, "unable to update sub-images with this format"); 5005 return false; 5006 } 5007 default: 5008 return false; 5009 } 5010 } 5011 5012 bool WebGLRenderingContextBase::validateDrawMode(const char* functionName, GLenum mode) 5013 { 5014 switch (mode) { 5015 case GL_POINTS: 5016 case GL_LINE_STRIP: 5017 case GL_LINE_LOOP: 5018 case GL_LINES: 5019 case GL_TRIANGLE_STRIP: 5020 case GL_TRIANGLE_FAN: 5021 case GL_TRIANGLES: 5022 return true; 5023 default: 5024 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid draw mode"); 5025 return false; 5026 } 5027 } 5028 5029 bool WebGLRenderingContextBase::validateStencilSettings(const char* functionName) 5030 { 5031 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) { 5032 synthesizeGLError(GL_INVALID_OPERATION, functionName, "front and back stencils settings do not match"); 5033 return false; 5034 } 5035 return true; 5036 } 5037 5038 bool WebGLRenderingContextBase::validateStencilOrDepthFunc(const char* functionName, GLenum func) 5039 { 5040 switch (func) { 5041 case GL_NEVER: 5042 case GL_LESS: 5043 case GL_LEQUAL: 5044 case GL_GREATER: 5045 case GL_GEQUAL: 5046 case GL_EQUAL: 5047 case GL_NOTEQUAL: 5048 case GL_ALWAYS: 5049 return true; 5050 default: 5051 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid function"); 5052 return false; 5053 } 5054 } 5055 5056 void WebGLRenderingContextBase::printGLErrorToConsole(const String& message) 5057 { 5058 if (!m_numGLErrorsToConsoleAllowed) 5059 return; 5060 5061 --m_numGLErrorsToConsoleAllowed; 5062 printWarningToConsole(message); 5063 5064 if (!m_numGLErrorsToConsoleAllowed) 5065 printWarningToConsole("WebGL: too many errors, no more errors will be reported to the console for this context."); 5066 5067 return; 5068 } 5069 5070 void WebGLRenderingContextBase::printWarningToConsole(const String& message) 5071 { 5072 if (!canvas()) 5073 return; 5074 canvas()->document().addConsoleMessage(RenderingMessageSource, WarningMessageLevel, message); 5075 } 5076 5077 bool WebGLRenderingContextBase::validateFramebufferFuncParameters(const char* functionName, GLenum target, GLenum attachment) 5078 { 5079 if (target != GL_FRAMEBUFFER) { 5080 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target"); 5081 return false; 5082 } 5083 switch (attachment) { 5084 case GL_COLOR_ATTACHMENT0: 5085 case GL_DEPTH_ATTACHMENT: 5086 case GL_STENCIL_ATTACHMENT: 5087 case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL: 5088 break; 5089 default: 5090 if (extensionEnabled(WebGLDrawBuffersName) 5091 && attachment > GL_COLOR_ATTACHMENT0 5092 && attachment < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + maxColorAttachments())) 5093 break; 5094 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid attachment"); 5095 return false; 5096 } 5097 return true; 5098 } 5099 5100 bool WebGLRenderingContextBase::validateBlendEquation(const char* functionName, GLenum mode) 5101 { 5102 switch (mode) { 5103 case GL_FUNC_ADD: 5104 case GL_FUNC_SUBTRACT: 5105 case GL_FUNC_REVERSE_SUBTRACT: 5106 return true; 5107 case GL_MIN_EXT: 5108 case GL_MAX_EXT: 5109 if (extensionEnabled(EXTBlendMinMaxName)) 5110 return true; 5111 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid mode"); 5112 return false; 5113 default: 5114 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid mode"); 5115 return false; 5116 } 5117 } 5118 5119 bool WebGLRenderingContextBase::validateBlendFuncFactors(const char* functionName, GLenum src, GLenum dst) 5120 { 5121 if (((src == GL_CONSTANT_COLOR || src == GL_ONE_MINUS_CONSTANT_COLOR) 5122 && (dst == GL_CONSTANT_ALPHA || dst == GL_ONE_MINUS_CONSTANT_ALPHA)) 5123 || ((dst == GL_CONSTANT_COLOR || dst == GL_ONE_MINUS_CONSTANT_COLOR) 5124 && (src == GL_CONSTANT_ALPHA || src == GL_ONE_MINUS_CONSTANT_ALPHA))) { 5125 synthesizeGLError(GL_INVALID_OPERATION, functionName, "incompatible src and dst"); 5126 return false; 5127 } 5128 return true; 5129 } 5130 5131 bool WebGLRenderingContextBase::validateCapability(const char* functionName, GLenum cap) 5132 { 5133 switch (cap) { 5134 case GL_BLEND: 5135 case GL_CULL_FACE: 5136 case GL_DEPTH_TEST: 5137 case GL_DITHER: 5138 case GL_POLYGON_OFFSET_FILL: 5139 case GL_SAMPLE_ALPHA_TO_COVERAGE: 5140 case GL_SAMPLE_COVERAGE: 5141 case GL_SCISSOR_TEST: 5142 case GL_STENCIL_TEST: 5143 return true; 5144 default: 5145 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid capability"); 5146 return false; 5147 } 5148 } 5149 5150 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Float32Array* v, GLsizei requiredMinSize) 5151 { 5152 if (!v) { 5153 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5154 return false; 5155 } 5156 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize); 5157 } 5158 5159 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, Int32Array* v, GLsizei requiredMinSize) 5160 { 5161 if (!v) { 5162 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5163 return false; 5164 } 5165 return validateUniformMatrixParameters(functionName, location, false, v->data(), v->length(), requiredMinSize); 5166 } 5167 5168 bool WebGLRenderingContextBase::validateUniformParameters(const char* functionName, const WebGLUniformLocation* location, void* v, GLsizei size, GLsizei requiredMinSize) 5169 { 5170 return validateUniformMatrixParameters(functionName, location, false, v, size, requiredMinSize); 5171 } 5172 5173 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, Float32Array* v, GLsizei requiredMinSize) 5174 { 5175 if (!v) { 5176 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5177 return false; 5178 } 5179 return validateUniformMatrixParameters(functionName, location, transpose, v->data(), v->length(), requiredMinSize); 5180 } 5181 5182 bool WebGLRenderingContextBase::validateUniformMatrixParameters(const char* functionName, const WebGLUniformLocation* location, GLboolean transpose, void* v, GLsizei size, GLsizei requiredMinSize) 5183 { 5184 if (!location) 5185 return false; 5186 if (location->program() != m_currentProgram) { 5187 synthesizeGLError(GL_INVALID_OPERATION, functionName, "location is not from current program"); 5188 return false; 5189 } 5190 if (!v) { 5191 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5192 return false; 5193 } 5194 if (transpose) { 5195 synthesizeGLError(GL_INVALID_VALUE, functionName, "transpose not FALSE"); 5196 return false; 5197 } 5198 if (size < requiredMinSize || (size % requiredMinSize)) { 5199 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size"); 5200 return false; 5201 } 5202 return true; 5203 } 5204 5205 WebGLBuffer* WebGLRenderingContextBase::validateBufferDataTarget(const char* functionName, GLenum target) 5206 { 5207 WebGLBuffer* buffer = 0; 5208 switch (target) { 5209 case GL_ELEMENT_ARRAY_BUFFER: 5210 buffer = m_boundVertexArrayObject->boundElementArrayBuffer().get(); 5211 break; 5212 case GL_ARRAY_BUFFER: 5213 buffer = m_boundArrayBuffer.get(); 5214 break; 5215 default: 5216 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target"); 5217 return 0; 5218 } 5219 if (!buffer) { 5220 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no buffer"); 5221 return 0; 5222 } 5223 return buffer; 5224 } 5225 5226 bool WebGLRenderingContextBase::validateHTMLImageElement(const char* functionName, HTMLImageElement* image, ExceptionState& exceptionState) 5227 { 5228 if (!image || !image->cachedImage()) { 5229 synthesizeGLError(GL_INVALID_VALUE, functionName, "no image"); 5230 return false; 5231 } 5232 const KURL& url = image->cachedImage()->response().url(); 5233 if (url.isNull() || url.isEmpty() || !url.isValid()) { 5234 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid image"); 5235 return false; 5236 } 5237 5238 if (wouldTaintOrigin(image)) { 5239 exceptionState.throwSecurityError("The cross-origin image at " + url.elidedString() + " may not be loaded."); 5240 return false; 5241 } 5242 return true; 5243 } 5244 5245 bool WebGLRenderingContextBase::validateHTMLCanvasElement(const char* functionName, HTMLCanvasElement* canvas, ExceptionState& exceptionState) 5246 { 5247 if (!canvas || !canvas->buffer()) { 5248 synthesizeGLError(GL_INVALID_VALUE, functionName, "no canvas"); 5249 return false; 5250 } 5251 if (wouldTaintOrigin(canvas)) { 5252 exceptionState.throwSecurityError("Tainted canvases may not be loaded."); 5253 return false; 5254 } 5255 return true; 5256 } 5257 5258 bool WebGLRenderingContextBase::validateHTMLVideoElement(const char* functionName, HTMLVideoElement* video, ExceptionState& exceptionState) 5259 { 5260 if (!video || !video->videoWidth() || !video->videoHeight()) { 5261 synthesizeGLError(GL_INVALID_VALUE, functionName, "no video"); 5262 return false; 5263 } 5264 5265 if (wouldTaintOrigin(video)) { 5266 exceptionState.throwSecurityError("The video element contains cross-origin data, and may not be loaded."); 5267 return false; 5268 } 5269 return true; 5270 } 5271 5272 bool WebGLRenderingContextBase::validateDrawArrays(const char* functionName, GLenum mode, GLint first, GLsizei count) 5273 { 5274 if (isContextLost() || !validateDrawMode(functionName, mode)) 5275 return false; 5276 5277 if (!validateStencilSettings(functionName)) 5278 return false; 5279 5280 if (first < 0 || count < 0) { 5281 synthesizeGLError(GL_INVALID_VALUE, functionName, "first or count < 0"); 5282 return false; 5283 } 5284 5285 if (!count) { 5286 markContextChanged(CanvasChanged); 5287 return false; 5288 } 5289 5290 if (!validateRenderingState(functionName)) { 5291 return false; 5292 } 5293 5294 const char* reason = "framebuffer incomplete"; 5295 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 5296 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason); 5297 return false; 5298 } 5299 5300 return true; 5301 } 5302 5303 bool WebGLRenderingContextBase::validateDrawElements(const char* functionName, GLenum mode, GLsizei count, GLenum type, long long offset) 5304 { 5305 if (isContextLost() || !validateDrawMode(functionName, mode)) 5306 return false; 5307 5308 if (!validateStencilSettings(functionName)) 5309 return false; 5310 5311 switch (type) { 5312 case GL_UNSIGNED_BYTE: 5313 case GL_UNSIGNED_SHORT: 5314 break; 5315 case GL_UNSIGNED_INT: 5316 if (extensionEnabled(OESElementIndexUintName)) 5317 break; 5318 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type"); 5319 return false; 5320 default: 5321 synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid type"); 5322 return false; 5323 } 5324 5325 if (count < 0) { 5326 synthesizeGLError(GL_INVALID_VALUE, functionName, "count < 0"); 5327 return false; 5328 } 5329 if (!validateValueFitNonNegInt32(functionName, "offset", offset)) 5330 return false; 5331 5332 if (!count) { 5333 markContextChanged(CanvasChanged); 5334 return false; 5335 } 5336 5337 if (!m_boundVertexArrayObject->boundElementArrayBuffer()) { 5338 synthesizeGLError(GL_INVALID_OPERATION, functionName, "no ELEMENT_ARRAY_BUFFER bound"); 5339 return false; 5340 } 5341 5342 if (!validateRenderingState(functionName)) { 5343 return false; 5344 } 5345 5346 const char* reason = "framebuffer incomplete"; 5347 if (m_framebufferBinding && !m_framebufferBinding->onAccess(webContext(), &reason)) { 5348 synthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, functionName, reason); 5349 return false; 5350 } 5351 5352 return true; 5353 } 5354 5355 // Helper function to validate draw*Instanced calls 5356 bool WebGLRenderingContextBase::validateDrawInstanced(const char* functionName, GLsizei primcount) 5357 { 5358 if (primcount < 0) { 5359 synthesizeGLError(GL_INVALID_VALUE, functionName, "primcount < 0"); 5360 return false; 5361 } 5362 5363 // Ensure at least one enabled vertex attrib has a divisor of 0. 5364 for (unsigned i = 0; i < m_onePlusMaxEnabledAttribIndex; ++i) { 5365 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i); 5366 if (state.enabled && !state.divisor) 5367 return true; 5368 } 5369 5370 synthesizeGLError(GL_INVALID_OPERATION, functionName, "at least one enabled attribute must have a divisor of 0"); 5371 return false; 5372 } 5373 5374 void WebGLRenderingContextBase::vertexAttribfImpl(const char* functionName, GLuint index, GLsizei expectedSize, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) 5375 { 5376 if (isContextLost()) 5377 return; 5378 if (index >= m_maxVertexAttribs) { 5379 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); 5380 return; 5381 } 5382 // In GL, we skip setting vertexAttrib0 values. 5383 switch (expectedSize) { 5384 case 1: 5385 webContext()->vertexAttrib1f(index, v0); 5386 break; 5387 case 2: 5388 webContext()->vertexAttrib2f(index, v0, v1); 5389 break; 5390 case 3: 5391 webContext()->vertexAttrib3f(index, v0, v1, v2); 5392 break; 5393 case 4: 5394 webContext()->vertexAttrib4f(index, v0, v1, v2, v3); 5395 break; 5396 } 5397 VertexAttribValue& attribValue = m_vertexAttribValue[index]; 5398 attribValue.value[0] = v0; 5399 attribValue.value[1] = v1; 5400 attribValue.value[2] = v2; 5401 attribValue.value[3] = v3; 5402 } 5403 5404 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, Float32Array* v, GLsizei expectedSize) 5405 { 5406 if (isContextLost()) 5407 return; 5408 if (!v) { 5409 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5410 return; 5411 } 5412 vertexAttribfvImpl(functionName, index, v->data(), v->length(), expectedSize); 5413 } 5414 5415 void WebGLRenderingContextBase::vertexAttribfvImpl(const char* functionName, GLuint index, GLfloat* v, GLsizei size, GLsizei expectedSize) 5416 { 5417 if (isContextLost()) 5418 return; 5419 if (!v) { 5420 synthesizeGLError(GL_INVALID_VALUE, functionName, "no array"); 5421 return; 5422 } 5423 if (size < expectedSize) { 5424 synthesizeGLError(GL_INVALID_VALUE, functionName, "invalid size"); 5425 return; 5426 } 5427 if (index >= m_maxVertexAttribs) { 5428 synthesizeGLError(GL_INVALID_VALUE, functionName, "index out of range"); 5429 return; 5430 } 5431 // In GL, we skip setting vertexAttrib0 values. 5432 switch (expectedSize) { 5433 case 1: 5434 webContext()->vertexAttrib1fv(index, v); 5435 break; 5436 case 2: 5437 webContext()->vertexAttrib2fv(index, v); 5438 break; 5439 case 3: 5440 webContext()->vertexAttrib3fv(index, v); 5441 break; 5442 case 4: 5443 webContext()->vertexAttrib4fv(index, v); 5444 break; 5445 } 5446 VertexAttribValue& attribValue = m_vertexAttribValue[index]; 5447 attribValue.initValue(); 5448 for (int ii = 0; ii < expectedSize; ++ii) 5449 attribValue.value[ii] = v[ii]; 5450 } 5451 5452 void WebGLRenderingContextBase::dispatchContextLostEvent(Timer<WebGLRenderingContextBase>*) 5453 { 5454 RefPtrWillBeRawPtr<WebGLContextEvent> event = WebGLContextEvent::create(EventTypeNames::webglcontextlost, false, true, ""); 5455 canvas()->dispatchEvent(event); 5456 m_restoreAllowed = event->defaultPrevented(); 5457 deactivateContext(this, m_contextLostMode != RealLostContext && m_restoreAllowed); 5458 if ((m_contextLostMode == RealLostContext || m_contextLostMode == AutoRecoverSyntheticLostContext) && m_restoreAllowed) 5459 m_restoreTimer.startOneShot(0, FROM_HERE); 5460 } 5461 5462 void WebGLRenderingContextBase::maybeRestoreContext(Timer<WebGLRenderingContextBase>*) 5463 { 5464 #ifndef NDEBUG 5465 printWarningToConsole("maybeRestoreContext(): begin"); 5466 #endif 5467 ASSERT(isContextLost()); 5468 5469 // The rendering context is not restored unless the default behavior of the 5470 // webglcontextlost event was prevented earlier. 5471 // 5472 // Because of the way m_restoreTimer is set up for real vs. synthetic lost 5473 // context events, we don't have to worry about this test short-circuiting 5474 // the retry loop for real context lost events. 5475 if (!m_restoreAllowed) 5476 return; 5477 5478 LocalFrame* frame = canvas()->document().frame(); 5479 if (!frame) 5480 return; 5481 5482 Settings* settings = frame->settings(); 5483 5484 if (!frame->loader().client()->allowWebGL(settings && settings->webGLEnabled())) 5485 return; 5486 5487 // If the context was lost due to RealLostContext, we need to destroy the old DrawingBuffer before creating new DrawingBuffer to ensure resource budget enough. 5488 if (m_drawingBuffer) { 5489 m_drawingBuffer->beginDestruction(); 5490 m_drawingBuffer.clear(); 5491 } 5492 #ifndef NDEBUG 5493 printWarningToConsole("maybeRestoreContext(): destroyed old DrawingBuffer"); 5494 #endif 5495 5496 blink::WebGraphicsContext3D::Attributes attributes = m_requestedAttributes->attributes(canvas()->document().topDocument().url().string(), settings); 5497 OwnPtr<blink::WebGraphicsContext3D> context = adoptPtr(blink::Platform::current()->createOffscreenGraphicsContext3D(attributes, 0)); 5498 RefPtr<DrawingBuffer> drawingBuffer; 5499 // Even if a non-null WebGraphicsContext3D is created, until it's made current, it isn't known whether the context is still lost. 5500 if (context) { 5501 // Construct a new drawing buffer with the new WebGraphicsContext3D. 5502 drawingBuffer = createDrawingBuffer(context.release()); 5503 // If DrawingBuffer::create() fails to allocate a fbo, |drawingBuffer| is set to null. 5504 } 5505 if (!drawingBuffer) { 5506 if (m_contextLostMode == RealLostContext) { 5507 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts, FROM_HERE); 5508 } else { 5509 // This likely shouldn't happen but is the best way to report it to the WebGL app. 5510 synthesizeGLError(GL_INVALID_OPERATION, "", "error restoring context"); 5511 } 5512 return; 5513 } 5514 #ifndef NDEBUG 5515 printWarningToConsole("maybeRestoreContext(): created new DrawingBuffer"); 5516 #endif 5517 5518 m_drawingBuffer = drawingBuffer.release(); 5519 m_drawingBuffer->bind(); 5520 m_lostContextErrors.clear(); 5521 m_contextLost = false; 5522 5523 setupFlags(); 5524 initializeNewContext(); 5525 markContextChanged(CanvasContextChanged); 5526 #ifndef NDEBUG 5527 printWarningToConsole("maybeRestoreContext(): before dispatchEvent"); 5528 #endif 5529 canvas()->dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontextrestored, false, true, "")); 5530 #ifndef NDEBUG 5531 printWarningToConsole("maybeRestoreContext(): end"); 5532 #endif 5533 } 5534 5535 String WebGLRenderingContextBase::ensureNotNull(const String& text) const 5536 { 5537 if (text.isNull()) 5538 return WTF::emptyString(); 5539 return text; 5540 } 5541 5542 WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(int capacity) 5543 : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity])) 5544 , m_capacity(capacity) 5545 { 5546 } 5547 5548 ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::imageBuffer(const IntSize& size) 5549 { 5550 int i; 5551 for (i = 0; i < m_capacity; ++i) { 5552 ImageBuffer* buf = m_buffers[i].get(); 5553 if (!buf) 5554 break; 5555 if (buf->size() != size) 5556 continue; 5557 bubbleToFront(i); 5558 return buf; 5559 } 5560 5561 OwnPtr<ImageBuffer> temp(ImageBuffer::create(size)); 5562 if (!temp) 5563 return 0; 5564 i = std::min(m_capacity - 1, i); 5565 m_buffers[i] = temp.release(); 5566 5567 ImageBuffer* buf = m_buffers[i].get(); 5568 bubbleToFront(i); 5569 return buf; 5570 } 5571 5572 void WebGLRenderingContextBase::LRUImageBufferCache::bubbleToFront(int idx) 5573 { 5574 for (int i = idx; i > 0; --i) 5575 m_buffers[i].swap(m_buffers[i-1]); 5576 } 5577 5578 namespace { 5579 5580 String GetErrorString(GLenum error) 5581 { 5582 switch (error) { 5583 case GL_INVALID_ENUM: 5584 return "INVALID_ENUM"; 5585 case GL_INVALID_VALUE: 5586 return "INVALID_VALUE"; 5587 case GL_INVALID_OPERATION: 5588 return "INVALID_OPERATION"; 5589 case GL_OUT_OF_MEMORY: 5590 return "OUT_OF_MEMORY"; 5591 case GL_INVALID_FRAMEBUFFER_OPERATION: 5592 return "INVALID_FRAMEBUFFER_OPERATION"; 5593 case GC3D_CONTEXT_LOST_WEBGL: 5594 return "CONTEXT_LOST_WEBGL"; 5595 default: 5596 return String::format("WebGL ERROR(0x%04X)", error); 5597 } 5598 } 5599 5600 } // namespace anonymous 5601 5602 void WebGLRenderingContextBase::synthesizeGLError(GLenum error, const char* functionName, const char* description, ConsoleDisplayPreference display) 5603 { 5604 String errorType = GetErrorString(error); 5605 if (m_synthesizedErrorsToConsole && display == DisplayInConsole) { 5606 String message = String("WebGL: ") + errorType + ": " + String(functionName) + ": " + String(description); 5607 printGLErrorToConsole(message); 5608 } 5609 if (!isContextLost()) 5610 webContext()->synthesizeGLError(error); 5611 else { 5612 if (m_lostContextErrors.find(error) == WTF::kNotFound) 5613 m_lostContextErrors.append(error); 5614 } 5615 InspectorInstrumentation::didFireWebGLError(canvas(), errorType); 5616 } 5617 5618 void WebGLRenderingContextBase::emitGLWarning(const char* functionName, const char* description) 5619 { 5620 if (m_synthesizedErrorsToConsole) { 5621 String message = String("WebGL: ") + String(functionName) + ": " + String(description); 5622 printGLErrorToConsole(message); 5623 } 5624 InspectorInstrumentation::didFireWebGLWarning(canvas()); 5625 } 5626 5627 void WebGLRenderingContextBase::applyStencilTest() 5628 { 5629 bool haveStencilBuffer = false; 5630 5631 if (m_framebufferBinding) 5632 haveStencilBuffer = m_framebufferBinding->hasStencilBuffer(); 5633 else { 5634 RefPtr<WebGLContextAttributes> attributes = getContextAttributes(); 5635 haveStencilBuffer = attributes->stencil(); 5636 } 5637 enableOrDisable(GL_STENCIL_TEST, 5638 m_stencilEnabled && haveStencilBuffer); 5639 } 5640 5641 void WebGLRenderingContextBase::enableOrDisable(GLenum capability, bool enable) 5642 { 5643 if (isContextLost()) 5644 return; 5645 if (enable) 5646 webContext()->enable(capability); 5647 else 5648 webContext()->disable(capability); 5649 } 5650 5651 IntSize WebGLRenderingContextBase::clampedCanvasSize() 5652 { 5653 return IntSize(clamp(canvas()->width(), 1, m_maxViewportDims[0]), 5654 clamp(canvas()->height(), 1, m_maxViewportDims[1])); 5655 } 5656 5657 GLint WebGLRenderingContextBase::maxDrawBuffers() 5658 { 5659 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName)) 5660 return 0; 5661 if (!m_maxDrawBuffers) 5662 webContext()->getIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &m_maxDrawBuffers); 5663 if (!m_maxColorAttachments) 5664 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); 5665 // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS. 5666 return std::min(m_maxDrawBuffers, m_maxColorAttachments); 5667 } 5668 5669 GLint WebGLRenderingContextBase::maxColorAttachments() 5670 { 5671 if (isContextLost() || !extensionEnabled(WebGLDrawBuffersName)) 5672 return 0; 5673 if (!m_maxColorAttachments) 5674 webContext()->getIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &m_maxColorAttachments); 5675 return m_maxColorAttachments; 5676 } 5677 5678 void WebGLRenderingContextBase::setBackDrawBuffer(GLenum buf) 5679 { 5680 m_backDrawBuffer = buf; 5681 } 5682 5683 void WebGLRenderingContextBase::restoreCurrentFramebuffer() 5684 { 5685 bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding.get()); 5686 } 5687 5688 void WebGLRenderingContextBase::restoreCurrentTexture2D() 5689 { 5690 bindTexture(GL_TEXTURE_2D, m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get()); 5691 } 5692 5693 void WebGLRenderingContextBase::multisamplingChanged(bool enabled) 5694 { 5695 if (m_multisamplingAllowed != enabled) { 5696 m_multisamplingAllowed = enabled; 5697 forceLostContext(WebGLRenderingContextBase::AutoRecoverSyntheticLostContext); 5698 } 5699 } 5700 5701 void WebGLRenderingContextBase::findNewMaxEnabledAttribIndex() 5702 { 5703 // Trace backwards from the current max to find the new max enabled attrib index 5704 int startIndex = m_onePlusMaxEnabledAttribIndex - 1; 5705 for (int i = startIndex; i >= 0; --i) { 5706 if (m_boundVertexArrayObject->getVertexAttribState(i).enabled) { 5707 m_onePlusMaxEnabledAttribIndex = i + 1; 5708 return; 5709 } 5710 } 5711 m_onePlusMaxEnabledAttribIndex = 0; 5712 } 5713 5714 void WebGLRenderingContextBase::findNewMaxNonDefaultTextureUnit() 5715 { 5716 // Trace backwards from the current max to find the new max non-default texture unit 5717 int startIndex = m_onePlusMaxNonDefaultTextureUnit - 1; 5718 for (int i = startIndex; i >= 0; --i) { 5719 if (m_textureUnits[i].m_texture2DBinding 5720 || m_textureUnits[i].m_textureCubeMapBinding) { 5721 m_onePlusMaxNonDefaultTextureUnit = i + 1; 5722 return; 5723 } 5724 } 5725 m_onePlusMaxNonDefaultTextureUnit = 0; 5726 } 5727 5728 } // namespace WebCore 5729