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