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