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