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