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 28 #if ENABLE(WEBGL) 29 30 #include "WebGLRenderingContext.h" 31 32 #include "CachedImage.h" 33 #include "CanvasPixelArray.h" 34 #include "CheckedInt.h" 35 #include "WebKitLoseContext.h" 36 #include "Console.h" 37 #include "DOMWindow.h" 38 #include "Extensions3D.h" 39 #include "FrameView.h" 40 #include "HTMLCanvasElement.h" 41 #include "HTMLImageElement.h" 42 #include "HTMLVideoElement.h" 43 #include "ImageBuffer.h" 44 #include "ImageData.h" 45 #include "IntSize.h" 46 #include "NotImplemented.h" 47 #include "OESStandardDerivatives.h" 48 #include "OESTextureFloat.h" 49 #include "OESVertexArrayObject.h" 50 #include "RenderBox.h" 51 #include "RenderLayer.h" 52 #include "Settings.h" 53 #include "Uint16Array.h" 54 #include "WebGLActiveInfo.h" 55 #include "WebGLBuffer.h" 56 #include "WebGLContextAttributes.h" 57 #include "WebGLContextEvent.h" 58 #include "WebGLFramebuffer.h" 59 #include "WebGLProgram.h" 60 #include "WebGLRenderbuffer.h" 61 #include "WebGLShader.h" 62 #include "WebGLTexture.h" 63 #include "WebGLUniformLocation.h" 64 65 #include <wtf/ByteArray.h> 66 #include <wtf/OwnArrayPtr.h> 67 #include <wtf/PassOwnArrayPtr.h> 68 #include <wtf/text/StringBuilder.h> 69 70 #if PLATFORM(QT) 71 #undef emit 72 #endif 73 74 namespace WebCore { 75 76 const double secondsBetweenRestoreAttempts = 1.0; 77 78 namespace { 79 80 Platform3DObject objectOrZero(WebGLObject* object) 81 { 82 return object ? object->object() : 0; 83 } 84 85 void clip1D(GC3Dint start, GC3Dsizei range, GC3Dsizei sourceRange, GC3Dint* clippedStart, GC3Dsizei* clippedRange) 86 { 87 ASSERT(clippedStart && clippedRange); 88 if (start < 0) { 89 range += start; 90 start = 0; 91 } 92 GC3Dint end = start + range; 93 if (end > sourceRange) 94 range -= end - sourceRange; 95 *clippedStart = start; 96 *clippedRange = range; 97 } 98 99 // Returns false if no clipping is necessary, i.e., x, y, width, height stay the same. 100 bool clip2D(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, 101 GC3Dsizei sourceWidth, GC3Dsizei sourceHeight, 102 GC3Dint* clippedX, GC3Dint* clippedY, GC3Dsizei* clippedWidth, GC3Dsizei*clippedHeight) 103 { 104 ASSERT(clippedX && clippedY && clippedWidth && clippedHeight); 105 clip1D(x, width, sourceWidth, clippedX, clippedWidth); 106 clip1D(y, height, sourceHeight, clippedY, clippedHeight); 107 return (*clippedX != x || *clippedY != y || *clippedWidth != width || *clippedHeight != height); 108 } 109 110 // Return true if a character belongs to the ASCII subset as defined in 111 // GLSL ES 1.0 spec section 3.1. 112 bool validateCharacter(unsigned char c) 113 { 114 // Printing characters are valid except " $ ` @ \ ' DEL. 115 if (c >= 32 && c <= 126 116 && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') 117 return true; 118 // Horizontal tab, line feed, vertical tab, form feed, carriage return 119 // are also valid. 120 if (c >= 9 && c <= 13) 121 return true; 122 return false; 123 } 124 125 // Strips comments from shader text. This allows non-ASCII characters 126 // to be used in comments without potentially breaking OpenGL 127 // implementations not expecting characters outside the GLSL ES set. 128 class StripComments { 129 public: 130 StripComments(const String& str) 131 : m_parseState(BeginningOfLine) 132 , m_sourceString(str) 133 , m_length(str.length()) 134 , m_position(0) 135 { 136 parse(); 137 } 138 139 String result() 140 { 141 return m_builder.toString(); 142 } 143 144 private: 145 bool hasMoreCharacters() 146 { 147 return (m_position < m_length); 148 } 149 150 void parse() 151 { 152 while (hasMoreCharacters()) { 153 process(current()); 154 // process() might advance the position. 155 if (hasMoreCharacters()) 156 advance(); 157 } 158 } 159 160 void process(UChar); 161 162 bool peek(UChar& character) 163 { 164 if (m_position + 1 >= m_length) 165 return false; 166 character = m_sourceString[m_position + 1]; 167 return true; 168 } 169 170 UChar current() 171 { 172 ASSERT(m_position < m_length); 173 return m_sourceString[m_position]; 174 } 175 176 void advance() 177 { 178 ++m_position; 179 } 180 181 bool isNewline(UChar character) 182 { 183 // Don't attempt to canonicalize newline related characters. 184 return (character == '\n' || character == '\r'); 185 } 186 187 void emit(UChar character) 188 { 189 m_builder.append(character); 190 } 191 192 enum ParseState { 193 // Have not seen an ASCII non-whitespace character yet on 194 // this line. Possible that we might see a preprocessor 195 // directive. 196 BeginningOfLine, 197 198 // Have seen at least one ASCII non-whitespace character 199 // on this line. 200 MiddleOfLine, 201 202 // Handling a preprocessor directive. Passes through all 203 // characters up to the end of the line. Disables comment 204 // processing. 205 InPreprocessorDirective, 206 207 // Handling a single-line comment. The comment text is 208 // replaced with a single space. 209 InSingleLineComment, 210 211 // Handling a multi-line comment. Newlines are passed 212 // through to preserve line numbers. 213 InMultiLineComment 214 }; 215 216 ParseState m_parseState; 217 String m_sourceString; 218 unsigned m_length; 219 unsigned m_position; 220 StringBuilder m_builder; 221 }; 222 223 void StripComments::process(UChar c) 224 { 225 if (isNewline(c)) { 226 // No matter what state we are in, pass through newlines 227 // so we preserve line numbers. 228 emit(c); 229 230 if (m_parseState != InMultiLineComment) 231 m_parseState = BeginningOfLine; 232 233 return; 234 } 235 236 UChar temp = 0; 237 switch (m_parseState) { 238 case BeginningOfLine: 239 if (WTF::isASCIISpace(c)) { 240 emit(c); 241 break; 242 } 243 244 if (c == '#') { 245 m_parseState = InPreprocessorDirective; 246 emit(c); 247 break; 248 } 249 250 // Transition to normal state and re-handle character. 251 m_parseState = MiddleOfLine; 252 process(c); 253 break; 254 255 case MiddleOfLine: 256 if (c == '/' && peek(temp)) { 257 if (temp == '/') { 258 m_parseState = InSingleLineComment; 259 emit(' '); 260 advance(); 261 break; 262 } 263 264 if (temp == '*') { 265 m_parseState = InMultiLineComment; 266 // Emit the comment start in case the user has 267 // an unclosed comment and we want to later 268 // signal an error. 269 emit('/'); 270 emit('*'); 271 advance(); 272 break; 273 } 274 } 275 276 emit(c); 277 break; 278 279 case InPreprocessorDirective: 280 // No matter what the character is, just pass it 281 // through. Do not parse comments in this state. This 282 // might not be the right thing to do long term, but it 283 // should handle the #error preprocessor directive. 284 emit(c); 285 break; 286 287 case InSingleLineComment: 288 // The newline code at the top of this function takes care 289 // of resetting our state when we get out of the 290 // single-line comment. Swallow all other characters. 291 break; 292 293 case InMultiLineComment: 294 if (c == '*' && peek(temp) && temp == '/') { 295 emit('*'); 296 emit('/'); 297 m_parseState = MiddleOfLine; 298 advance(); 299 break; 300 } 301 302 // Swallow all other characters. Unclear whether we may 303 // want or need to just emit a space per character to try 304 // to preserve column numbers for debugging purposes. 305 break; 306 } 307 } 308 } // namespace anonymous 309 310 class WebGLStateRestorer { 311 public: 312 WebGLStateRestorer(WebGLRenderingContext* context, 313 bool changed) 314 : m_context(context) 315 , m_changed(changed) 316 { 317 } 318 319 ~WebGLStateRestorer() 320 { 321 m_context->cleanupAfterGraphicsCall(m_changed); 322 } 323 324 private: 325 WebGLRenderingContext* m_context; 326 bool m_changed; 327 }; 328 329 void WebGLRenderingContext::WebGLRenderingContextRestoreTimer::fired() 330 { 331 // Timer is started when m_contextLost is false. It will first call 332 // onLostContext, which will set m_contextLost to true. Then it will keep 333 // calling restoreContext and reschedule itself until m_contextLost is back 334 // to false. 335 if (!m_context->m_contextLost) { 336 m_context->onLostContext(); 337 startOneShot(secondsBetweenRestoreAttempts); 338 } else { 339 // The rendering context is not restored if there is no handler for 340 // the context restored event. 341 if (!m_context->canvas()->hasEventListeners(eventNames().webglcontextrestoredEvent)) 342 return; 343 344 m_context->restoreContext(); 345 if (m_context->m_contextLost) 346 startOneShot(secondsBetweenRestoreAttempts); 347 } 348 } 349 350 class WebGLRenderingContextLostCallback : public GraphicsContext3D::ContextLostCallback { 351 public: 352 WebGLRenderingContextLostCallback(WebGLRenderingContext* cb) : m_contextLostCallback(cb) {} 353 virtual void onContextLost() { m_contextLostCallback->forceLostContext(); } 354 virtual ~WebGLRenderingContextLostCallback() {} 355 private: 356 WebGLRenderingContext* m_contextLostCallback; 357 }; 358 359 PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElement* canvas, WebGLContextAttributes* attrs) 360 { 361 HostWindow* hostWindow = canvas->document()->view()->root()->hostWindow(); 362 GraphicsContext3D::Attributes attributes = attrs ? attrs->attributes() : GraphicsContext3D::Attributes(); 363 364 if (attributes.antialias) { 365 Page* p = canvas->document()->page(); 366 if (p && !p->settings()->openGLMultisamplingEnabled()) 367 attributes.antialias = false; 368 } 369 370 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(attributes, hostWindow)); 371 372 if (!context) { 373 canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent, false, true, "Could not create a WebGL context.")); 374 return 0; 375 } 376 377 return new WebGLRenderingContext(canvas, context, attributes); 378 } 379 380 WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context, 381 GraphicsContext3D::Attributes attributes) 382 : CanvasRenderingContext(passedCanvas) 383 , m_context(context) 384 , m_restoreTimer(this) 385 , m_videoCache(4) 386 , m_contextLost(false) 387 , m_attributes(attributes) 388 { 389 ASSERT(m_context); 390 setupFlags(); 391 initializeNewContext(); 392 } 393 394 void WebGLRenderingContext::initializeNewContext() 395 { 396 ASSERT(!m_contextLost); 397 m_needsUpdate = true; 398 m_markedCanvasDirty = false; 399 m_activeTextureUnit = 0; 400 m_packAlignment = 4; 401 m_unpackAlignment = 4; 402 m_unpackFlipY = false; 403 m_unpackPremultiplyAlpha = false; 404 m_unpackColorspaceConversion = GraphicsContext3D::BROWSER_DEFAULT_WEBGL; 405 m_boundArrayBuffer = 0; 406 m_currentProgram = 0; 407 m_framebufferBinding = 0; 408 m_renderbufferBinding = 0; 409 m_stencilMask = 0xFFFFFFFF; 410 m_stencilMaskBack = 0xFFFFFFFF; 411 m_stencilFuncRef = 0; 412 m_stencilFuncRefBack = 0; 413 m_stencilFuncMask = 0xFFFFFFFF; 414 m_stencilFuncMaskBack = 0xFFFFFFFF; 415 m_layerCleared = false; 416 417 m_clearColor[0] = m_clearColor[1] = m_clearColor[2] = m_clearColor[3] = 0; 418 m_scissorEnabled = false; 419 m_clearDepth = 1; 420 m_clearStencil = 0; 421 m_colorMask[0] = m_colorMask[1] = m_colorMask[2] = m_colorMask[3] = true; 422 423 GC3Dint numCombinedTextureImageUnits = 0; 424 m_context->getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numCombinedTextureImageUnits); 425 m_textureUnits.clear(); 426 m_textureUnits.resize(numCombinedTextureImageUnits); 427 428 GC3Dint numVertexAttribs = 0; 429 m_context->getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &numVertexAttribs); 430 m_maxVertexAttribs = numVertexAttribs; 431 432 m_maxTextureSize = 0; 433 m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize); 434 m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize); 435 m_maxCubeMapTextureSize = 0; 436 m_context->getIntegerv(GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize); 437 m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize); 438 439 m_defaultVertexArrayObject = WebGLVertexArrayObjectOES::create(this, WebGLVertexArrayObjectOES::VaoTypeDefault); 440 addObject(m_defaultVertexArrayObject.get()); 441 m_boundVertexArrayObject = m_defaultVertexArrayObject; 442 443 m_vertexAttribValue.resize(m_maxVertexAttribs); 444 445 if (!isGLES2NPOTStrict()) 446 createFallbackBlackTextures1x1(); 447 if (!isGLES2Compliant()) 448 initVertexAttrib0(); 449 450 m_context->reshape(canvas()->width(), canvas()->height()); 451 m_context->viewport(0, 0, canvas()->width(), canvas()->height()); 452 453 m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this))); 454 } 455 456 void WebGLRenderingContext::setupFlags() 457 { 458 ASSERT(m_context); 459 460 m_isGLES2Compliant = m_context->isGLES2Compliant(); 461 m_isErrorGeneratedOnOutOfBoundsAccesses = m_context->getExtensions()->isEnabled("GL_CHROMIUM_strict_attribs"); 462 m_isResourceSafe = m_context->getExtensions()->isEnabled("GL_CHROMIUM_resource_safe"); 463 if (m_isGLES2Compliant) { 464 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_OES_texture_npot"); 465 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_OES_packed_depth_stencil"); 466 } else { 467 m_isGLES2NPOTStrict = !m_context->getExtensions()->isEnabled("GL_ARB_texture_non_power_of_two"); 468 m_isDepthStencilSupported = m_context->getExtensions()->isEnabled("GL_EXT_packed_depth_stencil"); 469 } 470 } 471 472 WebGLRenderingContext::~WebGLRenderingContext() 473 { 474 detachAndRemoveAllObjects(); 475 m_context->setContextLostCallback(0); 476 if (m_webkitLoseContext) 477 m_webkitLoseContext->contextDestroyed(); 478 } 479 480 void WebGLRenderingContext::markContextChanged() 481 { 482 if (m_framebufferBinding) 483 return; 484 m_context->markContextChanged(); 485 m_layerCleared = false; 486 #if USE(ACCELERATED_COMPOSITING) 487 RenderBox* renderBox = canvas()->renderBox(); 488 if (renderBox && renderBox->hasLayer() && renderBox->layer()->hasAcceleratedCompositing()) 489 renderBox->layer()->contentChanged(RenderLayer::CanvasChanged); 490 else { 491 #endif 492 if (!m_markedCanvasDirty) 493 canvas()->didDraw(FloatRect(0, 0, canvas()->width(), canvas()->height())); 494 #if USE(ACCELERATED_COMPOSITING) 495 } 496 #endif 497 m_markedCanvasDirty = true; 498 } 499 500 bool WebGLRenderingContext::clearIfComposited(GC3Dbitfield mask) 501 { 502 if (isContextLost()) 503 return false; 504 505 if (!m_context->layerComposited() || m_layerCleared 506 || m_attributes.preserveDrawingBuffer || m_framebufferBinding) 507 return false; 508 509 RefPtr<WebGLContextAttributes> contextAttributes = getContextAttributes(); 510 511 // Determine if it's possible to combine the clear the user asked for and this clear. 512 bool combinedClear = mask && !m_scissorEnabled; 513 514 m_context->disable(GraphicsContext3D::SCISSOR_TEST); 515 if (combinedClear && (mask & GraphicsContext3D::COLOR_BUFFER_BIT)) 516 m_context->clearColor(m_colorMask[0] ? m_clearColor[0] : 0, 517 m_colorMask[1] ? m_clearColor[1] : 0, 518 m_colorMask[2] ? m_clearColor[2] : 0, 519 m_colorMask[3] ? m_clearColor[3] : 0); 520 else 521 m_context->clearColor(0, 0, 0, 0); 522 m_context->colorMask(true, true, true, true); 523 if (contextAttributes->depth() && (!combinedClear || !(mask & GraphicsContext3D::DEPTH_BUFFER_BIT))) 524 m_context->clearDepth(1.0f); 525 if (contextAttributes->stencil() && (!combinedClear || !(mask & GraphicsContext3D::STENCIL_BUFFER_BIT))) 526 m_context->clearStencil(0); 527 GC3Dbitfield clearMask = GraphicsContext3D::COLOR_BUFFER_BIT; 528 if (contextAttributes->depth()) 529 clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT; 530 if (contextAttributes->stencil()) 531 clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT; 532 m_context->clear(clearMask); 533 534 // Restore the state that the context set. 535 if (m_scissorEnabled) 536 m_context->enable(GraphicsContext3D::SCISSOR_TEST); 537 m_context->clearColor(m_clearColor[0], m_clearColor[1], 538 m_clearColor[2], m_clearColor[3]); 539 m_context->colorMask(m_colorMask[0], m_colorMask[1], 540 m_colorMask[2], m_colorMask[3]); 541 m_context->clearDepth(m_clearDepth); 542 m_context->clearStencil(m_clearStencil); 543 m_layerCleared = true; 544 545 return combinedClear; 546 } 547 548 void WebGLRenderingContext::markLayerComposited() 549 { 550 m_context->markLayerComposited(); 551 } 552 553 void WebGLRenderingContext::paintRenderingResultsToCanvas() 554 { 555 // Until the canvas is written to by the application, the clear that 556 // happened after it was composited should be ignored by the compositor. 557 if (m_context->layerComposited() && !m_attributes.preserveDrawingBuffer) 558 canvas()->makePresentationCopy(); 559 else 560 canvas()->clearPresentationCopy(); 561 clearIfComposited(); 562 if (!m_markedCanvasDirty && !m_layerCleared) 563 return; 564 canvas()->clearCopiedImage(); 565 m_markedCanvasDirty = false; 566 m_context->paintRenderingResultsToCanvas(this); 567 } 568 569 PassRefPtr<ImageData> WebGLRenderingContext::paintRenderingResultsToImageData() 570 { 571 clearIfComposited(); 572 return m_context->paintRenderingResultsToImageData(); 573 } 574 575 bool WebGLRenderingContext::paintsIntoCanvasBuffer() const 576 { 577 return m_context->paintsIntoCanvasBuffer(); 578 } 579 580 void WebGLRenderingContext::reshape(int width, int height) 581 { 582 if (m_needsUpdate) { 583 #if USE(ACCELERATED_COMPOSITING) 584 RenderBox* renderBox = canvas()->renderBox(); 585 if (renderBox && renderBox->hasLayer()) 586 renderBox->layer()->contentChanged(RenderLayer::CanvasChanged); 587 #endif 588 m_needsUpdate = false; 589 } 590 591 // We don't have to mark the canvas as dirty, since the newly created image buffer will also start off 592 // clear (and this matches what reshape will do). 593 m_context->reshape(width, height); 594 } 595 596 unsigned int WebGLRenderingContext::sizeInBytes(GC3Denum type) 597 { 598 switch (type) { 599 case GraphicsContext3D::BYTE: 600 return sizeof(GC3Dbyte); 601 case GraphicsContext3D::UNSIGNED_BYTE: 602 return sizeof(GC3Dubyte); 603 case GraphicsContext3D::SHORT: 604 return sizeof(GC3Dshort); 605 case GraphicsContext3D::UNSIGNED_SHORT: 606 return sizeof(GC3Dushort); 607 case GraphicsContext3D::INT: 608 return sizeof(GC3Dint); 609 case GraphicsContext3D::UNSIGNED_INT: 610 return sizeof(GC3Duint); 611 case GraphicsContext3D::FLOAT: 612 return sizeof(GC3Dfloat); 613 } 614 ASSERT_NOT_REACHED(); 615 return 0; 616 } 617 618 void WebGLRenderingContext::activeTexture(GC3Denum texture, ExceptionCode& ec) 619 { 620 UNUSED_PARAM(ec); 621 if (isContextLost()) 622 return; 623 if (texture - GraphicsContext3D::TEXTURE0 >= m_textureUnits.size()) { 624 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 625 return; 626 } 627 m_activeTextureUnit = texture - GraphicsContext3D::TEXTURE0; 628 m_context->activeTexture(texture); 629 cleanupAfterGraphicsCall(false); 630 } 631 632 void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec) 633 { 634 UNUSED_PARAM(ec); 635 if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader)) 636 return; 637 if (!program->attachShader(shader)) { 638 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 639 return; 640 } 641 m_context->attachShader(objectOrZero(program), objectOrZero(shader)); 642 shader->onAttached(); 643 cleanupAfterGraphicsCall(false); 644 } 645 646 void WebGLRenderingContext::bindAttribLocation(WebGLProgram* program, GC3Duint index, const String& name, ExceptionCode& ec) 647 { 648 UNUSED_PARAM(ec); 649 if (isContextLost() || !validateWebGLObject(program)) 650 return; 651 if (!validateString(name)) 652 return; 653 m_context->bindAttribLocation(objectOrZero(program), index, name); 654 cleanupAfterGraphicsCall(false); 655 } 656 657 bool WebGLRenderingContext::checkObjectToBeBound(WebGLObject* object, bool& deleted) 658 { 659 deleted = false; 660 if (isContextLost()) 661 return false; 662 if (object) { 663 if (object->context() != this) { 664 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 665 return false; 666 } 667 deleted = !object->object(); 668 } 669 return true; 670 } 671 672 void WebGLRenderingContext::bindBuffer(GC3Denum target, WebGLBuffer* buffer, ExceptionCode& ec) 673 { 674 UNUSED_PARAM(ec); 675 bool deleted; 676 if (!checkObjectToBeBound(buffer, deleted)) 677 return; 678 if (deleted) 679 buffer = 0; 680 if (buffer && buffer->getTarget() && buffer->getTarget() != target) { 681 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 682 return; 683 } 684 if (target == GraphicsContext3D::ARRAY_BUFFER) 685 m_boundArrayBuffer = buffer; 686 else if (target == GraphicsContext3D::ELEMENT_ARRAY_BUFFER) 687 m_boundVertexArrayObject->setElementArrayBuffer(buffer); 688 else { 689 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 690 return; 691 } 692 693 m_context->bindBuffer(target, objectOrZero(buffer)); 694 if (buffer) 695 buffer->setTarget(target); 696 cleanupAfterGraphicsCall(false); 697 } 698 699 void WebGLRenderingContext::bindFramebuffer(GC3Denum target, WebGLFramebuffer* buffer, ExceptionCode& ec) 700 { 701 UNUSED_PARAM(ec); 702 bool deleted; 703 if (!checkObjectToBeBound(buffer, deleted)) 704 return; 705 if (deleted) 706 buffer = 0; 707 if (target != GraphicsContext3D::FRAMEBUFFER) { 708 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 709 return; 710 } 711 m_framebufferBinding = buffer; 712 m_context->bindFramebuffer(target, objectOrZero(buffer)); 713 if (buffer) 714 buffer->setHasEverBeenBound(); 715 cleanupAfterGraphicsCall(false); 716 } 717 718 void WebGLRenderingContext::bindRenderbuffer(GC3Denum target, WebGLRenderbuffer* renderBuffer, ExceptionCode& ec) 719 { 720 UNUSED_PARAM(ec); 721 bool deleted; 722 if (!checkObjectToBeBound(renderBuffer, deleted)) 723 return; 724 if (deleted) 725 renderBuffer = 0; 726 if (target != GraphicsContext3D::RENDERBUFFER) { 727 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 728 return; 729 } 730 m_renderbufferBinding = renderBuffer; 731 m_context->bindRenderbuffer(target, objectOrZero(renderBuffer)); 732 if (renderBuffer) 733 renderBuffer->setHasEverBeenBound(); 734 cleanupAfterGraphicsCall(false); 735 } 736 737 void WebGLRenderingContext::bindTexture(GC3Denum target, WebGLTexture* texture, ExceptionCode& ec) 738 { 739 UNUSED_PARAM(ec); 740 bool deleted; 741 if (!checkObjectToBeBound(texture, deleted)) 742 return; 743 if (deleted) 744 texture = 0; 745 if (texture && texture->getTarget() && texture->getTarget() != target) { 746 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 747 return; 748 } 749 GC3Dint maxLevel = 0; 750 if (target == GraphicsContext3D::TEXTURE_2D) { 751 m_textureUnits[m_activeTextureUnit].m_texture2DBinding = texture; 752 maxLevel = m_maxTextureLevel; 753 } else if (target == GraphicsContext3D::TEXTURE_CUBE_MAP) { 754 m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding = texture; 755 maxLevel = m_maxCubeMapTextureLevel; 756 } else { 757 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 758 return; 759 } 760 m_context->bindTexture(target, objectOrZero(texture)); 761 if (texture) 762 texture->setTarget(target, maxLevel); 763 764 // Note: previously we used to automatically set the TEXTURE_WRAP_R 765 // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL 766 // ES 2.0 doesn't expose this flag (a bug in the specification) and 767 // otherwise the application has no control over the seams in this 768 // dimension. However, it appears that supporting this properly on all 769 // platforms is fairly involved (will require a HashMap from texture ID 770 // in all ports), and we have not had any complaints, so the logic has 771 // been removed. 772 773 cleanupAfterGraphicsCall(false); 774 } 775 776 void WebGLRenderingContext::blendColor(GC3Dfloat red, GC3Dfloat green, GC3Dfloat blue, GC3Dfloat alpha) 777 { 778 if (isContextLost()) 779 return; 780 m_context->blendColor(red, green, blue, alpha); 781 cleanupAfterGraphicsCall(false); 782 } 783 784 void WebGLRenderingContext::blendEquation(GC3Denum mode) 785 { 786 if (isContextLost() || !validateBlendEquation(mode)) 787 return; 788 m_context->blendEquation(mode); 789 cleanupAfterGraphicsCall(false); 790 } 791 792 void WebGLRenderingContext::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha) 793 { 794 if (isContextLost() || !validateBlendEquation(modeRGB) || !validateBlendEquation(modeAlpha)) 795 return; 796 m_context->blendEquationSeparate(modeRGB, modeAlpha); 797 cleanupAfterGraphicsCall(false); 798 } 799 800 801 void WebGLRenderingContext::blendFunc(GC3Denum sfactor, GC3Denum dfactor) 802 { 803 if (isContextLost() || !validateBlendFuncFactors(sfactor, dfactor)) 804 return; 805 m_context->blendFunc(sfactor, dfactor); 806 cleanupAfterGraphicsCall(false); 807 } 808 809 void WebGLRenderingContext::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha) 810 { 811 if (isContextLost() || !validateBlendFuncFactors(srcRGB, dstRGB)) 812 return; 813 m_context->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); 814 cleanupAfterGraphicsCall(false); 815 } 816 817 void WebGLRenderingContext::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage, ExceptionCode& ec) 818 { 819 UNUSED_PARAM(ec); 820 if (isContextLost()) 821 return; 822 WebGLBuffer* buffer = validateBufferDataParameters(target, usage); 823 if (!buffer) 824 return; 825 if (size < 0) { 826 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 827 return; 828 } 829 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 830 if (!buffer->associateBufferData(size)) { 831 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 832 return; 833 } 834 } 835 836 m_context->bufferData(target, size, usage); 837 cleanupAfterGraphicsCall(false); 838 } 839 840 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBuffer* data, GC3Denum usage, ExceptionCode& ec) 841 { 842 UNUSED_PARAM(ec); 843 if (isContextLost()) 844 return; 845 WebGLBuffer* buffer = validateBufferDataParameters(target, usage); 846 if (!buffer) 847 return; 848 if (!data) { 849 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 850 return; 851 } 852 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 853 if (!buffer->associateBufferData(data)) { 854 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 855 return; 856 } 857 } 858 859 m_context->bufferData(target, data->byteLength(), data->data(), usage); 860 cleanupAfterGraphicsCall(false); 861 } 862 863 void WebGLRenderingContext::bufferData(GC3Denum target, ArrayBufferView* data, GC3Denum usage, ExceptionCode& ec) 864 { 865 UNUSED_PARAM(ec); 866 if (isContextLost()) 867 return; 868 WebGLBuffer* buffer = validateBufferDataParameters(target, usage); 869 if (!buffer) 870 return; 871 if (!data) { 872 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 873 return; 874 } 875 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 876 if (!buffer->associateBufferData(data)) { 877 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 878 return; 879 } 880 } 881 882 m_context->bufferData(target, data->byteLength(), data->baseAddress(), usage); 883 cleanupAfterGraphicsCall(false); 884 } 885 886 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBuffer* data, ExceptionCode& ec) 887 { 888 UNUSED_PARAM(ec); 889 if (isContextLost()) 890 return; 891 WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW); 892 if (!buffer) 893 return; 894 if (offset < 0) { 895 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 896 return; 897 } 898 if (!data) 899 return; 900 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 901 if (!buffer->associateBufferSubData(offset, data)) { 902 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 903 return; 904 } 905 } 906 907 m_context->bufferSubData(target, offset, data->byteLength(), data->data()); 908 cleanupAfterGraphicsCall(false); 909 } 910 911 void WebGLRenderingContext::bufferSubData(GC3Denum target, GC3Dintptr offset, ArrayBufferView* data, ExceptionCode& ec) 912 { 913 UNUSED_PARAM(ec); 914 if (isContextLost()) 915 return; 916 WebGLBuffer* buffer = validateBufferDataParameters(target, GraphicsContext3D::STATIC_DRAW); 917 if (!buffer) 918 return; 919 if (offset < 0) { 920 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 921 return; 922 } 923 if (!data) 924 return; 925 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 926 if (!buffer->associateBufferSubData(offset, data)) { 927 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 928 return; 929 } 930 } 931 932 m_context->bufferSubData(target, offset, data->byteLength(), data->baseAddress()); 933 cleanupAfterGraphicsCall(false); 934 } 935 936 GC3Denum WebGLRenderingContext::checkFramebufferStatus(GC3Denum target) 937 { 938 if (isContextLost()) 939 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; 940 if (target != GraphicsContext3D::FRAMEBUFFER) { 941 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 942 return 0; 943 } 944 if (!m_framebufferBinding || !m_framebufferBinding->object()) 945 return GraphicsContext3D::FRAMEBUFFER_COMPLETE; 946 if (m_framebufferBinding->isIncomplete(true)) 947 return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED; 948 unsigned long result = m_context->checkFramebufferStatus(target); 949 cleanupAfterGraphicsCall(false); 950 return result; 951 } 952 953 void WebGLRenderingContext::clear(GC3Dbitfield mask) 954 { 955 if (isContextLost()) 956 return; 957 if (mask & ~(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT)) { 958 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 959 return; 960 } 961 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 962 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 963 return; 964 } 965 if (!clearIfComposited(mask)) 966 m_context->clear(mask); 967 cleanupAfterGraphicsCall(true); 968 } 969 970 void WebGLRenderingContext::clearColor(GC3Dfloat r, GC3Dfloat g, GC3Dfloat b, GC3Dfloat a) 971 { 972 if (isContextLost()) 973 return; 974 if (isnan(r)) 975 r = 0; 976 if (isnan(g)) 977 g = 0; 978 if (isnan(b)) 979 b = 0; 980 if (isnan(a)) 981 a = 1; 982 m_clearColor[0] = r; 983 m_clearColor[1] = g; 984 m_clearColor[2] = b; 985 m_clearColor[3] = a; 986 m_context->clearColor(r, g, b, a); 987 cleanupAfterGraphicsCall(false); 988 } 989 990 void WebGLRenderingContext::clearDepth(GC3Dfloat depth) 991 { 992 if (isContextLost()) 993 return; 994 m_clearDepth = depth; 995 m_context->clearDepth(depth); 996 cleanupAfterGraphicsCall(false); 997 } 998 999 void WebGLRenderingContext::clearStencil(GC3Dint s) 1000 { 1001 if (isContextLost()) 1002 return; 1003 m_clearStencil = s; 1004 m_context->clearStencil(s); 1005 cleanupAfterGraphicsCall(false); 1006 } 1007 1008 void WebGLRenderingContext::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha) 1009 { 1010 if (isContextLost()) 1011 return; 1012 m_colorMask[0] = red; 1013 m_colorMask[1] = green; 1014 m_colorMask[2] = blue; 1015 m_colorMask[3] = alpha; 1016 m_context->colorMask(red, green, blue, alpha); 1017 cleanupAfterGraphicsCall(false); 1018 } 1019 1020 void WebGLRenderingContext::compileShader(WebGLShader* shader, ExceptionCode& ec) 1021 { 1022 UNUSED_PARAM(ec); 1023 if (isContextLost() || !validateWebGLObject(shader)) 1024 return; 1025 m_context->compileShader(objectOrZero(shader)); 1026 cleanupAfterGraphicsCall(false); 1027 } 1028 1029 void WebGLRenderingContext::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border) 1030 { 1031 if (isContextLost()) 1032 return; 1033 if (!validateTexFuncParameters(target, level, internalformat, width, height, border, internalformat, GraphicsContext3D::UNSIGNED_BYTE)) 1034 return; 1035 WebGLTexture* tex = validateTextureBinding(target, true); 1036 if (!tex) 1037 return; 1038 if (!isTexInternalFormatColorBufferCombinationValid(internalformat, getBoundFramebufferColorFormat())) { 1039 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1040 return; 1041 } 1042 if (!isGLES2NPOTStrict() && level && WebGLTexture::isNPOT(width, height)) { 1043 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1044 return; 1045 } 1046 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 1047 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 1048 return; 1049 } 1050 clearIfComposited(); 1051 if (isResourceSafe()) 1052 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border); 1053 else { 1054 GC3Dint clippedX, clippedY; 1055 GC3Dsizei clippedWidth, clippedHeight; 1056 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) { 1057 m_context->texImage2DResourceSafe(target, level, internalformat, width, height, border, 1058 internalformat, GraphicsContext3D::UNSIGNED_BYTE, m_unpackAlignment); 1059 if (clippedWidth > 0 && clippedHeight > 0) { 1060 m_context->copyTexSubImage2D(target, level, clippedX - x, clippedY - y, 1061 clippedX, clippedY, clippedWidth, clippedHeight); 1062 } 1063 } else 1064 m_context->copyTexImage2D(target, level, internalformat, x, y, width, height, border); 1065 } 1066 // FIXME: if the framebuffer is not complete, none of the below should be executed. 1067 tex->setLevelInfo(target, level, internalformat, width, height, GraphicsContext3D::UNSIGNED_BYTE); 1068 cleanupAfterGraphicsCall(false); 1069 } 1070 1071 void WebGLRenderingContext::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) 1072 { 1073 if (isContextLost()) 1074 return; 1075 if (!validateTexFuncLevel(target, level)) 1076 return; 1077 WebGLTexture* tex = validateTextureBinding(target, true); 1078 if (!tex) 1079 return; 1080 if (!validateSize(xoffset, yoffset) || !validateSize(width, height)) 1081 return; 1082 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) { 1083 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1084 return; 1085 } 1086 if (!isTexInternalFormatColorBufferCombinationValid(tex->getInternalFormat(target, level), getBoundFramebufferColorFormat())) { 1087 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1088 return; 1089 } 1090 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 1091 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 1092 return; 1093 } 1094 clearIfComposited(); 1095 if (isResourceSafe()) 1096 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); 1097 else { 1098 GC3Dint clippedX, clippedY; 1099 GC3Dsizei clippedWidth, clippedHeight; 1100 if (clip2D(x, y, width, height, getBoundFramebufferWidth(), getBoundFramebufferHeight(), &clippedX, &clippedY, &clippedWidth, &clippedHeight)) { 1101 GC3Denum format = tex->getInternalFormat(target, level); 1102 GC3Denum type = tex->getType(target, level); 1103 OwnArrayPtr<unsigned char> zero; 1104 if (width && height) { 1105 unsigned int size; 1106 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &size, 0); 1107 if (error != GraphicsContext3D::NO_ERROR) { 1108 m_context->synthesizeGLError(error); 1109 return; 1110 } 1111 zero = adoptArrayPtr(new unsigned char[size]); 1112 if (!zero) { 1113 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1114 return; 1115 } 1116 memset(zero.get(), 0, size); 1117 } 1118 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, zero.get()); 1119 if (clippedWidth > 0 && clippedHeight > 0) { 1120 m_context->copyTexSubImage2D(target, level, xoffset + clippedX - x, yoffset + clippedY - y, 1121 clippedX, clippedY, clippedWidth, clippedHeight); 1122 } 1123 } else 1124 m_context->copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); 1125 } 1126 cleanupAfterGraphicsCall(false); 1127 } 1128 1129 PassRefPtr<WebGLBuffer> WebGLRenderingContext::createBuffer() 1130 { 1131 if (isContextLost()) 1132 return 0; 1133 RefPtr<WebGLBuffer> o = WebGLBuffer::create(this); 1134 addObject(o.get()); 1135 return o; 1136 } 1137 1138 PassRefPtr<WebGLFramebuffer> WebGLRenderingContext::createFramebuffer() 1139 { 1140 if (isContextLost()) 1141 return 0; 1142 RefPtr<WebGLFramebuffer> o = WebGLFramebuffer::create(this); 1143 addObject(o.get()); 1144 return o; 1145 } 1146 1147 PassRefPtr<WebGLTexture> WebGLRenderingContext::createTexture() 1148 { 1149 if (isContextLost()) 1150 return 0; 1151 RefPtr<WebGLTexture> o = WebGLTexture::create(this); 1152 addObject(o.get()); 1153 return o; 1154 } 1155 1156 PassRefPtr<WebGLProgram> WebGLRenderingContext::createProgram() 1157 { 1158 if (isContextLost()) 1159 return 0; 1160 RefPtr<WebGLProgram> o = WebGLProgram::create(this); 1161 addObject(o.get()); 1162 return o; 1163 } 1164 1165 PassRefPtr<WebGLRenderbuffer> WebGLRenderingContext::createRenderbuffer() 1166 { 1167 if (isContextLost()) 1168 return 0; 1169 RefPtr<WebGLRenderbuffer> o = WebGLRenderbuffer::create(this); 1170 addObject(o.get()); 1171 return o; 1172 } 1173 1174 PassRefPtr<WebGLShader> WebGLRenderingContext::createShader(GC3Denum type, ExceptionCode& ec) 1175 { 1176 UNUSED_PARAM(ec); 1177 if (isContextLost()) 1178 return 0; 1179 if (type != GraphicsContext3D::VERTEX_SHADER && type != GraphicsContext3D::FRAGMENT_SHADER) { 1180 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1181 return 0; 1182 } 1183 1184 RefPtr<WebGLShader> o = WebGLShader::create(this, type); 1185 addObject(o.get()); 1186 return o; 1187 } 1188 1189 void WebGLRenderingContext::cullFace(GC3Denum mode) 1190 { 1191 if (isContextLost()) 1192 return; 1193 m_context->cullFace(mode); 1194 cleanupAfterGraphicsCall(false); 1195 } 1196 1197 bool WebGLRenderingContext::deleteObject(WebGLObject* object) 1198 { 1199 if (isContextLost() || !object) 1200 return false; 1201 if (object->context() != this) { 1202 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1203 return false; 1204 } 1205 if (object->object()) 1206 object->deleteObject(); 1207 return true; 1208 } 1209 1210 void WebGLRenderingContext::deleteBuffer(WebGLBuffer* buffer) 1211 { 1212 if (!deleteObject(buffer)) 1213 return; 1214 if (m_boundArrayBuffer == buffer) 1215 m_boundArrayBuffer = 0; 1216 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); 1217 if (elementArrayBuffer == buffer) 1218 m_boundVertexArrayObject->setElementArrayBuffer(0); 1219 if (!isGLES2Compliant()) { 1220 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0); 1221 if (buffer == state.bufferBinding) { 1222 state.bufferBinding = m_vertexAttrib0Buffer; 1223 state.bytesPerElement = 0; 1224 state.size = 4; 1225 state.type = GraphicsContext3D::FLOAT; 1226 state.normalized = false; 1227 state.stride = 16; 1228 state.originalStride = 0; 1229 state.offset = 0; 1230 } 1231 } 1232 } 1233 1234 void WebGLRenderingContext::deleteFramebuffer(WebGLFramebuffer* framebuffer) 1235 { 1236 if (!deleteObject(framebuffer)) 1237 return; 1238 if (framebuffer == m_framebufferBinding) { 1239 m_framebufferBinding = 0; 1240 // Have to call bindFramebuffer here to bind back to internal fbo. 1241 m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0); 1242 } 1243 } 1244 1245 void WebGLRenderingContext::deleteProgram(WebGLProgram* program) 1246 { 1247 deleteObject(program); 1248 // We don't reset m_currentProgram to 0 here because the deletion of the 1249 // current program is delayed. 1250 } 1251 1252 void WebGLRenderingContext::deleteRenderbuffer(WebGLRenderbuffer* renderbuffer) 1253 { 1254 if (!deleteObject(renderbuffer)) 1255 return; 1256 if (renderbuffer == m_renderbufferBinding) 1257 m_renderbufferBinding = 0; 1258 if (m_framebufferBinding) 1259 m_framebufferBinding->removeAttachment(renderbuffer); 1260 } 1261 1262 void WebGLRenderingContext::deleteShader(WebGLShader* shader) 1263 { 1264 deleteObject(shader); 1265 } 1266 1267 void WebGLRenderingContext::deleteTexture(WebGLTexture* texture) 1268 { 1269 if (!deleteObject(texture)) 1270 return; 1271 for (size_t i = 0; i < m_textureUnits.size(); ++i) { 1272 if (texture == m_textureUnits[i].m_texture2DBinding) 1273 m_textureUnits[i].m_texture2DBinding = 0; 1274 if (texture == m_textureUnits[i].m_textureCubeMapBinding) 1275 m_textureUnits[i].m_textureCubeMapBinding = 0; 1276 } 1277 if (m_framebufferBinding) 1278 m_framebufferBinding->removeAttachment(texture); 1279 } 1280 1281 void WebGLRenderingContext::depthFunc(GC3Denum func) 1282 { 1283 if (isContextLost()) 1284 return; 1285 m_context->depthFunc(func); 1286 cleanupAfterGraphicsCall(false); 1287 } 1288 1289 void WebGLRenderingContext::depthMask(GC3Dboolean flag) 1290 { 1291 if (isContextLost()) 1292 return; 1293 m_context->depthMask(flag); 1294 cleanupAfterGraphicsCall(false); 1295 } 1296 1297 void WebGLRenderingContext::depthRange(GC3Dfloat zNear, GC3Dfloat zFar) 1298 { 1299 if (isContextLost()) 1300 return; 1301 if (zNear > zFar) { 1302 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1303 return; 1304 } 1305 m_context->depthRange(zNear, zFar); 1306 cleanupAfterGraphicsCall(false); 1307 } 1308 1309 void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* shader, ExceptionCode& ec) 1310 { 1311 UNUSED_PARAM(ec); 1312 if (isContextLost() || !validateWebGLObject(program) || !validateWebGLObject(shader)) 1313 return; 1314 if (!program->detachShader(shader)) { 1315 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1316 return; 1317 } 1318 m_context->detachShader(objectOrZero(program), objectOrZero(shader)); 1319 shader->onDetached(); 1320 cleanupAfterGraphicsCall(false); 1321 } 1322 1323 void WebGLRenderingContext::disable(GC3Denum cap) 1324 { 1325 if (isContextLost() || !validateCapability(cap)) 1326 return; 1327 if (cap == GraphicsContext3D::SCISSOR_TEST) 1328 m_scissorEnabled = false; 1329 m_context->disable(cap); 1330 cleanupAfterGraphicsCall(false); 1331 } 1332 1333 void WebGLRenderingContext::disableVertexAttribArray(GC3Duint index, ExceptionCode& ec) 1334 { 1335 UNUSED_PARAM(ec); 1336 if (isContextLost()) 1337 return; 1338 if (index >= m_maxVertexAttribs) { 1339 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1340 return; 1341 } 1342 1343 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 1344 state.enabled = false; 1345 1346 if (index > 0 || isGLES2Compliant()) { 1347 m_context->disableVertexAttribArray(index); 1348 cleanupAfterGraphicsCall(false); 1349 } 1350 } 1351 1352 bool WebGLRenderingContext::validateElementArraySize(GC3Dsizei count, GC3Denum type, GC3Dintptr offset) 1353 { 1354 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); 1355 1356 if (!elementArrayBuffer) 1357 return false; 1358 1359 if (offset < 0) 1360 return false; 1361 1362 if (type == GraphicsContext3D::UNSIGNED_SHORT) { 1363 // For an unsigned short array, offset must be divisible by 2 for alignment reasons. 1364 if (offset % 2) 1365 return false; 1366 1367 // Make uoffset an element offset. 1368 offset /= 2; 1369 1370 GC3Dsizeiptr n = elementArrayBuffer->byteLength() / 2; 1371 if (offset > n || count > n - offset) 1372 return false; 1373 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) { 1374 GC3Dsizeiptr n = elementArrayBuffer->byteLength(); 1375 if (offset > n || count > n - offset) 1376 return false; 1377 } 1378 return true; 1379 } 1380 1381 bool WebGLRenderingContext::validateIndexArrayConservative(GC3Denum type, int& numElementsRequired) 1382 { 1383 // Performs conservative validation by caching a maximum index of 1384 // the given type per element array buffer. If all of the bound 1385 // array buffers have enough elements to satisfy that maximum 1386 // index, skips the expensive per-draw-call iteration in 1387 // validateIndexArrayPrecise. 1388 1389 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); 1390 1391 if (!elementArrayBuffer) 1392 return false; 1393 1394 GC3Dsizeiptr numElements = elementArrayBuffer->byteLength(); 1395 // The case count==0 is already dealt with in drawElements before validateIndexArrayConservative. 1396 if (!numElements) 1397 return false; 1398 const ArrayBuffer* buffer = elementArrayBuffer->elementArrayBuffer(); 1399 ASSERT(buffer); 1400 1401 int maxIndex = elementArrayBuffer->getCachedMaxIndex(type); 1402 if (maxIndex < 0) { 1403 // Compute the maximum index in the entire buffer for the given type of index. 1404 switch (type) { 1405 case GraphicsContext3D::UNSIGNED_BYTE: { 1406 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(buffer->data()); 1407 for (GC3Dsizeiptr i = 0; i < numElements; i++) 1408 maxIndex = max(maxIndex, static_cast<int>(p[i])); 1409 break; 1410 } 1411 case GraphicsContext3D::UNSIGNED_SHORT: { 1412 numElements /= sizeof(GC3Dushort); 1413 const GC3Dushort* p = static_cast<const GC3Dushort*>(buffer->data()); 1414 for (GC3Dsizeiptr i = 0; i < numElements; i++) 1415 maxIndex = max(maxIndex, static_cast<int>(p[i])); 1416 break; 1417 } 1418 default: 1419 return false; 1420 } 1421 elementArrayBuffer->setCachedMaxIndex(type, maxIndex); 1422 } 1423 1424 if (maxIndex >= 0) { 1425 // The number of required elements is one more than the maximum 1426 // index that will be accessed. 1427 numElementsRequired = maxIndex + 1; 1428 return true; 1429 } 1430 1431 return false; 1432 } 1433 1434 bool WebGLRenderingContext::validateIndexArrayPrecise(GC3Dsizei count, GC3Denum type, GC3Dintptr offset, int& numElementsRequired) 1435 { 1436 ASSERT(count >= 0 && offset >= 0); 1437 int lastIndex = -1; 1438 1439 RefPtr<WebGLBuffer> elementArrayBuffer = m_boundVertexArrayObject->getElementArrayBuffer(); 1440 1441 if (!elementArrayBuffer) 1442 return false; 1443 1444 if (!count) { 1445 numElementsRequired = 0; 1446 return true; 1447 } 1448 1449 if (!elementArrayBuffer->elementArrayBuffer()) 1450 return false; 1451 1452 unsigned long uoffset = offset; 1453 unsigned long n = count; 1454 1455 if (type == GraphicsContext3D::UNSIGNED_SHORT) { 1456 // Make uoffset an element offset. 1457 uoffset /= sizeof(GC3Dushort); 1458 const GC3Dushort* p = static_cast<const GC3Dushort*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset; 1459 while (n-- > 0) { 1460 if (*p > lastIndex) 1461 lastIndex = *p; 1462 ++p; 1463 } 1464 } else if (type == GraphicsContext3D::UNSIGNED_BYTE) { 1465 const GC3Dubyte* p = static_cast<const GC3Dubyte*>(elementArrayBuffer->elementArrayBuffer()->data()) + uoffset; 1466 while (n-- > 0) { 1467 if (*p > lastIndex) 1468 lastIndex = *p; 1469 ++p; 1470 } 1471 } 1472 1473 // Then set the last index in the index array and make sure it is valid. 1474 numElementsRequired = lastIndex + 1; 1475 return numElementsRequired > 0; 1476 } 1477 1478 bool WebGLRenderingContext::validateRenderingState(int numElementsRequired) 1479 { 1480 if (!m_currentProgram) 1481 return false; 1482 1483 // Look in each enabled vertex attrib and check if they've been bound to a buffer. 1484 for (unsigned i = 0; i < m_maxVertexAttribs; ++i) { 1485 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(i); 1486 if (state.enabled 1487 && (!state.bufferBinding || !state.bufferBinding->object())) 1488 return false; 1489 } 1490 1491 if (numElementsRequired <= 0) 1492 return true; 1493 1494 // Look in each consumed vertex attrib (by the current program) and find the smallest buffer size 1495 int smallestNumElements = INT_MAX; 1496 int numActiveAttribLocations = m_currentProgram->numActiveAttribLocations(); 1497 for (int i = 0; i < numActiveAttribLocations; ++i) { 1498 int loc = m_currentProgram->getActiveAttribLocation(i); 1499 if (loc >= 0 && loc < static_cast<int>(m_maxVertexAttribs)) { 1500 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(loc); 1501 if (state.enabled) { 1502 // Avoid off-by-one errors in numElements computation. 1503 // For the last element, we will only touch the data for the 1504 // element and nothing beyond it. 1505 int bytesRemaining = static_cast<int>(state.bufferBinding->byteLength() - state.offset); 1506 int numElements = 0; 1507 ASSERT(state.stride > 0); 1508 if (bytesRemaining >= state.bytesPerElement) 1509 numElements = 1 + (bytesRemaining - state.bytesPerElement) / state.stride; 1510 if (numElements < smallestNumElements) 1511 smallestNumElements = numElements; 1512 } 1513 } 1514 } 1515 1516 if (smallestNumElements == INT_MAX) 1517 smallestNumElements = 0; 1518 1519 return numElementsRequired <= smallestNumElements; 1520 } 1521 1522 bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object) 1523 { 1524 if (!object || !object->object()) { 1525 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1526 return false; 1527 } 1528 if (object->context() != this) { 1529 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1530 return false; 1531 } 1532 return true; 1533 } 1534 1535 void WebGLRenderingContext::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count, ExceptionCode& ec) 1536 { 1537 UNUSED_PARAM(ec); 1538 1539 if (isContextLost() || !validateDrawMode(mode)) 1540 return; 1541 1542 if (!validateStencilSettings()) 1543 return; 1544 1545 if (first < 0 || count < 0) { 1546 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1547 return; 1548 } 1549 1550 if (!count) 1551 return; 1552 1553 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 1554 // Ensure we have a valid rendering state 1555 CheckedInt<GC3Dint> checkedFirst(first); 1556 CheckedInt<GC3Dint> checkedCount(count); 1557 CheckedInt<GC3Dint> checkedSum = checkedFirst + checkedCount; 1558 if (!checkedSum.valid() || !validateRenderingState(checkedSum.value())) { 1559 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1560 return; 1561 } 1562 } else { 1563 if (!validateRenderingState(0)) { 1564 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1565 return; 1566 } 1567 } 1568 1569 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 1570 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 1571 return; 1572 } 1573 1574 clearIfComposited(); 1575 1576 bool vertexAttrib0Simulated = false; 1577 if (!isGLES2Compliant()) 1578 vertexAttrib0Simulated = simulateVertexAttrib0(first + count - 1); 1579 if (!isGLES2NPOTStrict()) 1580 handleNPOTTextures(true); 1581 m_context->drawArrays(mode, first, count); 1582 if (!isGLES2Compliant() && vertexAttrib0Simulated) 1583 restoreStatesAfterVertexAttrib0Simulation(); 1584 if (!isGLES2NPOTStrict()) 1585 handleNPOTTextures(false); 1586 cleanupAfterGraphicsCall(true); 1587 } 1588 1589 void WebGLRenderingContext::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset, ExceptionCode& ec) 1590 { 1591 UNUSED_PARAM(ec); 1592 1593 if (isContextLost() || !validateDrawMode(mode)) 1594 return; 1595 1596 if (!validateStencilSettings()) 1597 return; 1598 1599 switch (type) { 1600 case GraphicsContext3D::UNSIGNED_BYTE: 1601 case GraphicsContext3D::UNSIGNED_SHORT: 1602 break; 1603 default: 1604 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1605 return; 1606 } 1607 1608 if (count < 0 || offset < 0) { 1609 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1610 return; 1611 } 1612 1613 if (!count) 1614 return; 1615 1616 if (!m_boundVertexArrayObject->getElementArrayBuffer()) { 1617 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1618 return; 1619 } 1620 1621 int numElements = 0; 1622 if (!isErrorGeneratedOnOutOfBoundsAccesses()) { 1623 // Ensure we have a valid rendering state 1624 if (!validateElementArraySize(count, type, offset)) { 1625 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1626 return; 1627 } 1628 if (!count) 1629 return; 1630 if (!validateIndexArrayConservative(type, numElements) || !validateRenderingState(numElements)) { 1631 if (!validateIndexArrayPrecise(count, type, offset, numElements) || !validateRenderingState(numElements)) { 1632 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1633 return; 1634 } 1635 } 1636 } else { 1637 if (!validateRenderingState(0)) { 1638 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1639 return; 1640 } 1641 } 1642 1643 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 1644 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 1645 return; 1646 } 1647 clearIfComposited(); 1648 1649 bool vertexAttrib0Simulated = false; 1650 if (!isGLES2Compliant()) { 1651 if (!numElements) 1652 validateIndexArrayPrecise(count, type, offset, numElements); 1653 vertexAttrib0Simulated = simulateVertexAttrib0(numElements); 1654 } 1655 if (!isGLES2NPOTStrict()) 1656 handleNPOTTextures(true); 1657 m_context->drawElements(mode, count, type, offset); 1658 if (!isGLES2Compliant() && vertexAttrib0Simulated) 1659 restoreStatesAfterVertexAttrib0Simulation(); 1660 if (!isGLES2NPOTStrict()) 1661 handleNPOTTextures(false); 1662 cleanupAfterGraphicsCall(true); 1663 } 1664 1665 void WebGLRenderingContext::enable(GC3Denum cap) 1666 { 1667 if (isContextLost() || !validateCapability(cap)) 1668 return; 1669 if (cap == GraphicsContext3D::SCISSOR_TEST) 1670 m_scissorEnabled = true; 1671 m_context->enable(cap); 1672 cleanupAfterGraphicsCall(false); 1673 } 1674 1675 void WebGLRenderingContext::enableVertexAttribArray(GC3Duint index, ExceptionCode& ec) 1676 { 1677 UNUSED_PARAM(ec); 1678 if (isContextLost()) 1679 return; 1680 if (index >= m_maxVertexAttribs) { 1681 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1682 return; 1683 } 1684 1685 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 1686 state.enabled = true; 1687 1688 m_context->enableVertexAttribArray(index); 1689 cleanupAfterGraphicsCall(false); 1690 } 1691 1692 void WebGLRenderingContext::finish() 1693 { 1694 if (isContextLost()) 1695 return; 1696 m_context->finish(); 1697 cleanupAfterGraphicsCall(false); 1698 } 1699 1700 void WebGLRenderingContext::flush() 1701 { 1702 if (isContextLost()) 1703 return; 1704 m_context->flush(); 1705 cleanupAfterGraphicsCall(false); 1706 } 1707 1708 void WebGLRenderingContext::framebufferRenderbuffer(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, WebGLRenderbuffer* buffer, ExceptionCode& ec) 1709 { 1710 UNUSED_PARAM(ec); 1711 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) 1712 return; 1713 if (renderbuffertarget != GraphicsContext3D::RENDERBUFFER) { 1714 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1715 return; 1716 } 1717 if (buffer && buffer->context() != this) { 1718 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1719 return; 1720 } 1721 // Don't allow the default framebuffer to be mutated; all current 1722 // implementations use an FBO internally in place of the default 1723 // FBO. 1724 if (!m_framebufferBinding || !m_framebufferBinding->object()) { 1725 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1726 return; 1727 } 1728 Platform3DObject bufferObject = objectOrZero(buffer); 1729 bool reattachDepth = false; 1730 bool reattachStencil = false; 1731 bool reattachDepthStencilDepth = false; 1732 bool reattachDepthStencilStencil = false; 1733 switch (attachment) { 1734 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: 1735 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, bufferObject); 1736 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, bufferObject); 1737 if (!bufferObject) { 1738 reattachDepth = true; 1739 reattachStencil = true; 1740 } 1741 break; 1742 case GraphicsContext3D::DEPTH_ATTACHMENT: 1743 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); 1744 if (!bufferObject) 1745 reattachDepthStencilDepth = true; 1746 break; 1747 case GraphicsContext3D::STENCIL_ATTACHMENT: 1748 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); 1749 if (!bufferObject) 1750 reattachDepthStencilStencil = true; 1751 break; 1752 default: 1753 m_context->framebufferRenderbuffer(target, attachment, renderbuffertarget, objectOrZero(buffer)); 1754 } 1755 m_framebufferBinding->setAttachment(attachment, buffer); 1756 if (reattachDepth) { 1757 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_ATTACHMENT)); 1758 if (object) 1759 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object); 1760 } 1761 if (reattachStencil) { 1762 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT)); 1763 if (object) 1764 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object); 1765 } 1766 if (reattachDepthStencilDepth) { 1767 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT)); 1768 if (object) 1769 m_context->framebufferRenderbuffer(target, GraphicsContext3D::DEPTH_ATTACHMENT, renderbuffertarget, object); 1770 } 1771 if (reattachDepthStencilStencil) { 1772 Platform3DObject object = objectOrZero(m_framebufferBinding->getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT)); 1773 if (object) 1774 m_context->framebufferRenderbuffer(target, GraphicsContext3D::STENCIL_ATTACHMENT, renderbuffertarget, object); 1775 } 1776 cleanupAfterGraphicsCall(false); 1777 } 1778 1779 void WebGLRenderingContext::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, WebGLTexture* texture, GC3Dint level, ExceptionCode& ec) 1780 { 1781 UNUSED_PARAM(ec); 1782 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) 1783 return; 1784 if (level) { 1785 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 1786 return; 1787 } 1788 if (texture && texture->context() != this) { 1789 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1790 return; 1791 } 1792 // Don't allow the default framebuffer to be mutated; all current 1793 // implementations use an FBO internally in place of the default 1794 // FBO. 1795 if (!m_framebufferBinding || !m_framebufferBinding->object()) { 1796 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1797 return; 1798 } 1799 m_context->framebufferTexture2D(target, attachment, textarget, objectOrZero(texture), level); 1800 m_framebufferBinding->setAttachment(attachment, textarget, texture, level); 1801 cleanupAfterGraphicsCall(false); 1802 } 1803 1804 void WebGLRenderingContext::frontFace(GC3Denum mode) 1805 { 1806 if (isContextLost()) 1807 return; 1808 m_context->frontFace(mode); 1809 cleanupAfterGraphicsCall(false); 1810 } 1811 1812 void WebGLRenderingContext::generateMipmap(GC3Denum target) 1813 { 1814 if (isContextLost()) 1815 return; 1816 WebGLTexture* tex = validateTextureBinding(target, false); 1817 if (!tex) 1818 return; 1819 if (!tex->canGenerateMipmaps()) { 1820 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1821 return; 1822 } 1823 // generateMipmap won't work properly if minFilter is not NEAREST_MIPMAP_LINEAR 1824 // on Mac. Remove the hack once this driver bug is fixed. 1825 #if OS(DARWIN) 1826 bool needToResetMinFilter = false; 1827 if (tex->getMinFilter() != GraphicsContext3D::NEAREST_MIPMAP_LINEAR) { 1828 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::NEAREST_MIPMAP_LINEAR); 1829 needToResetMinFilter = true; 1830 } 1831 #endif 1832 m_context->generateMipmap(target); 1833 #if OS(DARWIN) 1834 if (needToResetMinFilter) 1835 m_context->texParameteri(target, GraphicsContext3D::TEXTURE_MIN_FILTER, tex->getMinFilter()); 1836 #endif 1837 tex->generateMipmapLevelInfo(); 1838 cleanupAfterGraphicsCall(false); 1839 } 1840 1841 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveAttrib(WebGLProgram* program, GC3Duint index, ExceptionCode& ec) 1842 { 1843 UNUSED_PARAM(ec); 1844 if (isContextLost() || !validateWebGLObject(program)) 1845 return 0; 1846 ActiveInfo info; 1847 if (!m_context->getActiveAttrib(objectOrZero(program), index, info)) 1848 return 0; 1849 return WebGLActiveInfo::create(info.name, info.type, info.size); 1850 } 1851 1852 PassRefPtr<WebGLActiveInfo> WebGLRenderingContext::getActiveUniform(WebGLProgram* program, GC3Duint index, ExceptionCode& ec) 1853 { 1854 UNUSED_PARAM(ec); 1855 if (isContextLost() || !validateWebGLObject(program)) 1856 return 0; 1857 ActiveInfo info; 1858 if (!m_context->getActiveUniform(objectOrZero(program), index, info)) 1859 return 0; 1860 if (!isGLES2Compliant()) 1861 if (info.size > 1 && !info.name.endsWith("[0]")) 1862 info.name.append("[0]"); 1863 return WebGLActiveInfo::create(info.name, info.type, info.size); 1864 } 1865 1866 bool WebGLRenderingContext::getAttachedShaders(WebGLProgram* program, Vector<WebGLShader*>& shaderObjects, ExceptionCode& ec) 1867 { 1868 UNUSED_PARAM(ec); 1869 shaderObjects.clear(); 1870 if (isContextLost() || !validateWebGLObject(program)) 1871 return false; 1872 GC3Dint numShaders = 0; 1873 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ATTACHED_SHADERS, &numShaders); 1874 if (numShaders) { 1875 OwnArrayPtr<Platform3DObject> shaders = adoptArrayPtr(new Platform3DObject[numShaders]); 1876 GC3Dsizei count = 0; 1877 m_context->getAttachedShaders(objectOrZero(program), numShaders, &count, shaders.get()); 1878 if (count != numShaders) 1879 return false; 1880 shaderObjects.resize(numShaders); 1881 for (GC3Dint ii = 0; ii < numShaders; ++ii) { 1882 WebGLShader* shader = findShader(shaders[ii]); 1883 if (!shader) { 1884 shaderObjects.clear(); 1885 return false; 1886 } 1887 shaderObjects[ii] = shader; 1888 } 1889 } 1890 return true; 1891 } 1892 1893 GC3Dint WebGLRenderingContext::getAttribLocation(WebGLProgram* program, const String& name) 1894 { 1895 if (isContextLost()) 1896 return -1; 1897 if (!validateString(name)) 1898 return -1; 1899 return m_context->getAttribLocation(objectOrZero(program), name); 1900 } 1901 1902 WebGLGetInfo WebGLRenderingContext::getBufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec) 1903 { 1904 UNUSED_PARAM(ec); 1905 if (isContextLost()) 1906 return WebGLGetInfo(); 1907 if (target != GraphicsContext3D::ARRAY_BUFFER && target != GraphicsContext3D::ELEMENT_ARRAY_BUFFER) { 1908 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1909 return WebGLGetInfo(); 1910 } 1911 1912 if (pname != GraphicsContext3D::BUFFER_SIZE && pname != GraphicsContext3D::BUFFER_USAGE) { 1913 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1914 return WebGLGetInfo(); 1915 } 1916 1917 WebGLStateRestorer(this, false); 1918 GC3Dint value = 0; 1919 m_context->getBufferParameteriv(target, pname, &value); 1920 if (pname == GraphicsContext3D::BUFFER_SIZE) 1921 return WebGLGetInfo(value); 1922 return WebGLGetInfo(static_cast<unsigned int>(value)); 1923 } 1924 1925 PassRefPtr<WebGLContextAttributes> WebGLRenderingContext::getContextAttributes() 1926 { 1927 if (isContextLost()) 1928 return 0; 1929 // We always need to return a new WebGLContextAttributes object to 1930 // prevent the user from mutating any cached version. 1931 return WebGLContextAttributes::create(m_context->getContextAttributes()); 1932 } 1933 1934 GC3Denum WebGLRenderingContext::getError() 1935 { 1936 return m_context->getError(); 1937 } 1938 1939 WebGLExtension* WebGLRenderingContext::getExtension(const String& name) 1940 { 1941 if (isContextLost()) 1942 return 0; 1943 1944 if (equalIgnoringCase(name, "OES_standard_derivatives") 1945 && m_context->getExtensions()->supports("GL_OES_standard_derivatives")) { 1946 if (!m_oesStandardDerivatives) { 1947 m_context->getExtensions()->ensureEnabled("GL_OES_standard_derivatives"); 1948 m_oesStandardDerivatives = OESStandardDerivatives::create(); 1949 } 1950 return m_oesStandardDerivatives.get(); 1951 } 1952 if (equalIgnoringCase(name, "OES_texture_float") 1953 && m_context->getExtensions()->supports("GL_OES_texture_float")) { 1954 if (!m_oesTextureFloat) { 1955 m_context->getExtensions()->ensureEnabled("GL_OES_texture_float"); 1956 m_oesTextureFloat = OESTextureFloat::create(); 1957 } 1958 return m_oesTextureFloat.get(); 1959 } 1960 if (equalIgnoringCase(name, "OES_vertex_array_object") 1961 && m_context->getExtensions()->supports("GL_OES_vertex_array_object")) { 1962 if (!m_oesVertexArrayObject) { 1963 m_context->getExtensions()->ensureEnabled("GL_OES_vertex_array_object"); 1964 m_oesVertexArrayObject = OESVertexArrayObject::create(this); 1965 } 1966 return m_oesVertexArrayObject.get(); 1967 } 1968 if (equalIgnoringCase(name, "WEBKIT_lose_context")) { 1969 if (!m_webkitLoseContext) 1970 m_webkitLoseContext = WebKitLoseContext::create(this); 1971 return m_webkitLoseContext.get(); 1972 } 1973 1974 return 0; 1975 } 1976 1977 WebGLGetInfo WebGLRenderingContext::getFramebufferAttachmentParameter(GC3Denum target, GC3Denum attachment, GC3Denum pname, ExceptionCode& ec) 1978 { 1979 UNUSED_PARAM(ec); 1980 if (isContextLost() || !validateFramebufferFuncParameters(target, attachment)) 1981 return WebGLGetInfo(); 1982 switch (pname) { 1983 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: 1984 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: 1985 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL: 1986 case GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: 1987 break; 1988 default: 1989 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 1990 return WebGLGetInfo(); 1991 } 1992 1993 if (!m_framebufferBinding || !m_framebufferBinding->object() || m_framebufferBinding->isIncomplete(false)) { 1994 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 1995 return WebGLGetInfo(); 1996 } 1997 1998 if (pname != GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) { 1999 WebGLStateRestorer(this, false); 2000 GC3Dint value = 0; 2001 m_context->getFramebufferAttachmentParameteriv(target, attachment, pname, &value); 2002 if (pname == GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) 2003 return WebGLGetInfo(static_cast<unsigned int>(value)); 2004 return WebGLGetInfo(value); 2005 } 2006 2007 WebGLStateRestorer(this, false); 2008 GC3Dint type = 0; 2009 m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type); 2010 if (!type) 2011 return WebGLGetInfo(); 2012 GC3Dint value = 0; 2013 m_context->getFramebufferAttachmentParameteriv(target, attachment, GraphicsContext3D::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &value); 2014 switch (type) { 2015 case GraphicsContext3D::RENDERBUFFER: 2016 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(findRenderbuffer(static_cast<Platform3DObject>(value)))); 2017 case GraphicsContext3D::TEXTURE: 2018 return WebGLGetInfo(PassRefPtr<WebGLTexture>(findTexture(static_cast<Platform3DObject>(value)))); 2019 default: 2020 // FIXME: raise exception? 2021 return WebGLGetInfo(); 2022 } 2023 } 2024 2025 WebGLGetInfo WebGLRenderingContext::getParameter(GC3Denum pname, ExceptionCode& ec) 2026 { 2027 UNUSED_PARAM(ec); 2028 if (isContextLost()) 2029 return WebGLGetInfo(); 2030 WebGLStateRestorer(this, false); 2031 switch (pname) { 2032 case GraphicsContext3D::ACTIVE_TEXTURE: 2033 return getUnsignedIntParameter(pname); 2034 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE: 2035 return getWebGLFloatArrayParameter(pname); 2036 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE: 2037 return getWebGLFloatArrayParameter(pname); 2038 case GraphicsContext3D::ALPHA_BITS: 2039 return getIntParameter(pname); 2040 case GraphicsContext3D::ARRAY_BUFFER_BINDING: 2041 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundArrayBuffer)); 2042 case GraphicsContext3D::BLEND: 2043 return getBooleanParameter(pname); 2044 case GraphicsContext3D::BLEND_COLOR: 2045 return getWebGLFloatArrayParameter(pname); 2046 case GraphicsContext3D::BLEND_DST_ALPHA: 2047 return getUnsignedIntParameter(pname); 2048 case GraphicsContext3D::BLEND_DST_RGB: 2049 return getUnsignedIntParameter(pname); 2050 case GraphicsContext3D::BLEND_EQUATION_ALPHA: 2051 return getUnsignedIntParameter(pname); 2052 case GraphicsContext3D::BLEND_EQUATION_RGB: 2053 return getUnsignedIntParameter(pname); 2054 case GraphicsContext3D::BLEND_SRC_ALPHA: 2055 return getUnsignedIntParameter(pname); 2056 case GraphicsContext3D::BLEND_SRC_RGB: 2057 return getUnsignedIntParameter(pname); 2058 case GraphicsContext3D::BLUE_BITS: 2059 return getIntParameter(pname); 2060 case GraphicsContext3D::COLOR_CLEAR_VALUE: 2061 return getWebGLFloatArrayParameter(pname); 2062 case GraphicsContext3D::COLOR_WRITEMASK: 2063 return getBooleanArrayParameter(pname); 2064 case GraphicsContext3D::COMPRESSED_TEXTURE_FORMATS: 2065 // Defined as null in the spec 2066 return WebGLGetInfo(); 2067 case GraphicsContext3D::CULL_FACE: 2068 return getBooleanParameter(pname); 2069 case GraphicsContext3D::CULL_FACE_MODE: 2070 return getUnsignedIntParameter(pname); 2071 case GraphicsContext3D::CURRENT_PROGRAM: 2072 return WebGLGetInfo(PassRefPtr<WebGLProgram>(m_currentProgram)); 2073 case GraphicsContext3D::DEPTH_BITS: 2074 return getIntParameter(pname); 2075 case GraphicsContext3D::DEPTH_CLEAR_VALUE: 2076 return getFloatParameter(pname); 2077 case GraphicsContext3D::DEPTH_FUNC: 2078 return getUnsignedIntParameter(pname); 2079 case GraphicsContext3D::DEPTH_RANGE: 2080 return getWebGLFloatArrayParameter(pname); 2081 case GraphicsContext3D::DEPTH_TEST: 2082 return getBooleanParameter(pname); 2083 case GraphicsContext3D::DEPTH_WRITEMASK: 2084 return getBooleanParameter(pname); 2085 case GraphicsContext3D::DITHER: 2086 return getBooleanParameter(pname); 2087 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER_BINDING: 2088 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(m_boundVertexArrayObject->getElementArrayBuffer())); 2089 case GraphicsContext3D::FRAMEBUFFER_BINDING: 2090 return WebGLGetInfo(PassRefPtr<WebGLFramebuffer>(m_framebufferBinding)); 2091 case GraphicsContext3D::FRONT_FACE: 2092 return getUnsignedIntParameter(pname); 2093 case GraphicsContext3D::GENERATE_MIPMAP_HINT: 2094 return getUnsignedIntParameter(pname); 2095 case GraphicsContext3D::GREEN_BITS: 2096 return getIntParameter(pname); 2097 case GraphicsContext3D::LINE_WIDTH: 2098 return getFloatParameter(pname); 2099 case GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS: 2100 return getIntParameter(pname); 2101 case GraphicsContext3D::MAX_CUBE_MAP_TEXTURE_SIZE: 2102 return getIntParameter(pname); 2103 case GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS: 2104 return getIntParameter(pname); 2105 case GraphicsContext3D::MAX_RENDERBUFFER_SIZE: 2106 return getIntParameter(pname); 2107 case GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS: 2108 return getIntParameter(pname); 2109 case GraphicsContext3D::MAX_TEXTURE_SIZE: 2110 return getIntParameter(pname); 2111 case GraphicsContext3D::MAX_VARYING_VECTORS: 2112 return getIntParameter(pname); 2113 case GraphicsContext3D::MAX_VERTEX_ATTRIBS: 2114 return getIntParameter(pname); 2115 case GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS: 2116 return getIntParameter(pname); 2117 case GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS: 2118 return getIntParameter(pname); 2119 case GraphicsContext3D::MAX_VIEWPORT_DIMS: 2120 return getWebGLIntArrayParameter(pname); 2121 case GraphicsContext3D::NUM_COMPRESSED_TEXTURE_FORMATS: 2122 // WebGL 1.0 specifies that there are no compressed texture formats. 2123 return WebGLGetInfo(static_cast<int>(0)); 2124 case GraphicsContext3D::NUM_SHADER_BINARY_FORMATS: 2125 // FIXME: should we always return 0 for this? 2126 return getIntParameter(pname); 2127 case GraphicsContext3D::PACK_ALIGNMENT: 2128 return getIntParameter(pname); 2129 case GraphicsContext3D::POLYGON_OFFSET_FACTOR: 2130 return getFloatParameter(pname); 2131 case GraphicsContext3D::POLYGON_OFFSET_FILL: 2132 return getBooleanParameter(pname); 2133 case GraphicsContext3D::POLYGON_OFFSET_UNITS: 2134 return getFloatParameter(pname); 2135 case GraphicsContext3D::RED_BITS: 2136 return getIntParameter(pname); 2137 case GraphicsContext3D::RENDERBUFFER_BINDING: 2138 return WebGLGetInfo(PassRefPtr<WebGLRenderbuffer>(m_renderbufferBinding)); 2139 case GraphicsContext3D::RENDERER: 2140 return WebGLGetInfo(m_context->getString(GraphicsContext3D::RENDERER)); 2141 case GraphicsContext3D::SAMPLE_BUFFERS: 2142 return getIntParameter(pname); 2143 case GraphicsContext3D::SAMPLE_COVERAGE_INVERT: 2144 return getBooleanParameter(pname); 2145 case GraphicsContext3D::SAMPLE_COVERAGE_VALUE: 2146 return getFloatParameter(pname); 2147 case GraphicsContext3D::SAMPLES: 2148 return getIntParameter(pname); 2149 case GraphicsContext3D::SCISSOR_BOX: 2150 return getWebGLIntArrayParameter(pname); 2151 case GraphicsContext3D::SCISSOR_TEST: 2152 return getBooleanParameter(pname); 2153 case GraphicsContext3D::SHADING_LANGUAGE_VERSION: 2154 return WebGLGetInfo("WebGL GLSL ES 1.0 (" + m_context->getString(GraphicsContext3D::SHADING_LANGUAGE_VERSION) + ")"); 2155 case GraphicsContext3D::STENCIL_BACK_FAIL: 2156 return getUnsignedIntParameter(pname); 2157 case GraphicsContext3D::STENCIL_BACK_FUNC: 2158 return getUnsignedIntParameter(pname); 2159 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_FAIL: 2160 return getUnsignedIntParameter(pname); 2161 case GraphicsContext3D::STENCIL_BACK_PASS_DEPTH_PASS: 2162 return getUnsignedIntParameter(pname); 2163 case GraphicsContext3D::STENCIL_BACK_REF: 2164 return getIntParameter(pname); 2165 case GraphicsContext3D::STENCIL_BACK_VALUE_MASK: 2166 return getUnsignedIntParameter(pname); 2167 case GraphicsContext3D::STENCIL_BACK_WRITEMASK: 2168 return getUnsignedIntParameter(pname); 2169 case GraphicsContext3D::STENCIL_BITS: 2170 return getIntParameter(pname); 2171 case GraphicsContext3D::STENCIL_CLEAR_VALUE: 2172 return getIntParameter(pname); 2173 case GraphicsContext3D::STENCIL_FAIL: 2174 return getUnsignedIntParameter(pname); 2175 case GraphicsContext3D::STENCIL_FUNC: 2176 return getUnsignedIntParameter(pname); 2177 case GraphicsContext3D::STENCIL_PASS_DEPTH_FAIL: 2178 return getUnsignedIntParameter(pname); 2179 case GraphicsContext3D::STENCIL_PASS_DEPTH_PASS: 2180 return getUnsignedIntParameter(pname); 2181 case GraphicsContext3D::STENCIL_REF: 2182 return getIntParameter(pname); 2183 case GraphicsContext3D::STENCIL_TEST: 2184 return getBooleanParameter(pname); 2185 case GraphicsContext3D::STENCIL_VALUE_MASK: 2186 return getUnsignedIntParameter(pname); 2187 case GraphicsContext3D::STENCIL_WRITEMASK: 2188 return getUnsignedIntParameter(pname); 2189 case GraphicsContext3D::SUBPIXEL_BITS: 2190 return getIntParameter(pname); 2191 case GraphicsContext3D::TEXTURE_BINDING_2D: 2192 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_texture2DBinding)); 2193 case GraphicsContext3D::TEXTURE_BINDING_CUBE_MAP: 2194 return WebGLGetInfo(PassRefPtr<WebGLTexture>(m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding)); 2195 case GraphicsContext3D::UNPACK_ALIGNMENT: 2196 return getIntParameter(pname); 2197 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL: 2198 return WebGLGetInfo(m_unpackFlipY); 2199 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL: 2200 return WebGLGetInfo(m_unpackPremultiplyAlpha); 2201 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL: 2202 return WebGLGetInfo(m_unpackColorspaceConversion); 2203 case GraphicsContext3D::VENDOR: 2204 return WebGLGetInfo("Webkit (" + m_context->getString(GraphicsContext3D::VENDOR) + ")"); 2205 case GraphicsContext3D::VERSION: 2206 return WebGLGetInfo("WebGL 1.0 (" + m_context->getString(GraphicsContext3D::VERSION) + ")"); 2207 case GraphicsContext3D::VIEWPORT: 2208 return getWebGLIntArrayParameter(pname); 2209 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives 2210 if (m_oesStandardDerivatives) 2211 return getUnsignedIntParameter(Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES); 2212 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2213 return WebGLGetInfo(); 2214 case Extensions3D::VERTEX_ARRAY_BINDING_OES: // OES_vertex_array_object 2215 if (m_oesVertexArrayObject) { 2216 if (!m_boundVertexArrayObject->isDefaultObject()) 2217 return WebGLGetInfo(PassRefPtr<WebGLVertexArrayObjectOES>(m_boundVertexArrayObject)); 2218 return WebGLGetInfo(); 2219 } 2220 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2221 return WebGLGetInfo(); 2222 default: 2223 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2224 return WebGLGetInfo(); 2225 } 2226 } 2227 2228 WebGLGetInfo WebGLRenderingContext::getProgramParameter(WebGLProgram* program, GC3Denum pname, ExceptionCode& ec) 2229 { 2230 UNUSED_PARAM(ec); 2231 if (isContextLost() || !validateWebGLObject(program)) 2232 return WebGLGetInfo(); 2233 2234 WebGLStateRestorer(this, false); 2235 GC3Dint value = 0; 2236 switch (pname) { 2237 case GraphicsContext3D::DELETE_STATUS: 2238 return WebGLGetInfo(program->isDeleted()); 2239 case GraphicsContext3D::VALIDATE_STATUS: 2240 m_context->getProgramiv(objectOrZero(program), pname, &value); 2241 return WebGLGetInfo(static_cast<bool>(value)); 2242 case GraphicsContext3D::LINK_STATUS: 2243 return WebGLGetInfo(program->getLinkStatus()); 2244 case GraphicsContext3D::ATTACHED_SHADERS: 2245 case GraphicsContext3D::ACTIVE_ATTRIBUTES: 2246 case GraphicsContext3D::ACTIVE_UNIFORMS: 2247 m_context->getProgramiv(objectOrZero(program), pname, &value); 2248 return WebGLGetInfo(value); 2249 default: 2250 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2251 return WebGLGetInfo(); 2252 } 2253 } 2254 2255 String WebGLRenderingContext::getProgramInfoLog(WebGLProgram* program, ExceptionCode& ec) 2256 { 2257 UNUSED_PARAM(ec); 2258 if (isContextLost()) 2259 return String(); 2260 if (!validateWebGLObject(program)) 2261 return ""; 2262 WebGLStateRestorer(this, false); 2263 return m_context->getProgramInfoLog(objectOrZero(program)); 2264 } 2265 2266 WebGLGetInfo WebGLRenderingContext::getRenderbufferParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec) 2267 { 2268 UNUSED_PARAM(ec); 2269 if (isContextLost()) 2270 return WebGLGetInfo(); 2271 if (target != GraphicsContext3D::RENDERBUFFER) { 2272 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2273 return WebGLGetInfo(); 2274 } 2275 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { 2276 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2277 return WebGLGetInfo(); 2278 } 2279 2280 if (m_renderbufferBinding->getInternalFormat() == GraphicsContext3D::DEPTH_STENCIL 2281 && !m_renderbufferBinding->isValid()) { 2282 ASSERT(!isDepthStencilSupported()); 2283 int value = 0; 2284 switch (pname) { 2285 case GraphicsContext3D::RENDERBUFFER_WIDTH: 2286 value = m_renderbufferBinding->getWidth(); 2287 break; 2288 case GraphicsContext3D::RENDERBUFFER_HEIGHT: 2289 value = m_renderbufferBinding->getHeight(); 2290 break; 2291 case GraphicsContext3D::RENDERBUFFER_RED_SIZE: 2292 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE: 2293 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE: 2294 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE: 2295 value = 0; 2296 break; 2297 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE: 2298 value = 24; 2299 break; 2300 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE: 2301 value = 8; 2302 break; 2303 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT: 2304 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat()); 2305 default: 2306 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2307 return WebGLGetInfo(); 2308 } 2309 return WebGLGetInfo(value); 2310 } 2311 2312 WebGLStateRestorer(this, false); 2313 GC3Dint value = 0; 2314 switch (pname) { 2315 case GraphicsContext3D::RENDERBUFFER_WIDTH: 2316 case GraphicsContext3D::RENDERBUFFER_HEIGHT: 2317 case GraphicsContext3D::RENDERBUFFER_RED_SIZE: 2318 case GraphicsContext3D::RENDERBUFFER_GREEN_SIZE: 2319 case GraphicsContext3D::RENDERBUFFER_BLUE_SIZE: 2320 case GraphicsContext3D::RENDERBUFFER_ALPHA_SIZE: 2321 case GraphicsContext3D::RENDERBUFFER_DEPTH_SIZE: 2322 case GraphicsContext3D::RENDERBUFFER_STENCIL_SIZE: 2323 m_context->getRenderbufferParameteriv(target, pname, &value); 2324 return WebGLGetInfo(value); 2325 case GraphicsContext3D::RENDERBUFFER_INTERNAL_FORMAT: 2326 return WebGLGetInfo(m_renderbufferBinding->getInternalFormat()); 2327 default: 2328 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2329 return WebGLGetInfo(); 2330 } 2331 } 2332 2333 WebGLGetInfo WebGLRenderingContext::getShaderParameter(WebGLShader* shader, GC3Denum pname, ExceptionCode& ec) 2334 { 2335 UNUSED_PARAM(ec); 2336 if (isContextLost() || !validateWebGLObject(shader)) 2337 return WebGLGetInfo(); 2338 WebGLStateRestorer(this, false); 2339 GC3Dint value = 0; 2340 switch (pname) { 2341 case GraphicsContext3D::DELETE_STATUS: 2342 return WebGLGetInfo(shader->isDeleted()); 2343 case GraphicsContext3D::COMPILE_STATUS: 2344 m_context->getShaderiv(objectOrZero(shader), pname, &value); 2345 return WebGLGetInfo(static_cast<bool>(value)); 2346 case GraphicsContext3D::SHADER_TYPE: 2347 m_context->getShaderiv(objectOrZero(shader), pname, &value); 2348 return WebGLGetInfo(static_cast<unsigned int>(value)); 2349 default: 2350 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2351 return WebGLGetInfo(); 2352 } 2353 } 2354 2355 String WebGLRenderingContext::getShaderInfoLog(WebGLShader* shader, ExceptionCode& ec) 2356 { 2357 UNUSED_PARAM(ec); 2358 if (isContextLost()) 2359 return String(); 2360 if (!validateWebGLObject(shader)) 2361 return ""; 2362 WebGLStateRestorer(this, false); 2363 return m_context->getShaderInfoLog(objectOrZero(shader)); 2364 } 2365 2366 String WebGLRenderingContext::getShaderSource(WebGLShader* shader, ExceptionCode& ec) 2367 { 2368 UNUSED_PARAM(ec); 2369 if (isContextLost()) 2370 return String(); 2371 if (!validateWebGLObject(shader)) 2372 return ""; 2373 return shader->getSource(); 2374 } 2375 2376 Vector<String> WebGLRenderingContext::getSupportedExtensions() 2377 { 2378 Vector<String> result; 2379 if (m_context->getExtensions()->supports("GL_OES_texture_float")) 2380 result.append("OES_texture_float"); 2381 if (m_context->getExtensions()->supports("GL_OES_standard_derivatives")) 2382 result.append("OES_standard_derivatives"); 2383 if (m_context->getExtensions()->supports("GL_OES_vertex_array_object")) 2384 result.append("OES_vertex_array_object"); 2385 result.append("WEBKIT_lose_context"); 2386 return result; 2387 } 2388 2389 WebGLGetInfo WebGLRenderingContext::getTexParameter(GC3Denum target, GC3Denum pname, ExceptionCode& ec) 2390 { 2391 UNUSED_PARAM(ec); 2392 if (isContextLost()) 2393 return WebGLGetInfo(); 2394 WebGLTexture* tex = validateTextureBinding(target, false); 2395 if (!tex) 2396 return WebGLGetInfo(); 2397 WebGLStateRestorer(this, false); 2398 GC3Dint value = 0; 2399 switch (pname) { 2400 case GraphicsContext3D::TEXTURE_MAG_FILTER: 2401 case GraphicsContext3D::TEXTURE_MIN_FILTER: 2402 case GraphicsContext3D::TEXTURE_WRAP_S: 2403 case GraphicsContext3D::TEXTURE_WRAP_T: 2404 m_context->getTexParameteriv(target, pname, &value); 2405 return WebGLGetInfo(static_cast<unsigned int>(value)); 2406 default: 2407 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2408 return WebGLGetInfo(); 2409 } 2410 } 2411 2412 WebGLGetInfo WebGLRenderingContext::getUniform(WebGLProgram* program, const WebGLUniformLocation* uniformLocation, ExceptionCode& ec) 2413 { 2414 UNUSED_PARAM(ec); 2415 if (isContextLost() || !validateWebGLObject(program)) 2416 return WebGLGetInfo(); 2417 if (!uniformLocation || uniformLocation->program() != program) { 2418 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2419 return WebGLGetInfo(); 2420 } 2421 GC3Dint location = uniformLocation->location(); 2422 2423 WebGLStateRestorer(this, false); 2424 // FIXME: make this more efficient using WebGLUniformLocation and caching types in it 2425 GC3Dint activeUniforms = 0; 2426 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::ACTIVE_UNIFORMS, &activeUniforms); 2427 for (GC3Dint i = 0; i < activeUniforms; i++) { 2428 ActiveInfo info; 2429 if (!m_context->getActiveUniform(objectOrZero(program), i, info)) 2430 return WebGLGetInfo(); 2431 // Strip "[0]" from the name if it's an array. 2432 if (info.size > 1) 2433 info.name = info.name.left(info.name.length() - 3); 2434 // If it's an array, we need to iterate through each element, appending "[index]" to the name. 2435 for (GC3Dint index = 0; index < info.size; ++index) { 2436 String name = info.name; 2437 if (info.size > 1 && index >= 1) { 2438 name.append('['); 2439 name.append(String::number(index)); 2440 name.append(']'); 2441 } 2442 // Now need to look this up by name again to find its location 2443 GC3Dint loc = m_context->getUniformLocation(objectOrZero(program), name); 2444 if (loc == location) { 2445 // Found it. Use the type in the ActiveInfo to determine the return type. 2446 GC3Denum baseType; 2447 unsigned int length; 2448 switch (info.type) { 2449 case GraphicsContext3D::BOOL: 2450 baseType = GraphicsContext3D::BOOL; 2451 length = 1; 2452 break; 2453 case GraphicsContext3D::BOOL_VEC2: 2454 baseType = GraphicsContext3D::BOOL; 2455 length = 2; 2456 break; 2457 case GraphicsContext3D::BOOL_VEC3: 2458 baseType = GraphicsContext3D::BOOL; 2459 length = 3; 2460 break; 2461 case GraphicsContext3D::BOOL_VEC4: 2462 baseType = GraphicsContext3D::BOOL; 2463 length = 4; 2464 break; 2465 case GraphicsContext3D::INT: 2466 baseType = GraphicsContext3D::INT; 2467 length = 1; 2468 break; 2469 case GraphicsContext3D::INT_VEC2: 2470 baseType = GraphicsContext3D::INT; 2471 length = 2; 2472 break; 2473 case GraphicsContext3D::INT_VEC3: 2474 baseType = GraphicsContext3D::INT; 2475 length = 3; 2476 break; 2477 case GraphicsContext3D::INT_VEC4: 2478 baseType = GraphicsContext3D::INT; 2479 length = 4; 2480 break; 2481 case GraphicsContext3D::FLOAT: 2482 baseType = GraphicsContext3D::FLOAT; 2483 length = 1; 2484 break; 2485 case GraphicsContext3D::FLOAT_VEC2: 2486 baseType = GraphicsContext3D::FLOAT; 2487 length = 2; 2488 break; 2489 case GraphicsContext3D::FLOAT_VEC3: 2490 baseType = GraphicsContext3D::FLOAT; 2491 length = 3; 2492 break; 2493 case GraphicsContext3D::FLOAT_VEC4: 2494 baseType = GraphicsContext3D::FLOAT; 2495 length = 4; 2496 break; 2497 case GraphicsContext3D::FLOAT_MAT2: 2498 baseType = GraphicsContext3D::FLOAT; 2499 length = 4; 2500 break; 2501 case GraphicsContext3D::FLOAT_MAT3: 2502 baseType = GraphicsContext3D::FLOAT; 2503 length = 9; 2504 break; 2505 case GraphicsContext3D::FLOAT_MAT4: 2506 baseType = GraphicsContext3D::FLOAT; 2507 length = 16; 2508 break; 2509 case GraphicsContext3D::SAMPLER_2D: 2510 case GraphicsContext3D::SAMPLER_CUBE: 2511 baseType = GraphicsContext3D::INT; 2512 length = 1; 2513 break; 2514 default: 2515 // Can't handle this type 2516 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2517 return WebGLGetInfo(); 2518 } 2519 switch (baseType) { 2520 case GraphicsContext3D::FLOAT: { 2521 GC3Dfloat value[16] = {0}; 2522 m_context->getUniformfv(objectOrZero(program), location, value); 2523 if (length == 1) 2524 return WebGLGetInfo(value[0]); 2525 return WebGLGetInfo(Float32Array::create(value, length)); 2526 } 2527 case GraphicsContext3D::INT: { 2528 GC3Dint value[4] = {0}; 2529 m_context->getUniformiv(objectOrZero(program), location, value); 2530 if (length == 1) 2531 return WebGLGetInfo(value[0]); 2532 return WebGLGetInfo(Int32Array::create(value, length)); 2533 } 2534 case GraphicsContext3D::BOOL: { 2535 GC3Dint value[4] = {0}; 2536 m_context->getUniformiv(objectOrZero(program), location, value); 2537 if (length > 1) { 2538 bool boolValue[16] = {0}; 2539 for (unsigned j = 0; j < length; j++) 2540 boolValue[j] = static_cast<bool>(value[j]); 2541 return WebGLGetInfo(boolValue, length); 2542 } 2543 return WebGLGetInfo(static_cast<bool>(value[0])); 2544 } 2545 default: 2546 notImplemented(); 2547 } 2548 } 2549 } 2550 } 2551 // If we get here, something went wrong in our unfortunately complex logic above 2552 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2553 return WebGLGetInfo(); 2554 } 2555 2556 PassRefPtr<WebGLUniformLocation> WebGLRenderingContext::getUniformLocation(WebGLProgram* program, const String& name, ExceptionCode& ec) 2557 { 2558 UNUSED_PARAM(ec); 2559 if (isContextLost() || !validateWebGLObject(program)) 2560 return 0; 2561 if (!validateString(name)) 2562 return 0; 2563 WebGLStateRestorer(this, false); 2564 GC3Dint uniformLocation = m_context->getUniformLocation(objectOrZero(program), name); 2565 if (uniformLocation == -1) 2566 return 0; 2567 return WebGLUniformLocation::create(program, uniformLocation); 2568 } 2569 2570 WebGLGetInfo WebGLRenderingContext::getVertexAttrib(GC3Duint index, GC3Denum pname, ExceptionCode& ec) 2571 { 2572 UNUSED_PARAM(ec); 2573 if (isContextLost()) 2574 return WebGLGetInfo(); 2575 WebGLStateRestorer(this, false); 2576 if (index >= m_maxVertexAttribs) { 2577 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2578 return WebGLGetInfo(); 2579 } 2580 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 2581 switch (pname) { 2582 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: 2583 if ((!isGLES2Compliant() && !index && m_boundVertexArrayObject->getVertexAttribState(0).bufferBinding == m_vertexAttrib0Buffer) 2584 || !state.bufferBinding 2585 || !state.bufferBinding->object()) 2586 return WebGLGetInfo(); 2587 return WebGLGetInfo(PassRefPtr<WebGLBuffer>(state.bufferBinding)); 2588 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_ENABLED: 2589 return WebGLGetInfo(state.enabled); 2590 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_NORMALIZED: 2591 return WebGLGetInfo(state.normalized); 2592 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_SIZE: 2593 return WebGLGetInfo(state.size); 2594 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_STRIDE: 2595 return WebGLGetInfo(state.originalStride); 2596 case GraphicsContext3D::VERTEX_ATTRIB_ARRAY_TYPE: 2597 return WebGLGetInfo(state.type); 2598 case GraphicsContext3D::CURRENT_VERTEX_ATTRIB: 2599 return WebGLGetInfo(Float32Array::create(m_vertexAttribValue[index].value, 4)); 2600 default: 2601 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2602 return WebGLGetInfo(); 2603 } 2604 } 2605 2606 GC3Dsizeiptr WebGLRenderingContext::getVertexAttribOffset(GC3Duint index, GC3Denum pname) 2607 { 2608 if (isContextLost()) 2609 return 0; 2610 GC3Dsizeiptr result = m_context->getVertexAttribOffset(index, pname); 2611 cleanupAfterGraphicsCall(false); 2612 return result; 2613 } 2614 2615 void WebGLRenderingContext::hint(GC3Denum target, GC3Denum mode) 2616 { 2617 if (isContextLost()) 2618 return; 2619 bool isValid = false; 2620 switch (target) { 2621 case GraphicsContext3D::GENERATE_MIPMAP_HINT: 2622 isValid = true; 2623 break; 2624 case Extensions3D::FRAGMENT_SHADER_DERIVATIVE_HINT_OES: // OES_standard_derivatives 2625 if (m_oesStandardDerivatives) 2626 isValid = true; 2627 break; 2628 } 2629 if (!isValid) { 2630 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2631 return; 2632 } 2633 m_context->hint(target, mode); 2634 cleanupAfterGraphicsCall(false); 2635 } 2636 2637 GC3Dboolean WebGLRenderingContext::isBuffer(WebGLBuffer* buffer) 2638 { 2639 if (!buffer || isContextLost()) 2640 return 0; 2641 2642 if (!buffer->hasEverBeenBound()) 2643 return 0; 2644 2645 return m_context->isBuffer(buffer->object()); 2646 } 2647 2648 bool WebGLRenderingContext::isContextLost() 2649 { 2650 if (m_restoreTimer.isActive()) 2651 return true; 2652 2653 bool newContextLost = m_context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR; 2654 2655 if (newContextLost != m_contextLost) 2656 m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts); 2657 2658 return m_contextLost; 2659 } 2660 2661 GC3Dboolean WebGLRenderingContext::isEnabled(GC3Denum cap) 2662 { 2663 if (!validateCapability(cap) || isContextLost()) 2664 return 0; 2665 return m_context->isEnabled(cap); 2666 } 2667 2668 GC3Dboolean WebGLRenderingContext::isFramebuffer(WebGLFramebuffer* framebuffer) 2669 { 2670 if (!framebuffer || isContextLost()) 2671 return 0; 2672 2673 if (!framebuffer->hasEverBeenBound()) 2674 return 0; 2675 2676 return m_context->isFramebuffer(framebuffer->object()); 2677 } 2678 2679 GC3Dboolean WebGLRenderingContext::isProgram(WebGLProgram* program) 2680 { 2681 if (!program || isContextLost()) 2682 return 0; 2683 2684 return m_context->isProgram(program->object()); 2685 } 2686 2687 GC3Dboolean WebGLRenderingContext::isRenderbuffer(WebGLRenderbuffer* renderbuffer) 2688 { 2689 if (!renderbuffer || isContextLost()) 2690 return 0; 2691 2692 if (!renderbuffer->hasEverBeenBound()) 2693 return 0; 2694 2695 return m_context->isRenderbuffer(renderbuffer->object()); 2696 } 2697 2698 GC3Dboolean WebGLRenderingContext::isShader(WebGLShader* shader) 2699 { 2700 if (!shader || isContextLost()) 2701 return 0; 2702 2703 return m_context->isShader(shader->object()); 2704 } 2705 2706 GC3Dboolean WebGLRenderingContext::isTexture(WebGLTexture* texture) 2707 { 2708 if (!texture || isContextLost()) 2709 return 0; 2710 2711 if (!texture->hasEverBeenBound()) 2712 return 0; 2713 2714 return m_context->isTexture(texture->object()); 2715 } 2716 2717 void WebGLRenderingContext::lineWidth(GC3Dfloat width) 2718 { 2719 if (isContextLost()) 2720 return; 2721 m_context->lineWidth(width); 2722 cleanupAfterGraphicsCall(false); 2723 } 2724 2725 void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec) 2726 { 2727 UNUSED_PARAM(ec); 2728 if (isContextLost() || !validateWebGLObject(program)) 2729 return; 2730 if (!isGLES2Compliant()) { 2731 if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) { 2732 program->setLinkStatus(false); 2733 return; 2734 } 2735 } 2736 2737 m_context->linkProgram(objectOrZero(program)); 2738 program->increaseLinkCount(); 2739 // cache link status 2740 GC3Dint value = 0; 2741 m_context->getProgramiv(objectOrZero(program), GraphicsContext3D::LINK_STATUS, &value); 2742 program->setLinkStatus(static_cast<bool>(value)); 2743 // Need to cache link status before caching active attribute locations. 2744 program->cacheActiveAttribLocations(); 2745 cleanupAfterGraphicsCall(false); 2746 } 2747 2748 void WebGLRenderingContext::pixelStorei(GC3Denum pname, GC3Dint param) 2749 { 2750 if (isContextLost()) 2751 return; 2752 switch (pname) { 2753 case GraphicsContext3D::UNPACK_FLIP_Y_WEBGL: 2754 m_unpackFlipY = param; 2755 break; 2756 case GraphicsContext3D::UNPACK_PREMULTIPLY_ALPHA_WEBGL: 2757 m_unpackPremultiplyAlpha = param; 2758 break; 2759 case GraphicsContext3D::UNPACK_COLORSPACE_CONVERSION_WEBGL: 2760 if (param == GraphicsContext3D::BROWSER_DEFAULT_WEBGL || param == GraphicsContext3D::NONE) 2761 m_unpackColorspaceConversion = static_cast<GC3Denum>(param); 2762 else { 2763 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2764 return; 2765 } 2766 break; 2767 case GraphicsContext3D::PACK_ALIGNMENT: 2768 case GraphicsContext3D::UNPACK_ALIGNMENT: 2769 if (param == 1 || param == 2 || param == 4 || param == 8) { 2770 if (pname == GraphicsContext3D::PACK_ALIGNMENT) 2771 m_packAlignment = param; 2772 else // GraphicsContext3D::UNPACK_ALIGNMENT: 2773 m_unpackAlignment = param; 2774 m_context->pixelStorei(pname, param); 2775 cleanupAfterGraphicsCall(false); 2776 } else { 2777 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2778 return; 2779 } 2780 break; 2781 default: 2782 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2783 return; 2784 } 2785 } 2786 2787 void WebGLRenderingContext::polygonOffset(GC3Dfloat factor, GC3Dfloat units) 2788 { 2789 if (isContextLost()) 2790 return; 2791 m_context->polygonOffset(factor, units); 2792 cleanupAfterGraphicsCall(false); 2793 } 2794 2795 void WebGLRenderingContext::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec) 2796 { 2797 if (isContextLost()) 2798 return; 2799 if (!canvas()->originClean()) { 2800 ec = SECURITY_ERR; 2801 return; 2802 } 2803 // Validate input parameters. 2804 if (!pixels) { 2805 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 2806 return; 2807 } 2808 switch (format) { 2809 case GraphicsContext3D::ALPHA: 2810 case GraphicsContext3D::RGB: 2811 case GraphicsContext3D::RGBA: 2812 break; 2813 default: 2814 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2815 return; 2816 } 2817 switch (type) { 2818 case GraphicsContext3D::UNSIGNED_BYTE: 2819 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: 2820 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: 2821 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: 2822 break; 2823 default: 2824 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2825 return; 2826 } 2827 if (format != GraphicsContext3D::RGBA || type != GraphicsContext3D::UNSIGNED_BYTE) { 2828 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2829 return; 2830 } 2831 // Validate array type against pixel type. 2832 if (!pixels->isUnsignedByteArray()) { 2833 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2834 return; 2835 } 2836 if (m_framebufferBinding && !m_framebufferBinding->onAccess(!isResourceSafe())) { 2837 m_context->synthesizeGLError(GraphicsContext3D::INVALID_FRAMEBUFFER_OPERATION); 2838 return; 2839 } 2840 // Calculate array size, taking into consideration of PACK_ALIGNMENT. 2841 unsigned int totalBytesRequired; 2842 unsigned int padding; 2843 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_packAlignment, &totalBytesRequired, &padding); 2844 if (error != GraphicsContext3D::NO_ERROR) { 2845 m_context->synthesizeGLError(error); 2846 return; 2847 } 2848 if (pixels->byteLength() < totalBytesRequired) { 2849 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2850 return; 2851 } 2852 clearIfComposited(); 2853 void* data = pixels->baseAddress(); 2854 m_context->readPixels(x, y, width, height, format, type, data); 2855 #if OS(DARWIN) 2856 // FIXME: remove this section when GL driver bug on Mac is fixed, i.e., 2857 // when alpha is off, readPixels should set alpha to 255 instead of 0. 2858 if (!m_context->getContextAttributes().alpha) { 2859 unsigned char* pixels = reinterpret_cast<unsigned char*>(data); 2860 for (GC3Dsizei iy = 0; iy < height; ++iy) { 2861 for (GC3Dsizei ix = 0; ix < width; ++ix) { 2862 pixels[3] = 255; 2863 pixels += 4; 2864 } 2865 pixels += padding; 2866 } 2867 } 2868 #endif 2869 cleanupAfterGraphicsCall(false); 2870 } 2871 2872 void WebGLRenderingContext::releaseShaderCompiler() 2873 { 2874 if (isContextLost()) 2875 return; 2876 m_context->releaseShaderCompiler(); 2877 cleanupAfterGraphicsCall(false); 2878 } 2879 2880 void WebGLRenderingContext::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height) 2881 { 2882 if (isContextLost()) 2883 return; 2884 if (target != GraphicsContext3D::RENDERBUFFER) { 2885 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2886 return; 2887 } 2888 if (!m_renderbufferBinding || !m_renderbufferBinding->object()) { 2889 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 2890 return; 2891 } 2892 if (!validateSize(width, height)) 2893 return; 2894 switch (internalformat) { 2895 case GraphicsContext3D::DEPTH_COMPONENT16: 2896 case GraphicsContext3D::RGBA4: 2897 case GraphicsContext3D::RGB5_A1: 2898 case GraphicsContext3D::RGB565: 2899 case GraphicsContext3D::STENCIL_INDEX8: 2900 m_context->renderbufferStorage(target, internalformat, width, height); 2901 m_renderbufferBinding->setInternalFormat(internalformat); 2902 m_renderbufferBinding->setIsValid(true); 2903 m_renderbufferBinding->setSize(width, height); 2904 cleanupAfterGraphicsCall(false); 2905 break; 2906 case GraphicsContext3D::DEPTH_STENCIL: 2907 if (isDepthStencilSupported()) { 2908 m_context->renderbufferStorage(target, Extensions3D::DEPTH24_STENCIL8, width, height); 2909 cleanupAfterGraphicsCall(false); 2910 } 2911 m_renderbufferBinding->setSize(width, height); 2912 m_renderbufferBinding->setIsValid(isDepthStencilSupported()); 2913 m_renderbufferBinding->setInternalFormat(internalformat); 2914 break; 2915 default: 2916 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2917 } 2918 } 2919 2920 void WebGLRenderingContext::sampleCoverage(GC3Dfloat value, GC3Dboolean invert) 2921 { 2922 if (isContextLost()) 2923 return; 2924 m_context->sampleCoverage(value, invert); 2925 cleanupAfterGraphicsCall(false); 2926 } 2927 2928 void WebGLRenderingContext::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) 2929 { 2930 if (isContextLost()) 2931 return; 2932 if (!validateSize(width, height)) 2933 return; 2934 m_context->scissor(x, y, width, height); 2935 cleanupAfterGraphicsCall(false); 2936 } 2937 2938 void WebGLRenderingContext::shaderSource(WebGLShader* shader, const String& string, ExceptionCode& ec) 2939 { 2940 UNUSED_PARAM(ec); 2941 if (isContextLost() || !validateWebGLObject(shader)) 2942 return; 2943 String stringWithoutComments = StripComments(string).result(); 2944 if (!validateString(stringWithoutComments)) 2945 return; 2946 shader->setSource(string); 2947 m_context->shaderSource(objectOrZero(shader), stringWithoutComments); 2948 cleanupAfterGraphicsCall(false); 2949 } 2950 2951 void WebGLRenderingContext::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask) 2952 { 2953 if (isContextLost()) 2954 return; 2955 if (!validateStencilFunc(func)) 2956 return; 2957 m_stencilFuncRef = ref; 2958 m_stencilFuncRefBack = ref; 2959 m_stencilFuncMask = mask; 2960 m_stencilFuncMaskBack = mask; 2961 m_context->stencilFunc(func, ref, mask); 2962 cleanupAfterGraphicsCall(false); 2963 } 2964 2965 void WebGLRenderingContext::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask) 2966 { 2967 if (isContextLost()) 2968 return; 2969 if (!validateStencilFunc(func)) 2970 return; 2971 switch (face) { 2972 case GraphicsContext3D::FRONT_AND_BACK: 2973 m_stencilFuncRef = ref; 2974 m_stencilFuncRefBack = ref; 2975 m_stencilFuncMask = mask; 2976 m_stencilFuncMaskBack = mask; 2977 break; 2978 case GraphicsContext3D::FRONT: 2979 m_stencilFuncRef = ref; 2980 m_stencilFuncMask = mask; 2981 break; 2982 case GraphicsContext3D::BACK: 2983 m_stencilFuncRefBack = ref; 2984 m_stencilFuncMaskBack = mask; 2985 break; 2986 default: 2987 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 2988 return; 2989 } 2990 m_context->stencilFuncSeparate(face, func, ref, mask); 2991 cleanupAfterGraphicsCall(false); 2992 } 2993 2994 void WebGLRenderingContext::stencilMask(GC3Duint mask) 2995 { 2996 if (isContextLost()) 2997 return; 2998 m_stencilMask = mask; 2999 m_stencilMaskBack = mask; 3000 m_context->stencilMask(mask); 3001 cleanupAfterGraphicsCall(false); 3002 } 3003 3004 void WebGLRenderingContext::stencilMaskSeparate(GC3Denum face, GC3Duint mask) 3005 { 3006 if (isContextLost()) 3007 return; 3008 switch (face) { 3009 case GraphicsContext3D::FRONT_AND_BACK: 3010 m_stencilMask = mask; 3011 m_stencilMaskBack = mask; 3012 break; 3013 case GraphicsContext3D::FRONT: 3014 m_stencilMask = mask; 3015 break; 3016 case GraphicsContext3D::BACK: 3017 m_stencilMaskBack = mask; 3018 break; 3019 default: 3020 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 3021 return; 3022 } 3023 m_context->stencilMaskSeparate(face, mask); 3024 cleanupAfterGraphicsCall(false); 3025 } 3026 3027 void WebGLRenderingContext::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass) 3028 { 3029 if (isContextLost()) 3030 return; 3031 m_context->stencilOp(fail, zfail, zpass); 3032 cleanupAfterGraphicsCall(false); 3033 } 3034 3035 void WebGLRenderingContext::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass) 3036 { 3037 if (isContextLost()) 3038 return; 3039 m_context->stencilOpSeparate(face, fail, zfail, zpass); 3040 cleanupAfterGraphicsCall(false); 3041 } 3042 3043 void WebGLRenderingContext::texImage2DBase(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3044 GC3Dsizei width, GC3Dsizei height, GC3Dint border, 3045 GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec) 3046 { 3047 // FIXME: For now we ignore any errors returned 3048 ec = 0; 3049 if (!validateTexFuncParameters(target, level, internalformat, width, height, border, format, type)) 3050 return; 3051 WebGLTexture* tex = validateTextureBinding(target, true); 3052 if (!tex) 3053 return; 3054 if (!isGLES2NPOTStrict()) { 3055 if (level && WebGLTexture::isNPOT(width, height)) { 3056 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3057 return; 3058 } 3059 } 3060 if (!pixels && !isResourceSafe()) { 3061 bool succeed = m_context->texImage2DResourceSafe(target, level, internalformat, width, height, 3062 border, format, type, m_unpackAlignment); 3063 if (!succeed) 3064 return; 3065 } else { 3066 m_context->texImage2D(target, level, internalformat, width, height, 3067 border, format, type, pixels); 3068 } 3069 tex->setLevelInfo(target, level, internalformat, width, height, type); 3070 cleanupAfterGraphicsCall(false); 3071 } 3072 3073 void WebGLRenderingContext::texImage2DImpl(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3074 GC3Denum format, GC3Denum type, Image* image, 3075 bool flipY, bool premultiplyAlpha, ExceptionCode& ec) 3076 { 3077 ec = 0; 3078 Vector<uint8_t> data; 3079 if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) { 3080 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3081 return; 3082 } 3083 if (m_unpackAlignment != 1) 3084 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1); 3085 texImage2DBase(target, level, internalformat, image->width(), image->height(), 0, 3086 format, type, data.data(), ec); 3087 if (m_unpackAlignment != 1) 3088 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment); 3089 } 3090 3091 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3092 GC3Dsizei width, GC3Dsizei height, GC3Dint border, 3093 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec) 3094 { 3095 if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels)) 3096 return; 3097 void* data = pixels ? pixels->baseAddress() : 0; 3098 Vector<uint8_t> tempData; 3099 bool changeUnpackAlignment = false; 3100 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) { 3101 if (!m_context->extractTextureData(width, height, format, type, 3102 m_unpackAlignment, 3103 m_unpackFlipY, m_unpackPremultiplyAlpha, 3104 data, 3105 tempData)) 3106 return; 3107 data = tempData.data(); 3108 changeUnpackAlignment = true; 3109 } 3110 if (changeUnpackAlignment) 3111 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1); 3112 texImage2DBase(target, level, internalformat, width, height, border, 3113 format, type, data, ec); 3114 if (changeUnpackAlignment) 3115 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment); 3116 } 3117 3118 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3119 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec) 3120 { 3121 ec = 0; 3122 if (isContextLost()) 3123 return; 3124 Vector<uint8_t> data; 3125 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { 3126 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3127 return; 3128 } 3129 if (m_unpackAlignment != 1) 3130 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1); 3131 texImage2DBase(target, level, internalformat, pixels->width(), pixels->height(), 0, 3132 format, type, data.data(), ec); 3133 if (m_unpackAlignment != 1) 3134 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment); 3135 } 3136 3137 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3138 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec) 3139 { 3140 ec = 0; 3141 if (isContextLost()) 3142 return; 3143 if (!validateHTMLImageElement(image)) 3144 return; 3145 checkOrigin(image); 3146 texImage2DImpl(target, level, internalformat, format, type, image->cachedImage()->image(), 3147 m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3148 } 3149 3150 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3151 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec) 3152 { 3153 ec = 0; 3154 if (isContextLost()) 3155 return; 3156 if (!canvas || !canvas->buffer()) { 3157 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3158 return; 3159 } 3160 checkOrigin(canvas); 3161 RefPtr<ImageData> imageData = canvas->getImageData(); 3162 if (imageData) 3163 texImage2D(target, level, internalformat, format, type, imageData.get(), ec); 3164 else 3165 texImage2DImpl(target, level, internalformat, format, type, canvas->copiedImage(), 3166 m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3167 } 3168 3169 #if ENABLE(VIDEO) 3170 PassRefPtr<Image> WebGLRenderingContext::videoFrameToImage(HTMLVideoElement* video) 3171 { 3172 if (!video || !video->videoWidth() || !video->videoHeight()) { 3173 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3174 return 0; 3175 } 3176 IntSize size(video->videoWidth(), video->videoHeight()); 3177 ImageBuffer* buf = m_videoCache.imageBuffer(size); 3178 if (!buf) { 3179 m_context->synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY); 3180 return 0; 3181 } 3182 checkOrigin(video); 3183 IntRect destRect(0, 0, size.width(), size.height()); 3184 // FIXME: Turn this into a GPU-GPU texture copy instead of CPU readback. 3185 video->paintCurrentFrameInContext(buf->context(), destRect); 3186 return buf->copyImage(); 3187 } 3188 3189 void WebGLRenderingContext::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, 3190 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec) 3191 { 3192 ec = 0; 3193 if (isContextLost()) 3194 return; 3195 RefPtr<Image> image = videoFrameToImage(video); 3196 if (!video) 3197 return; 3198 texImage2DImpl(target, level, internalformat, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3199 } 3200 #endif 3201 3202 void WebGLRenderingContext::texParameter(GC3Denum target, GC3Denum pname, GC3Dfloat paramf, GC3Dint parami, bool isFloat) 3203 { 3204 if (isContextLost()) 3205 return; 3206 WebGLTexture* tex = validateTextureBinding(target, false); 3207 if (!tex) 3208 return; 3209 switch (pname) { 3210 case GraphicsContext3D::TEXTURE_MIN_FILTER: 3211 case GraphicsContext3D::TEXTURE_MAG_FILTER: 3212 break; 3213 case GraphicsContext3D::TEXTURE_WRAP_S: 3214 case GraphicsContext3D::TEXTURE_WRAP_T: 3215 if ((isFloat && paramf != GraphicsContext3D::CLAMP_TO_EDGE && paramf != GraphicsContext3D::MIRRORED_REPEAT && paramf != GraphicsContext3D::REPEAT) 3216 || (!isFloat && parami != GraphicsContext3D::CLAMP_TO_EDGE && parami != GraphicsContext3D::MIRRORED_REPEAT && parami != GraphicsContext3D::REPEAT)) { 3217 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 3218 return; 3219 } 3220 break; 3221 default: 3222 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 3223 return; 3224 } 3225 if (isFloat) { 3226 tex->setParameterf(pname, paramf); 3227 m_context->texParameterf(target, pname, paramf); 3228 } else { 3229 tex->setParameteri(pname, parami); 3230 m_context->texParameteri(target, pname, parami); 3231 } 3232 cleanupAfterGraphicsCall(false); 3233 } 3234 3235 void WebGLRenderingContext::texParameterf(GC3Denum target, GC3Denum pname, GC3Dfloat param) 3236 { 3237 texParameter(target, pname, param, 0, true); 3238 } 3239 3240 void WebGLRenderingContext::texParameteri(GC3Denum target, GC3Denum pname, GC3Dint param) 3241 { 3242 texParameter(target, pname, 0, param, false); 3243 } 3244 3245 void WebGLRenderingContext::texSubImage2DBase(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3246 GC3Dsizei width, GC3Dsizei height, 3247 GC3Denum format, GC3Denum type, void* pixels, ExceptionCode& ec) 3248 { 3249 // FIXME: For now we ignore any errors returned 3250 ec = 0; 3251 if (isContextLost()) 3252 return; 3253 if (!validateTexFuncParameters(target, level, format, width, height, 0, format, type)) 3254 return; 3255 if (!validateSize(xoffset, yoffset)) 3256 return; 3257 WebGLTexture* tex = validateTextureBinding(target, true); 3258 if (!tex) 3259 return; 3260 if (xoffset + width > tex->getWidth(target, level) || yoffset + height > tex->getHeight(target, level)) { 3261 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3262 return; 3263 } 3264 if (tex->getInternalFormat(target, level) != format || tex->getType(target, level) != type) { 3265 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3266 return; 3267 } 3268 m_context->texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); 3269 cleanupAfterGraphicsCall(false); 3270 } 3271 3272 void WebGLRenderingContext::texSubImage2DImpl(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3273 GC3Denum format, GC3Denum type, 3274 Image* image, bool flipY, bool premultiplyAlpha, ExceptionCode& ec) 3275 { 3276 ec = 0; 3277 if (isContextLost()) 3278 return; 3279 Vector<uint8_t> data; 3280 if (!m_context->extractImageData(image, format, type, flipY, premultiplyAlpha, m_unpackColorspaceConversion == GraphicsContext3D::NONE, data)) { 3281 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3282 return; 3283 } 3284 texSubImage2DBase(target, level, xoffset, yoffset, image->width(), image->height(), 3285 format, type, data.data(), ec); 3286 } 3287 3288 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3289 GC3Dsizei width, GC3Dsizei height, 3290 GC3Denum format, GC3Denum type, ArrayBufferView* pixels, ExceptionCode& ec) 3291 { 3292 if (isContextLost() || !validateTexFuncData(width, height, format, type, pixels)) 3293 return; 3294 void* data = pixels ? pixels->baseAddress() : 0; 3295 Vector<uint8_t> tempData; 3296 bool changeUnpackAlignment = false; 3297 if (data && (m_unpackFlipY || m_unpackPremultiplyAlpha)) { 3298 if (!m_context->extractTextureData(width, height, format, type, 3299 m_unpackAlignment, 3300 m_unpackFlipY, m_unpackPremultiplyAlpha, 3301 data, 3302 tempData)) 3303 return; 3304 data = tempData.data(); 3305 changeUnpackAlignment = true; 3306 } 3307 if (changeUnpackAlignment) 3308 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, 1); 3309 texSubImage2DBase(target, level, xoffset, yoffset, width, height, format, type, data, ec); 3310 if (changeUnpackAlignment) 3311 m_context->pixelStorei(GraphicsContext3D::UNPACK_ALIGNMENT, m_unpackAlignment); 3312 } 3313 3314 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3315 GC3Denum format, GC3Denum type, ImageData* pixels, ExceptionCode& ec) 3316 { 3317 ec = 0; 3318 if (isContextLost()) 3319 return; 3320 Vector<uint8_t> data; 3321 if (!m_context->extractImageData(pixels, format, type, m_unpackFlipY, m_unpackPremultiplyAlpha, data)) { 3322 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3323 return; 3324 } 3325 texSubImage2DBase(target, level, xoffset, yoffset, pixels->width(), pixels->height(), 3326 format, type, data.data(), ec); 3327 } 3328 3329 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3330 GC3Denum format, GC3Denum type, HTMLImageElement* image, ExceptionCode& ec) 3331 { 3332 ec = 0; 3333 if (isContextLost()) 3334 return; 3335 if (!validateHTMLImageElement(image)) 3336 return; 3337 checkOrigin(image); 3338 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image->cachedImage()->image(), 3339 m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3340 } 3341 3342 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3343 GC3Denum format, GC3Denum type, HTMLCanvasElement* canvas, ExceptionCode& ec) 3344 { 3345 ec = 0; 3346 if (isContextLost()) 3347 return; 3348 if (!canvas || !canvas->buffer()) { 3349 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3350 return; 3351 } 3352 checkOrigin(canvas); 3353 RefPtr<ImageData> imageData = canvas->getImageData(); 3354 if (imageData) 3355 texSubImage2D(target, level, xoffset, yoffset, format, type, imageData.get(), ec); 3356 else 3357 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, canvas->copiedImage(), 3358 m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3359 } 3360 3361 #if ENABLE(VIDEO) 3362 void WebGLRenderingContext::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, 3363 GC3Denum format, GC3Denum type, HTMLVideoElement* video, ExceptionCode& ec) 3364 { 3365 ec = 0; 3366 if (isContextLost()) 3367 return; 3368 RefPtr<Image> image = videoFrameToImage(video); 3369 if (!video) 3370 return; 3371 texSubImage2DImpl(target, level, xoffset, yoffset, format, type, image.get(), m_unpackFlipY, m_unpackPremultiplyAlpha, ec); 3372 } 3373 #endif 3374 3375 void WebGLRenderingContext::uniform1f(const WebGLUniformLocation* location, GC3Dfloat x, ExceptionCode& ec) 3376 { 3377 UNUSED_PARAM(ec); 3378 if (isContextLost() || !location) 3379 return; 3380 3381 if (location->program() != m_currentProgram) { 3382 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3383 return; 3384 } 3385 3386 m_context->uniform1f(location->location(), x); 3387 cleanupAfterGraphicsCall(false); 3388 } 3389 3390 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) 3391 { 3392 UNUSED_PARAM(ec); 3393 if (isContextLost() || !validateUniformParameters(location, v, 1)) 3394 return; 3395 3396 m_context->uniform1fv(location->location(), v->data(), v->length()); 3397 cleanupAfterGraphicsCall(false); 3398 } 3399 3400 void WebGLRenderingContext::uniform1fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3401 { 3402 UNUSED_PARAM(ec); 3403 if (isContextLost() || !validateUniformParameters(location, v, size, 1)) 3404 return; 3405 3406 m_context->uniform1fv(location->location(), v, size); 3407 cleanupAfterGraphicsCall(false); 3408 } 3409 3410 void WebGLRenderingContext::uniform1i(const WebGLUniformLocation* location, GC3Dint x, ExceptionCode& ec) 3411 { 3412 UNUSED_PARAM(ec); 3413 if (isContextLost() || !location) 3414 return; 3415 3416 if (location->program() != m_currentProgram) { 3417 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3418 return; 3419 } 3420 3421 m_context->uniform1i(location->location(), x); 3422 cleanupAfterGraphicsCall(false); 3423 } 3424 3425 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) 3426 { 3427 UNUSED_PARAM(ec); 3428 if (isContextLost() || !validateUniformParameters(location, v, 1)) 3429 return; 3430 3431 m_context->uniform1iv(location->location(), v->data(), v->length()); 3432 cleanupAfterGraphicsCall(false); 3433 } 3434 3435 void WebGLRenderingContext::uniform1iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec) 3436 { 3437 UNUSED_PARAM(ec); 3438 if (isContextLost() || !validateUniformParameters(location, v, size, 1)) 3439 return; 3440 3441 m_context->uniform1iv(location->location(), v, size); 3442 cleanupAfterGraphicsCall(false); 3443 } 3444 3445 void WebGLRenderingContext::uniform2f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, ExceptionCode& ec) 3446 { 3447 UNUSED_PARAM(ec); 3448 if (isContextLost() || !location) 3449 return; 3450 3451 if (location->program() != m_currentProgram) { 3452 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3453 return; 3454 } 3455 3456 m_context->uniform2f(location->location(), x, y); 3457 cleanupAfterGraphicsCall(false); 3458 } 3459 3460 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) 3461 { 3462 UNUSED_PARAM(ec); 3463 if (isContextLost() || !validateUniformParameters(location, v, 2)) 3464 return; 3465 3466 m_context->uniform2fv(location->location(), v->data(), v->length() / 2); 3467 cleanupAfterGraphicsCall(false); 3468 } 3469 3470 void WebGLRenderingContext::uniform2fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3471 { 3472 UNUSED_PARAM(ec); 3473 if (isContextLost() || !validateUniformParameters(location, v, size, 2)) 3474 return; 3475 3476 m_context->uniform2fv(location->location(), v, size / 2); 3477 cleanupAfterGraphicsCall(false); 3478 } 3479 3480 void WebGLRenderingContext::uniform2i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, ExceptionCode& ec) 3481 { 3482 UNUSED_PARAM(ec); 3483 if (isContextLost() || !location) 3484 return; 3485 3486 if (location->program() != m_currentProgram) { 3487 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3488 return; 3489 } 3490 3491 m_context->uniform2i(location->location(), x, y); 3492 cleanupAfterGraphicsCall(false); 3493 } 3494 3495 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) 3496 { 3497 UNUSED_PARAM(ec); 3498 if (isContextLost() || !validateUniformParameters(location, v, 2)) 3499 return; 3500 3501 m_context->uniform2iv(location->location(), v->data(), v->length() / 2); 3502 cleanupAfterGraphicsCall(false); 3503 } 3504 3505 void WebGLRenderingContext::uniform2iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec) 3506 { 3507 UNUSED_PARAM(ec); 3508 if (isContextLost() || !validateUniformParameters(location, v, size, 2)) 3509 return; 3510 3511 m_context->uniform2iv(location->location(), v, size / 2); 3512 cleanupAfterGraphicsCall(false); 3513 } 3514 3515 void WebGLRenderingContext::uniform3f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, ExceptionCode& ec) 3516 { 3517 UNUSED_PARAM(ec); 3518 if (isContextLost() || !location) 3519 return; 3520 3521 if (location->program() != m_currentProgram) { 3522 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3523 return; 3524 } 3525 3526 m_context->uniform3f(location->location(), x, y, z); 3527 cleanupAfterGraphicsCall(false); 3528 } 3529 3530 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) 3531 { 3532 UNUSED_PARAM(ec); 3533 if (isContextLost() || !validateUniformParameters(location, v, 3)) 3534 return; 3535 3536 m_context->uniform3fv(location->location(), v->data(), v->length() / 3); 3537 cleanupAfterGraphicsCall(false); 3538 } 3539 3540 void WebGLRenderingContext::uniform3fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3541 { 3542 UNUSED_PARAM(ec); 3543 if (isContextLost() || !validateUniformParameters(location, v, size, 3)) 3544 return; 3545 3546 m_context->uniform3fv(location->location(), v, size / 3); 3547 cleanupAfterGraphicsCall(false); 3548 } 3549 3550 void WebGLRenderingContext::uniform3i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, ExceptionCode& ec) 3551 { 3552 UNUSED_PARAM(ec); 3553 if (isContextLost() || !location) 3554 return; 3555 3556 if (location->program() != m_currentProgram) { 3557 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3558 return; 3559 } 3560 3561 m_context->uniform3i(location->location(), x, y, z); 3562 cleanupAfterGraphicsCall(false); 3563 } 3564 3565 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) 3566 { 3567 UNUSED_PARAM(ec); 3568 if (isContextLost() || !validateUniformParameters(location, v, 3)) 3569 return; 3570 3571 m_context->uniform3iv(location->location(), v->data(), v->length() / 3); 3572 cleanupAfterGraphicsCall(false); 3573 } 3574 3575 void WebGLRenderingContext::uniform3iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec) 3576 { 3577 UNUSED_PARAM(ec); 3578 if (isContextLost() || !validateUniformParameters(location, v, size, 3)) 3579 return; 3580 3581 m_context->uniform3iv(location->location(), v, size / 3); 3582 cleanupAfterGraphicsCall(false); 3583 } 3584 3585 void WebGLRenderingContext::uniform4f(const WebGLUniformLocation* location, GC3Dfloat x, GC3Dfloat y, GC3Dfloat z, GC3Dfloat w, ExceptionCode& ec) 3586 { 3587 UNUSED_PARAM(ec); 3588 if (isContextLost() || !location) 3589 return; 3590 3591 if (location->program() != m_currentProgram) { 3592 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3593 return; 3594 } 3595 3596 m_context->uniform4f(location->location(), x, y, z, w); 3597 cleanupAfterGraphicsCall(false); 3598 } 3599 3600 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, Float32Array* v, ExceptionCode& ec) 3601 { 3602 UNUSED_PARAM(ec); 3603 if (isContextLost() || !validateUniformParameters(location, v, 4)) 3604 return; 3605 3606 m_context->uniform4fv(location->location(), v->data(), v->length() / 4); 3607 cleanupAfterGraphicsCall(false); 3608 } 3609 3610 void WebGLRenderingContext::uniform4fv(const WebGLUniformLocation* location, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3611 { 3612 UNUSED_PARAM(ec); 3613 if (isContextLost() || !validateUniformParameters(location, v, size, 4)) 3614 return; 3615 3616 m_context->uniform4fv(location->location(), v, size / 4); 3617 cleanupAfterGraphicsCall(false); 3618 } 3619 3620 void WebGLRenderingContext::uniform4i(const WebGLUniformLocation* location, GC3Dint x, GC3Dint y, GC3Dint z, GC3Dint w, ExceptionCode& ec) 3621 { 3622 UNUSED_PARAM(ec); 3623 if (isContextLost() || !location) 3624 return; 3625 3626 if (location->program() != m_currentProgram) { 3627 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3628 return; 3629 } 3630 3631 m_context->uniform4i(location->location(), x, y, z, w); 3632 cleanupAfterGraphicsCall(false); 3633 } 3634 3635 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, Int32Array* v, ExceptionCode& ec) 3636 { 3637 UNUSED_PARAM(ec); 3638 if (isContextLost() || !validateUniformParameters(location, v, 4)) 3639 return; 3640 3641 m_context->uniform4iv(location->location(), v->data(), v->length() / 4); 3642 cleanupAfterGraphicsCall(false); 3643 } 3644 3645 void WebGLRenderingContext::uniform4iv(const WebGLUniformLocation* location, GC3Dint* v, GC3Dsizei size, ExceptionCode& ec) 3646 { 3647 UNUSED_PARAM(ec); 3648 if (isContextLost() || !validateUniformParameters(location, v, size, 4)) 3649 return; 3650 3651 m_context->uniform4iv(location->location(), v, size / 4); 3652 cleanupAfterGraphicsCall(false); 3653 } 3654 3655 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec) 3656 { 3657 UNUSED_PARAM(ec); 3658 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 4)) 3659 return; 3660 m_context->uniformMatrix2fv(location->location(), transpose, v->data(), v->length() / 4); 3661 cleanupAfterGraphicsCall(false); 3662 } 3663 3664 void WebGLRenderingContext::uniformMatrix2fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3665 { 3666 UNUSED_PARAM(ec); 3667 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 4)) 3668 return; 3669 m_context->uniformMatrix2fv(location->location(), transpose, v, size / 4); 3670 cleanupAfterGraphicsCall(false); 3671 } 3672 3673 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec) 3674 { 3675 UNUSED_PARAM(ec); 3676 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 9)) 3677 return; 3678 m_context->uniformMatrix3fv(location->location(), transpose, v->data(), v->length() / 9); 3679 cleanupAfterGraphicsCall(false); 3680 } 3681 3682 void WebGLRenderingContext::uniformMatrix3fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3683 { 3684 UNUSED_PARAM(ec); 3685 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 9)) 3686 return; 3687 m_context->uniformMatrix3fv(location->location(), transpose, v, size / 9); 3688 cleanupAfterGraphicsCall(false); 3689 } 3690 3691 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, ExceptionCode& ec) 3692 { 3693 UNUSED_PARAM(ec); 3694 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, 16)) 3695 return; 3696 m_context->uniformMatrix4fv(location->location(), transpose, v->data(), v->length() / 16); 3697 cleanupAfterGraphicsCall(false); 3698 } 3699 3700 void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* location, GC3Dboolean transpose, GC3Dfloat* v, GC3Dsizei size, ExceptionCode& ec) 3701 { 3702 UNUSED_PARAM(ec); 3703 if (isContextLost() || !validateUniformMatrixParameters(location, transpose, v, size, 16)) 3704 return; 3705 m_context->uniformMatrix4fv(location->location(), transpose, v, size / 16); 3706 cleanupAfterGraphicsCall(false); 3707 } 3708 3709 void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec) 3710 { 3711 UNUSED_PARAM(ec); 3712 bool deleted; 3713 if (!checkObjectToBeBound(program, deleted)) 3714 return; 3715 if (deleted) 3716 program = 0; 3717 if (program && !program->getLinkStatus()) { 3718 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3719 cleanupAfterGraphicsCall(false); 3720 return; 3721 } 3722 if (m_currentProgram != program) { 3723 if (m_currentProgram) 3724 m_currentProgram->onDetached(); 3725 m_currentProgram = program; 3726 m_context->useProgram(objectOrZero(program)); 3727 if (program) 3728 program->onAttached(); 3729 } 3730 cleanupAfterGraphicsCall(false); 3731 } 3732 3733 void WebGLRenderingContext::validateProgram(WebGLProgram* program, ExceptionCode& ec) 3734 { 3735 UNUSED_PARAM(ec); 3736 if (isContextLost() || !validateWebGLObject(program)) 3737 return; 3738 m_context->validateProgram(objectOrZero(program)); 3739 cleanupAfterGraphicsCall(false); 3740 } 3741 3742 void WebGLRenderingContext::vertexAttrib1f(GC3Duint index, GC3Dfloat v0) 3743 { 3744 vertexAttribfImpl(index, 1, v0, 0.0f, 0.0f, 1.0f); 3745 } 3746 3747 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, Float32Array* v) 3748 { 3749 vertexAttribfvImpl(index, v, 1); 3750 } 3751 3752 void WebGLRenderingContext::vertexAttrib1fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size) 3753 { 3754 vertexAttribfvImpl(index, v, size, 1); 3755 } 3756 3757 void WebGLRenderingContext::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1) 3758 { 3759 vertexAttribfImpl(index, 2, v0, v1, 0.0f, 1.0f); 3760 } 3761 3762 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, Float32Array* v) 3763 { 3764 vertexAttribfvImpl(index, v, 2); 3765 } 3766 3767 void WebGLRenderingContext::vertexAttrib2fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size) 3768 { 3769 vertexAttribfvImpl(index, v, size, 2); 3770 } 3771 3772 void WebGLRenderingContext::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2) 3773 { 3774 vertexAttribfImpl(index, 3, v0, v1, v2, 1.0f); 3775 } 3776 3777 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, Float32Array* v) 3778 { 3779 vertexAttribfvImpl(index, v, 3); 3780 } 3781 3782 void WebGLRenderingContext::vertexAttrib3fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size) 3783 { 3784 vertexAttribfvImpl(index, v, size, 3); 3785 } 3786 3787 void WebGLRenderingContext::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) 3788 { 3789 vertexAttribfImpl(index, 4, v0, v1, v2, v3); 3790 } 3791 3792 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, Float32Array* v) 3793 { 3794 vertexAttribfvImpl(index, v, 4); 3795 } 3796 3797 void WebGLRenderingContext::vertexAttrib4fv(GC3Duint index, GC3Dfloat* v, GC3Dsizei size) 3798 { 3799 vertexAttribfvImpl(index, v, size, 4); 3800 } 3801 3802 void WebGLRenderingContext::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset, ExceptionCode& ec) 3803 { 3804 UNUSED_PARAM(ec); 3805 if (isContextLost()) 3806 return; 3807 switch (type) { 3808 case GraphicsContext3D::BYTE: 3809 case GraphicsContext3D::UNSIGNED_BYTE: 3810 case GraphicsContext3D::SHORT: 3811 case GraphicsContext3D::UNSIGNED_SHORT: 3812 case GraphicsContext3D::FLOAT: 3813 break; 3814 default: 3815 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 3816 return; 3817 } 3818 if (index >= m_maxVertexAttribs) { 3819 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3820 return; 3821 } 3822 if (size < 1 || size > 4 || stride < 0 || stride > 255 || offset < 0) { 3823 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 3824 return; 3825 } 3826 if (!m_boundArrayBuffer) { 3827 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3828 return; 3829 } 3830 // Determine the number of elements the bound buffer can hold, given the offset, size, type and stride 3831 unsigned int typeSize = sizeInBytes(type); 3832 if (!typeSize) { 3833 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 3834 return; 3835 } 3836 if ((stride % typeSize) || (offset % typeSize)) { 3837 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3838 return; 3839 } 3840 GC3Dsizei bytesPerElement = size * typeSize; 3841 3842 GC3Dsizei validatedStride = stride ? stride : bytesPerElement; 3843 3844 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(index); 3845 state.bufferBinding = m_boundArrayBuffer; 3846 state.bytesPerElement = bytesPerElement; 3847 state.size = size; 3848 state.type = type; 3849 state.normalized = normalized; 3850 state.stride = validatedStride; 3851 state.originalStride = stride; 3852 state.offset = offset; 3853 m_context->vertexAttribPointer(index, size, type, normalized, stride, offset); 3854 cleanupAfterGraphicsCall(false); 3855 } 3856 3857 void WebGLRenderingContext::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height) 3858 { 3859 if (isContextLost()) 3860 return; 3861 if (isnan(x)) 3862 x = 0; 3863 if (isnan(y)) 3864 y = 0; 3865 if (isnan(width)) 3866 width = 100; 3867 if (isnan(height)) 3868 height = 100; 3869 if (!validateSize(width, height)) 3870 return; 3871 m_context->viewport(x, y, width, height); 3872 cleanupAfterGraphicsCall(false); 3873 } 3874 3875 void WebGLRenderingContext::forceLostContext() 3876 { 3877 if (isContextLost()) { 3878 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 3879 return; 3880 } 3881 3882 m_restoreTimer.startOneShot(0); 3883 } 3884 3885 void WebGLRenderingContext::onLostContext() 3886 { 3887 m_contextLost = true; 3888 3889 detachAndRemoveAllObjects(); 3890 3891 // There is no direct way to clear errors from a GL implementation and 3892 // looping until getError() becomes NO_ERROR might cause an infinite loop if 3893 // the driver or context implementation had a bug. So, loop a reasonably 3894 // large number of times to clear any existing errors. 3895 for (int i = 0; i < 100; ++i) { 3896 if (m_context->getError() == GraphicsContext3D::NO_ERROR) 3897 break; 3898 } 3899 m_context->synthesizeGLError(GraphicsContext3D::CONTEXT_LOST_WEBGL); 3900 3901 canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, "")); 3902 } 3903 3904 void WebGLRenderingContext::restoreContext() 3905 { 3906 RefPtr<GraphicsContext3D> context(GraphicsContext3D::create(m_attributes, canvas()->document()->view()->root()->hostWindow())); 3907 if (!context) 3908 return; 3909 3910 m_context = context; 3911 m_contextLost = false; 3912 initializeNewContext(); 3913 canvas()->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, false, true, "")); 3914 } 3915 3916 void WebGLRenderingContext::removeObject(WebGLObject* object) 3917 { 3918 m_canvasObjects.remove(object); 3919 } 3920 3921 void WebGLRenderingContext::addObject(WebGLObject* object) 3922 { 3923 ASSERT(!isContextLost()); 3924 removeObject(object); 3925 m_canvasObjects.add(object); 3926 } 3927 3928 void WebGLRenderingContext::detachAndRemoveAllObjects() 3929 { 3930 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end(); 3931 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) 3932 (*it)->detachContext(); 3933 3934 m_canvasObjects.clear(); 3935 } 3936 3937 WebGLTexture* WebGLRenderingContext::findTexture(Platform3DObject obj) 3938 { 3939 if (!obj) 3940 return 0; 3941 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end(); 3942 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) { 3943 if ((*it)->isTexture() && (*it)->object() == obj) 3944 return reinterpret_cast<WebGLTexture*>((*it).get()); 3945 } 3946 return 0; 3947 } 3948 3949 WebGLRenderbuffer* WebGLRenderingContext::findRenderbuffer(Platform3DObject obj) 3950 { 3951 if (!obj) 3952 return 0; 3953 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end(); 3954 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) { 3955 if ((*it)->isRenderbuffer() && (*it)->object() == obj) 3956 return reinterpret_cast<WebGLRenderbuffer*>((*it).get()); 3957 } 3958 return 0; 3959 } 3960 3961 WebGLBuffer* WebGLRenderingContext::findBuffer(Platform3DObject obj) 3962 { 3963 if (!obj) 3964 return 0; 3965 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end(); 3966 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) { 3967 if ((*it)->isBuffer() && (*it)->object() == obj) 3968 return reinterpret_cast<WebGLBuffer*>((*it).get()); 3969 } 3970 return 0; 3971 } 3972 3973 WebGLShader* WebGLRenderingContext::findShader(Platform3DObject obj) 3974 { 3975 if (!obj) 3976 return 0; 3977 HashSet<RefPtr<WebGLObject> >::iterator pend = m_canvasObjects.end(); 3978 for (HashSet<RefPtr<WebGLObject> >::iterator it = m_canvasObjects.begin(); it != pend; ++it) { 3979 if ((*it)->isShader() && (*it)->object() == obj) 3980 return reinterpret_cast<WebGLShader*>((*it).get()); 3981 } 3982 return 0; 3983 } 3984 3985 WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname) 3986 { 3987 GC3Dboolean value = 0; 3988 m_context->getBooleanv(pname, &value); 3989 return WebGLGetInfo(static_cast<bool>(value)); 3990 } 3991 3992 WebGLGetInfo WebGLRenderingContext::getBooleanArrayParameter(GC3Denum pname) 3993 { 3994 if (pname != GraphicsContext3D::COLOR_WRITEMASK) { 3995 notImplemented(); 3996 return WebGLGetInfo(0, 0); 3997 } 3998 GC3Dboolean value[4] = {0}; 3999 m_context->getBooleanv(pname, value); 4000 bool boolValue[4]; 4001 for (int ii = 0; ii < 4; ++ii) 4002 boolValue[ii] = static_cast<bool>(value[ii]); 4003 return WebGLGetInfo(boolValue, 4); 4004 } 4005 4006 WebGLGetInfo WebGLRenderingContext::getFloatParameter(GC3Denum pname) 4007 { 4008 GC3Dfloat value = 0; 4009 m_context->getFloatv(pname, &value); 4010 return WebGLGetInfo(value); 4011 } 4012 4013 WebGLGetInfo WebGLRenderingContext::getIntParameter(GC3Denum pname) 4014 { 4015 GC3Dint value = 0; 4016 m_context->getIntegerv(pname, &value); 4017 return WebGLGetInfo(value); 4018 } 4019 4020 WebGLGetInfo WebGLRenderingContext::getUnsignedIntParameter(GC3Denum pname) 4021 { 4022 GC3Dint value = 0; 4023 m_context->getIntegerv(pname, &value); 4024 return WebGLGetInfo(static_cast<unsigned int>(value)); 4025 } 4026 4027 WebGLGetInfo WebGLRenderingContext::getWebGLFloatArrayParameter(GC3Denum pname) 4028 { 4029 GC3Dfloat value[4] = {0}; 4030 m_context->getFloatv(pname, value); 4031 unsigned length = 0; 4032 switch (pname) { 4033 case GraphicsContext3D::ALIASED_POINT_SIZE_RANGE: 4034 case GraphicsContext3D::ALIASED_LINE_WIDTH_RANGE: 4035 case GraphicsContext3D::DEPTH_RANGE: 4036 length = 2; 4037 break; 4038 case GraphicsContext3D::BLEND_COLOR: 4039 case GraphicsContext3D::COLOR_CLEAR_VALUE: 4040 length = 4; 4041 break; 4042 default: 4043 notImplemented(); 4044 } 4045 return WebGLGetInfo(Float32Array::create(value, length)); 4046 } 4047 4048 WebGLGetInfo WebGLRenderingContext::getWebGLIntArrayParameter(GC3Denum pname) 4049 { 4050 GC3Dint value[4] = {0}; 4051 m_context->getIntegerv(pname, value); 4052 unsigned length = 0; 4053 switch (pname) { 4054 case GraphicsContext3D::MAX_VIEWPORT_DIMS: 4055 length = 2; 4056 break; 4057 case GraphicsContext3D::SCISSOR_BOX: 4058 case GraphicsContext3D::VIEWPORT: 4059 length = 4; 4060 break; 4061 default: 4062 notImplemented(); 4063 } 4064 return WebGLGetInfo(Int32Array::create(value, length)); 4065 } 4066 4067 void WebGLRenderingContext::handleNPOTTextures(bool prepareToDraw) 4068 { 4069 bool resetActiveUnit = false; 4070 for (unsigned ii = 0; ii < m_textureUnits.size(); ++ii) { 4071 if ((m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture()) 4072 || (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture())) { 4073 if (ii != m_activeTextureUnit) { 4074 m_context->activeTexture(ii); 4075 resetActiveUnit = true; 4076 } else if (resetActiveUnit) { 4077 m_context->activeTexture(ii); 4078 resetActiveUnit = false; 4079 } 4080 WebGLTexture* tex2D; 4081 WebGLTexture* texCubeMap; 4082 if (prepareToDraw) { 4083 tex2D = m_blackTexture2D.get(); 4084 texCubeMap = m_blackTextureCubeMap.get(); 4085 } else { 4086 tex2D = m_textureUnits[ii].m_texture2DBinding.get(); 4087 texCubeMap = m_textureUnits[ii].m_textureCubeMapBinding.get(); 4088 } 4089 if (m_textureUnits[ii].m_texture2DBinding && m_textureUnits[ii].m_texture2DBinding->needToUseBlackTexture()) 4090 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, objectOrZero(tex2D)); 4091 if (m_textureUnits[ii].m_textureCubeMapBinding && m_textureUnits[ii].m_textureCubeMapBinding->needToUseBlackTexture()) 4092 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, objectOrZero(texCubeMap)); 4093 } 4094 } 4095 if (resetActiveUnit) 4096 m_context->activeTexture(m_activeTextureUnit); 4097 } 4098 4099 void WebGLRenderingContext::createFallbackBlackTextures1x1() 4100 { 4101 unsigned char black[] = {0, 0, 0, 255}; 4102 m_blackTexture2D = createTexture(); 4103 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_blackTexture2D->object()); 4104 m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 4105 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4106 m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0); 4107 m_blackTextureCubeMap = createTexture(); 4108 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, m_blackTextureCubeMap->object()); 4109 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X, 0, GraphicsContext3D::RGBA, 1, 1, 4110 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4111 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GraphicsContext3D::RGBA, 1, 1, 4112 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4113 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1, 4114 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4115 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GraphicsContext3D::RGBA, 1, 1, 4116 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4117 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1, 4118 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4119 m_context->texImage2D(GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GraphicsContext3D::RGBA, 1, 1, 4120 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, black); 4121 m_context->bindTexture(GraphicsContext3D::TEXTURE_CUBE_MAP, 0); 4122 } 4123 4124 bool WebGLRenderingContext::isTexInternalFormatColorBufferCombinationValid(GC3Denum texInternalFormat, 4125 GC3Denum colorBufferFormat) 4126 { 4127 switch (colorBufferFormat) { 4128 case GraphicsContext3D::ALPHA: 4129 if (texInternalFormat == GraphicsContext3D::ALPHA) 4130 return true; 4131 break; 4132 case GraphicsContext3D::RGB: 4133 if (texInternalFormat == GraphicsContext3D::LUMINANCE 4134 || texInternalFormat == GraphicsContext3D::RGB) 4135 return true; 4136 break; 4137 case GraphicsContext3D::RGBA: 4138 return true; 4139 } 4140 return false; 4141 } 4142 4143 GC3Denum WebGLRenderingContext::getBoundFramebufferColorFormat() 4144 { 4145 if (m_framebufferBinding && m_framebufferBinding->object()) 4146 return m_framebufferBinding->getColorBufferFormat(); 4147 if (m_attributes.alpha) 4148 return GraphicsContext3D::RGBA; 4149 return GraphicsContext3D::RGB; 4150 } 4151 4152 int WebGLRenderingContext::getBoundFramebufferWidth() 4153 { 4154 if (m_framebufferBinding && m_framebufferBinding->object()) 4155 return m_framebufferBinding->getWidth(); 4156 return m_context->getInternalFramebufferSize().width(); 4157 } 4158 4159 int WebGLRenderingContext::getBoundFramebufferHeight() 4160 { 4161 if (m_framebufferBinding && m_framebufferBinding->object()) 4162 return m_framebufferBinding->getHeight(); 4163 return m_context->getInternalFramebufferSize().height(); 4164 } 4165 4166 WebGLTexture* WebGLRenderingContext::validateTextureBinding(GC3Denum target, bool useSixEnumsForCubeMap) 4167 { 4168 WebGLTexture* tex = 0; 4169 switch (target) { 4170 case GraphicsContext3D::TEXTURE_2D: 4171 tex = m_textureUnits[m_activeTextureUnit].m_texture2DBinding.get(); 4172 break; 4173 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X: 4174 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X: 4175 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y: 4176 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y: 4177 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z: 4178 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z: 4179 if (!useSixEnumsForCubeMap) { 4180 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4181 return 0; 4182 } 4183 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get(); 4184 break; 4185 case GraphicsContext3D::TEXTURE_CUBE_MAP: 4186 if (useSixEnumsForCubeMap) { 4187 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4188 return 0; 4189 } 4190 tex = m_textureUnits[m_activeTextureUnit].m_textureCubeMapBinding.get(); 4191 break; 4192 default: 4193 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4194 return 0; 4195 } 4196 if (!tex) 4197 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4198 return tex; 4199 } 4200 4201 bool WebGLRenderingContext::validateSize(GC3Dint x, GC3Dint y) 4202 { 4203 if (x < 0 || y < 0) { 4204 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4205 return false; 4206 } 4207 return true; 4208 } 4209 4210 bool WebGLRenderingContext::validateString(const String& string) 4211 { 4212 for (size_t i = 0; i < string.length(); ++i) { 4213 if (!validateCharacter(string[i])) { 4214 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4215 return false; 4216 } 4217 } 4218 return true; 4219 } 4220 4221 bool WebGLRenderingContext::validateTexFuncFormatAndType(GC3Denum format, GC3Denum type) 4222 { 4223 switch (format) { 4224 case GraphicsContext3D::ALPHA: 4225 case GraphicsContext3D::LUMINANCE: 4226 case GraphicsContext3D::LUMINANCE_ALPHA: 4227 case GraphicsContext3D::RGB: 4228 case GraphicsContext3D::RGBA: 4229 break; 4230 default: 4231 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4232 return false; 4233 } 4234 4235 switch (type) { 4236 case GraphicsContext3D::UNSIGNED_BYTE: 4237 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: 4238 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: 4239 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: 4240 break; 4241 case GraphicsContext3D::FLOAT: 4242 if (m_oesTextureFloat) 4243 break; 4244 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4245 return false; 4246 default: 4247 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4248 return false; 4249 } 4250 4251 // Verify that the combination of format and type is supported. 4252 switch (format) { 4253 case GraphicsContext3D::ALPHA: 4254 case GraphicsContext3D::LUMINANCE: 4255 case GraphicsContext3D::LUMINANCE_ALPHA: 4256 if (type != GraphicsContext3D::UNSIGNED_BYTE 4257 && type != GraphicsContext3D::FLOAT) { 4258 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4259 return false; 4260 } 4261 break; 4262 case GraphicsContext3D::RGB: 4263 if (type != GraphicsContext3D::UNSIGNED_BYTE 4264 && type != GraphicsContext3D::UNSIGNED_SHORT_5_6_5 4265 && type != GraphicsContext3D::FLOAT) { 4266 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4267 return false; 4268 } 4269 break; 4270 case GraphicsContext3D::RGBA: 4271 if (type != GraphicsContext3D::UNSIGNED_BYTE 4272 && type != GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4 4273 && type != GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1 4274 && type != GraphicsContext3D::FLOAT) { 4275 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4276 return false; 4277 } 4278 break; 4279 default: 4280 ASSERT_NOT_REACHED(); 4281 } 4282 4283 return true; 4284 } 4285 4286 bool WebGLRenderingContext::validateTexFuncLevel(GC3Denum target, GC3Dint level) 4287 { 4288 if (level < 0) { 4289 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4290 return false; 4291 } 4292 switch (target) { 4293 case GraphicsContext3D::TEXTURE_2D: 4294 if (level > m_maxTextureLevel) { 4295 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4296 return false; 4297 } 4298 break; 4299 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X: 4300 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X: 4301 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y: 4302 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y: 4303 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z: 4304 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z: 4305 if (level > m_maxCubeMapTextureLevel) { 4306 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4307 return false; 4308 } 4309 break; 4310 } 4311 // This function only checks if level is legal, so we return true and don't 4312 // generate INVALID_ENUM if target is illegal. 4313 return true; 4314 } 4315 4316 bool WebGLRenderingContext::validateTexFuncParameters(GC3Denum target, GC3Dint level, 4317 GC3Denum internalformat, 4318 GC3Dsizei width, GC3Dsizei height, GC3Dint border, 4319 GC3Denum format, GC3Denum type) 4320 { 4321 // We absolutely have to validate the format and type combination. 4322 // The texImage2D entry points taking HTMLImage, etc. will produce 4323 // temporary data based on this combination, so it must be legal. 4324 if (!validateTexFuncFormatAndType(format, type) || !validateTexFuncLevel(target, level)) 4325 return false; 4326 4327 if (width < 0 || height < 0) { 4328 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4329 return false; 4330 } 4331 4332 switch (target) { 4333 case GraphicsContext3D::TEXTURE_2D: 4334 if (width > m_maxTextureSize || height > m_maxTextureSize) { 4335 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4336 return false; 4337 } 4338 break; 4339 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_X: 4340 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_X: 4341 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Y: 4342 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Y: 4343 case GraphicsContext3D::TEXTURE_CUBE_MAP_POSITIVE_Z: 4344 case GraphicsContext3D::TEXTURE_CUBE_MAP_NEGATIVE_Z: 4345 if (width != height || width > m_maxCubeMapTextureSize) { 4346 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4347 return false; 4348 } 4349 break; 4350 default: 4351 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4352 return false; 4353 } 4354 4355 if (format != internalformat) { 4356 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4357 return false; 4358 } 4359 4360 if (border) { 4361 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4362 return false; 4363 } 4364 4365 return true; 4366 } 4367 4368 bool WebGLRenderingContext::validateTexFuncData(GC3Dsizei width, GC3Dsizei height, 4369 GC3Denum format, GC3Denum type, 4370 ArrayBufferView* pixels) 4371 { 4372 if (!pixels) 4373 return true; 4374 4375 if (!validateTexFuncFormatAndType(format, type)) 4376 return false; 4377 4378 switch (type) { 4379 case GraphicsContext3D::UNSIGNED_BYTE: 4380 if (!pixels->isUnsignedByteArray()) { 4381 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4382 return false; 4383 } 4384 break; 4385 case GraphicsContext3D::UNSIGNED_SHORT_5_6_5: 4386 case GraphicsContext3D::UNSIGNED_SHORT_4_4_4_4: 4387 case GraphicsContext3D::UNSIGNED_SHORT_5_5_5_1: 4388 if (!pixels->isUnsignedShortArray()) { 4389 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4390 return false; 4391 } 4392 break; 4393 case GraphicsContext3D::FLOAT: // OES_texture_float 4394 if (!pixels->isFloatArray()) { 4395 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4396 return false; 4397 } 4398 break; 4399 default: 4400 ASSERT_NOT_REACHED(); 4401 } 4402 4403 unsigned int totalBytesRequired; 4404 GC3Denum error = m_context->computeImageSizeInBytes(format, type, width, height, m_unpackAlignment, &totalBytesRequired, 0); 4405 if (error != GraphicsContext3D::NO_ERROR) { 4406 m_context->synthesizeGLError(error); 4407 return false; 4408 } 4409 if (pixels->byteLength() < totalBytesRequired) { 4410 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4411 return false; 4412 } 4413 return true; 4414 } 4415 4416 bool WebGLRenderingContext::validateDrawMode(GC3Denum mode) 4417 { 4418 switch (mode) { 4419 case GraphicsContext3D::POINTS: 4420 case GraphicsContext3D::LINE_STRIP: 4421 case GraphicsContext3D::LINE_LOOP: 4422 case GraphicsContext3D::LINES: 4423 case GraphicsContext3D::TRIANGLE_STRIP: 4424 case GraphicsContext3D::TRIANGLE_FAN: 4425 case GraphicsContext3D::TRIANGLES: 4426 return true; 4427 default: 4428 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4429 return false; 4430 } 4431 } 4432 4433 bool WebGLRenderingContext::validateStencilSettings() 4434 { 4435 if (m_stencilMask != m_stencilMaskBack || m_stencilFuncRef != m_stencilFuncRefBack || m_stencilFuncMask != m_stencilFuncMaskBack) { 4436 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4437 return false; 4438 } 4439 return true; 4440 } 4441 4442 bool WebGLRenderingContext::validateStencilFunc(GC3Denum func) 4443 { 4444 switch (func) { 4445 case GraphicsContext3D::NEVER: 4446 case GraphicsContext3D::LESS: 4447 case GraphicsContext3D::LEQUAL: 4448 case GraphicsContext3D::GREATER: 4449 case GraphicsContext3D::GEQUAL: 4450 case GraphicsContext3D::EQUAL: 4451 case GraphicsContext3D::NOTEQUAL: 4452 case GraphicsContext3D::ALWAYS: 4453 return true; 4454 default: 4455 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4456 return false; 4457 } 4458 } 4459 4460 void WebGLRenderingContext::printWarningToConsole(const String& message) 4461 { 4462 canvas()->document()->frame()->domWindow()->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, 4463 message, 0, canvas()->document()->url().string()); 4464 } 4465 4466 bool WebGLRenderingContext::validateFramebufferFuncParameters(GC3Denum target, GC3Denum attachment) 4467 { 4468 if (target != GraphicsContext3D::FRAMEBUFFER) { 4469 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4470 return false; 4471 } 4472 switch (attachment) { 4473 case GraphicsContext3D::COLOR_ATTACHMENT0: 4474 case GraphicsContext3D::DEPTH_ATTACHMENT: 4475 case GraphicsContext3D::STENCIL_ATTACHMENT: 4476 case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT: 4477 break; 4478 default: 4479 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4480 return false; 4481 } 4482 return true; 4483 } 4484 4485 bool WebGLRenderingContext::validateBlendEquation(GC3Denum mode) 4486 { 4487 switch (mode) { 4488 case GraphicsContext3D::FUNC_ADD: 4489 case GraphicsContext3D::FUNC_SUBTRACT: 4490 case GraphicsContext3D::FUNC_REVERSE_SUBTRACT: 4491 return true; 4492 default: 4493 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4494 return false; 4495 } 4496 } 4497 4498 bool WebGLRenderingContext::validateBlendFuncFactors(GC3Denum src, GC3Denum dst) 4499 { 4500 if (((src == GraphicsContext3D::CONSTANT_COLOR || src == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR) 4501 && (dst == GraphicsContext3D::CONSTANT_ALPHA || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA)) 4502 || ((dst == GraphicsContext3D::CONSTANT_COLOR || dst == GraphicsContext3D::ONE_MINUS_CONSTANT_COLOR) 4503 && (src == GraphicsContext3D::CONSTANT_ALPHA || src == GraphicsContext3D::ONE_MINUS_CONSTANT_ALPHA))) { 4504 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4505 return false; 4506 } 4507 return true; 4508 } 4509 4510 bool WebGLRenderingContext::validateCapability(GC3Denum cap) 4511 { 4512 switch (cap) { 4513 case GraphicsContext3D::BLEND: 4514 case GraphicsContext3D::CULL_FACE: 4515 case GraphicsContext3D::DEPTH_TEST: 4516 case GraphicsContext3D::DITHER: 4517 case GraphicsContext3D::POLYGON_OFFSET_FILL: 4518 case GraphicsContext3D::SAMPLE_ALPHA_TO_COVERAGE: 4519 case GraphicsContext3D::SAMPLE_COVERAGE: 4520 case GraphicsContext3D::SCISSOR_TEST: 4521 case GraphicsContext3D::STENCIL_TEST: 4522 return true; 4523 default: 4524 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4525 return false; 4526 } 4527 } 4528 4529 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Float32Array* v, GC3Dsizei requiredMinSize) 4530 { 4531 if (!v) { 4532 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4533 return false; 4534 } 4535 return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize); 4536 } 4537 4538 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, Int32Array* v, GC3Dsizei requiredMinSize) 4539 { 4540 if (!v) { 4541 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4542 return false; 4543 } 4544 return validateUniformMatrixParameters(location, false, v->data(), v->length(), requiredMinSize); 4545 } 4546 4547 bool WebGLRenderingContext::validateUniformParameters(const WebGLUniformLocation* location, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize) 4548 { 4549 return validateUniformMatrixParameters(location, false, v, size, requiredMinSize); 4550 } 4551 4552 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, Float32Array* v, GC3Dsizei requiredMinSize) 4553 { 4554 if (!v) { 4555 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4556 return false; 4557 } 4558 return validateUniformMatrixParameters(location, transpose, v->data(), v->length(), requiredMinSize); 4559 } 4560 4561 bool WebGLRenderingContext::validateUniformMatrixParameters(const WebGLUniformLocation* location, GC3Dboolean transpose, void* v, GC3Dsizei size, GC3Dsizei requiredMinSize) 4562 { 4563 if (!location) 4564 return false; 4565 if (location->program() != m_currentProgram) { 4566 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4567 return false; 4568 } 4569 if (!v) { 4570 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4571 return false; 4572 } 4573 if (transpose) { 4574 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4575 return false; 4576 } 4577 if (size < requiredMinSize || (size % requiredMinSize)) { 4578 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4579 return false; 4580 } 4581 return true; 4582 } 4583 4584 WebGLBuffer* WebGLRenderingContext::validateBufferDataParameters(GC3Denum target, GC3Denum usage) 4585 { 4586 WebGLBuffer* buffer = 0; 4587 switch (target) { 4588 case GraphicsContext3D::ELEMENT_ARRAY_BUFFER: 4589 buffer = m_boundVertexArrayObject->getElementArrayBuffer().get(); 4590 break; 4591 case GraphicsContext3D::ARRAY_BUFFER: 4592 buffer = m_boundArrayBuffer.get(); 4593 break; 4594 default: 4595 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4596 return 0; 4597 } 4598 if (!buffer) { 4599 m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION); 4600 return 0; 4601 } 4602 switch (usage) { 4603 case GraphicsContext3D::STREAM_DRAW: 4604 case GraphicsContext3D::STATIC_DRAW: 4605 case GraphicsContext3D::DYNAMIC_DRAW: 4606 return buffer; 4607 } 4608 m_context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM); 4609 return 0; 4610 } 4611 4612 bool WebGLRenderingContext::validateHTMLImageElement(HTMLImageElement* image) 4613 { 4614 if (!image || !image->cachedImage()) { 4615 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4616 return false; 4617 } 4618 const KURL& url = image->cachedImage()->response().url(); 4619 if (url.isNull() || url.isEmpty() || !url.isValid()) { 4620 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4621 return false; 4622 } 4623 return true; 4624 } 4625 4626 void WebGLRenderingContext::vertexAttribfImpl(GC3Duint index, GC3Dsizei expectedSize, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3) 4627 { 4628 if (isContextLost()) 4629 return; 4630 if (index >= m_maxVertexAttribs) { 4631 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4632 return; 4633 } 4634 // In GL, we skip setting vertexAttrib0 values. 4635 if (index || isGLES2Compliant()) { 4636 switch (expectedSize) { 4637 case 1: 4638 m_context->vertexAttrib1f(index, v0); 4639 break; 4640 case 2: 4641 m_context->vertexAttrib2f(index, v0, v1); 4642 break; 4643 case 3: 4644 m_context->vertexAttrib3f(index, v0, v1, v2); 4645 break; 4646 case 4: 4647 m_context->vertexAttrib4f(index, v0, v1, v2, v3); 4648 break; 4649 } 4650 cleanupAfterGraphicsCall(false); 4651 } 4652 VertexAttribValue& attribValue = m_vertexAttribValue[index]; 4653 attribValue.value[0] = v0; 4654 attribValue.value[1] = v1; 4655 attribValue.value[2] = v2; 4656 attribValue.value[3] = v3; 4657 } 4658 4659 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, Float32Array* v, GC3Dsizei expectedSize) 4660 { 4661 if (isContextLost()) 4662 return; 4663 if (!v) { 4664 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4665 return; 4666 } 4667 vertexAttribfvImpl(index, v->data(), v->length(), expectedSize); 4668 } 4669 4670 void WebGLRenderingContext::vertexAttribfvImpl(GC3Duint index, GC3Dfloat* v, GC3Dsizei size, GC3Dsizei expectedSize) 4671 { 4672 if (isContextLost()) 4673 return; 4674 if (!v) { 4675 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4676 return; 4677 } 4678 if (size < expectedSize) { 4679 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4680 return; 4681 } 4682 if (index >= m_maxVertexAttribs) { 4683 m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE); 4684 return; 4685 } 4686 // In GL, we skip setting vertexAttrib0 values. 4687 if (index || isGLES2Compliant()) { 4688 switch (expectedSize) { 4689 case 1: 4690 m_context->vertexAttrib1fv(index, v); 4691 break; 4692 case 2: 4693 m_context->vertexAttrib2fv(index, v); 4694 break; 4695 case 3: 4696 m_context->vertexAttrib3fv(index, v); 4697 break; 4698 case 4: 4699 m_context->vertexAttrib4fv(index, v); 4700 break; 4701 } 4702 cleanupAfterGraphicsCall(false); 4703 } 4704 VertexAttribValue& attribValue = m_vertexAttribValue[index]; 4705 attribValue.initValue(); 4706 for (int ii = 0; ii < expectedSize; ++ii) 4707 attribValue.value[ii] = v[ii]; 4708 } 4709 4710 void WebGLRenderingContext::initVertexAttrib0() 4711 { 4712 WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0); 4713 4714 m_vertexAttrib0Buffer = createBuffer(); 4715 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object()); 4716 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, 0, GraphicsContext3D::DYNAMIC_DRAW); 4717 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, false, 0, 0); 4718 state.bufferBinding = m_vertexAttrib0Buffer; 4719 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, 0); 4720 m_context->enableVertexAttribArray(0); 4721 m_vertexAttrib0BufferSize = 0; 4722 m_vertexAttrib0BufferValue[0] = 0.0f; 4723 m_vertexAttrib0BufferValue[1] = 0.0f; 4724 m_vertexAttrib0BufferValue[2] = 0.0f; 4725 m_vertexAttrib0BufferValue[3] = 1.0f; 4726 m_forceAttrib0BufferRefill = false; 4727 m_vertexAttrib0UsedBefore = false; 4728 } 4729 4730 bool WebGLRenderingContext::simulateVertexAttrib0(GC3Dsizei numVertex) 4731 { 4732 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0); 4733 const VertexAttribValue& attribValue = m_vertexAttribValue[0]; 4734 if (!m_currentProgram) 4735 return false; 4736 bool usingVertexAttrib0 = m_currentProgram->isUsingVertexAttrib0(); 4737 if (usingVertexAttrib0) 4738 m_vertexAttrib0UsedBefore = true; 4739 if (state.enabled && usingVertexAttrib0) 4740 return false; 4741 if (!usingVertexAttrib0 && !m_vertexAttrib0UsedBefore) 4742 return false; 4743 m_vertexAttrib0UsedBefore = true; 4744 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, m_vertexAttrib0Buffer->object()); 4745 GC3Dsizeiptr bufferDataSize = (numVertex + 1) * 4 * sizeof(GC3Dfloat); 4746 if (bufferDataSize > m_vertexAttrib0BufferSize) { 4747 m_context->bufferData(GraphicsContext3D::ARRAY_BUFFER, bufferDataSize, 0, GraphicsContext3D::DYNAMIC_DRAW); 4748 m_vertexAttrib0BufferSize = bufferDataSize; 4749 m_forceAttrib0BufferRefill = true; 4750 } 4751 if (usingVertexAttrib0 4752 && (m_forceAttrib0BufferRefill 4753 || attribValue.value[0] != m_vertexAttrib0BufferValue[0] 4754 || attribValue.value[1] != m_vertexAttrib0BufferValue[1] 4755 || attribValue.value[2] != m_vertexAttrib0BufferValue[2] 4756 || attribValue.value[3] != m_vertexAttrib0BufferValue[3])) { 4757 OwnArrayPtr<GC3Dfloat> bufferData = adoptArrayPtr(new GC3Dfloat[(numVertex + 1) * 4]); 4758 for (GC3Dsizei ii = 0; ii < numVertex + 1; ++ii) { 4759 bufferData[ii * 4] = attribValue.value[0]; 4760 bufferData[ii * 4 + 1] = attribValue.value[1]; 4761 bufferData[ii * 4 + 2] = attribValue.value[2]; 4762 bufferData[ii * 4 + 3] = attribValue.value[3]; 4763 } 4764 m_vertexAttrib0BufferValue[0] = attribValue.value[0]; 4765 m_vertexAttrib0BufferValue[1] = attribValue.value[1]; 4766 m_vertexAttrib0BufferValue[2] = attribValue.value[2]; 4767 m_vertexAttrib0BufferValue[3] = attribValue.value[3]; 4768 m_forceAttrib0BufferRefill = false; 4769 m_context->bufferSubData(GraphicsContext3D::ARRAY_BUFFER, 0, bufferDataSize, bufferData.get()); 4770 } 4771 m_context->vertexAttribPointer(0, 4, GraphicsContext3D::FLOAT, 0, 0, 0); 4772 return true; 4773 } 4774 4775 void WebGLRenderingContext::restoreStatesAfterVertexAttrib0Simulation() 4776 { 4777 const WebGLVertexArrayObjectOES::VertexAttribState& state = m_boundVertexArrayObject->getVertexAttribState(0); 4778 if (state.bufferBinding != m_vertexAttrib0Buffer) { 4779 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(state.bufferBinding.get())); 4780 m_context->vertexAttribPointer(0, state.size, state.type, state.normalized, state.originalStride, state.offset); 4781 } 4782 m_context->bindBuffer(GraphicsContext3D::ARRAY_BUFFER, objectOrZero(m_boundArrayBuffer.get())); 4783 } 4784 4785 int WebGLRenderingContext::getNumberOfExtensions() 4786 { 4787 return (m_oesVertexArrayObject ? 1 : 0) + (m_oesStandardDerivatives ? 1 : 0) + (m_webkitLoseContext ? 1 : 0) + (m_oesTextureFloat ? 1 : 0); 4788 } 4789 4790 WebGLExtension* WebGLRenderingContext::getExtensionNumber(int i) 4791 { 4792 if (m_oesVertexArrayObject) { 4793 if (!i) 4794 return m_oesVertexArrayObject.get(); 4795 --i; 4796 } 4797 if (m_oesStandardDerivatives) { 4798 if (!i) 4799 return m_oesStandardDerivatives.get(); 4800 --i; 4801 } 4802 if (m_webkitLoseContext) { 4803 if (!i) 4804 return m_webkitLoseContext.get(); 4805 --i; 4806 } 4807 if (m_oesTextureFloat) { 4808 if (!i) 4809 return m_oesTextureFloat.get(); 4810 --i; 4811 } 4812 // Similar tests for other extensions would go here. 4813 return 0; 4814 } 4815 4816 WebGLRenderingContext::LRUImageBufferCache::LRUImageBufferCache(int capacity) 4817 : m_buffers(adoptArrayPtr(new OwnPtr<ImageBuffer>[capacity])) 4818 , m_capacity(capacity) 4819 { 4820 } 4821 4822 ImageBuffer* WebGLRenderingContext::LRUImageBufferCache::imageBuffer(const IntSize& size) 4823 { 4824 int i; 4825 for (i = 0; i < m_capacity; ++i) { 4826 ImageBuffer* buf = m_buffers[i].get(); 4827 if (!buf) 4828 break; 4829 if (buf->size() != size) 4830 continue; 4831 bubbleToFront(i); 4832 return buf; 4833 } 4834 4835 OwnPtr<ImageBuffer> temp = ImageBuffer::create(size); 4836 if (!temp) 4837 return 0; 4838 i = std::min(m_capacity - 1, i); 4839 m_buffers[i] = temp.release(); 4840 4841 ImageBuffer* buf = m_buffers[i].get(); 4842 bubbleToFront(i); 4843 return buf; 4844 } 4845 4846 void WebGLRenderingContext::LRUImageBufferCache::bubbleToFront(int idx) 4847 { 4848 for (int i = idx; i > 0; --i) 4849 m_buffers[i].swap(m_buffers[i-1]); 4850 } 4851 4852 } // namespace WebCore 4853 4854 #endif // ENABLE(WEBGL) 4855