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