1 /* 2 * Copyright (c) 2010, Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 33 #include "platform/graphics/gpu/DrawingBuffer.h" 34 35 #include "platform/RuntimeEnabledFeatures.h" 36 #include <algorithm> 37 #include "platform/TraceEvent.h" 38 #include "platform/graphics/GraphicsLayer.h" 39 #include "platform/graphics/gpu/Extensions3DUtil.h" 40 #include "public/platform/Platform.h" 41 #include "public/platform/WebCompositorSupport.h" 42 #include "public/platform/WebExternalBitmap.h" 43 #include "public/platform/WebExternalTextureLayer.h" 44 #include "public/platform/WebGraphicsContext3D.h" 45 #include "public/platform/WebGraphicsContext3DProvider.h" 46 #ifndef NDEBUG 47 #include "wtf/RefCountedLeakCounter.h" 48 #endif 49 50 namespace blink { 51 52 namespace { 53 // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer creation and resize. 54 // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() calls that would 55 // exceed the global cap will instead clear the buffer. 56 const int s_maximumResourceUsePixels = 16 * 1024 * 1024; 57 int s_currentResourceUsePixels = 0; 58 const float s_resourceAdjustedRatio = 0.5; 59 60 const bool s_allowContextEvictionOnCreate = true; 61 const int s_maxScaleAttempts = 3; 62 63 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, drawingBufferCounter, ("DrawingBuffer")); 64 65 class ScopedTextureUnit0BindingRestorer { 66 public: 67 ScopedTextureUnit0BindingRestorer(WebGraphicsContext3D* context, GLenum activeTextureUnit, Platform3DObject textureUnitZeroId) 68 : m_context(context) 69 , m_oldActiveTextureUnit(activeTextureUnit) 70 , m_oldTextureUnitZeroId(textureUnitZeroId) 71 { 72 m_context->activeTexture(GL_TEXTURE0); 73 } 74 ~ScopedTextureUnit0BindingRestorer() 75 { 76 m_context->bindTexture(GL_TEXTURE_2D, m_oldTextureUnitZeroId); 77 m_context->activeTexture(m_oldActiveTextureUnit); 78 } 79 80 private: 81 WebGraphicsContext3D* m_context; 82 GLenum m_oldActiveTextureUnit; 83 Platform3DObject m_oldTextureUnitZeroId; 84 }; 85 86 } // namespace 87 88 PassRefPtr<DrawingBuffer> DrawingBuffer::create(PassOwnPtr<WebGraphicsContext3D> context, const IntSize& size, PreserveDrawingBuffer preserve, WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr<ContextEvictionManager> contextEvictionManager) 89 { 90 ASSERT(context); 91 OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get()); 92 if (!extensionsUtil) { 93 // This might be the first time we notice that the WebGraphicsContext3D is lost. 94 return nullptr; 95 } 96 bool multisampleSupported = extensionsUtil->supportsExtension("GL_CHROMIUM_framebuffer_multisample") 97 && extensionsUtil->supportsExtension("GL_OES_rgb8_rgba8"); 98 if (multisampleSupported) { 99 extensionsUtil->ensureExtensionEnabled("GL_CHROMIUM_framebuffer_multisample"); 100 extensionsUtil->ensureExtensionEnabled("GL_OES_rgb8_rgba8"); 101 } 102 bool packedDepthStencilSupported = extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil"); 103 if (packedDepthStencilSupported) 104 extensionsUtil->ensureExtensionEnabled("GL_OES_packed_depth_stencil"); 105 106 RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, extensionsUtil.release(), multisampleSupported, packedDepthStencilSupported, preserve, requestedAttributes, contextEvictionManager)); 107 if (!drawingBuffer->initialize(size)) { 108 drawingBuffer->beginDestruction(); 109 return PassRefPtr<DrawingBuffer>(); 110 } 111 return drawingBuffer.release(); 112 } 113 114 DrawingBuffer::DrawingBuffer(PassOwnPtr<WebGraphicsContext3D> context, 115 PassOwnPtr<Extensions3DUtil> extensionsUtil, 116 bool multisampleExtensionSupported, 117 bool packedDepthStencilExtensionSupported, 118 PreserveDrawingBuffer preserve, 119 WebGraphicsContext3D::Attributes requestedAttributes, 120 PassRefPtr<ContextEvictionManager> contextEvictionManager) 121 : m_preserveDrawingBuffer(preserve) 122 , m_scissorEnabled(false) 123 , m_texture2DBinding(0) 124 , m_framebufferBinding(0) 125 , m_activeTextureUnit(GL_TEXTURE0) 126 , m_context(context) 127 , m_extensionsUtil(extensionsUtil) 128 , m_size(-1, -1) 129 , m_requestedAttributes(requestedAttributes) 130 , m_multisampleExtensionSupported(multisampleExtensionSupported) 131 , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) 132 , m_fbo(0) 133 , m_depthStencilBuffer(0) 134 , m_depthBuffer(0) 135 , m_stencilBuffer(0) 136 , m_multisampleFBO(0) 137 , m_multisampleColorBuffer(0) 138 , m_contentsChanged(true) 139 , m_contentsChangeCommitted(false) 140 , m_layerComposited(false) 141 , m_multisampleMode(None) 142 , m_internalColorFormat(0) 143 , m_colorFormat(0) 144 , m_internalRenderbufferFormat(0) 145 , m_maxTextureSize(0) 146 , m_sampleCount(0) 147 , m_packAlignment(4) 148 , m_destructionInProgress(false) 149 , m_isHidden(false) 150 , m_contextEvictionManager(contextEvictionManager) 151 { 152 // Used by browser tests to detect the use of a DrawingBuffer. 153 TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation"); 154 #ifndef NDEBUG 155 drawingBufferCounter.increment(); 156 #endif 157 } 158 159 DrawingBuffer::~DrawingBuffer() 160 { 161 ASSERT(m_destructionInProgress); 162 ASSERT(m_textureMailboxes.isEmpty()); 163 m_layer.clear(); 164 m_context.clear(); 165 #ifndef NDEBUG 166 drawingBufferCounter.decrement(); 167 #endif 168 } 169 170 void DrawingBuffer::markContentsChanged() 171 { 172 m_contentsChanged = true; 173 m_contentsChangeCommitted = false; 174 m_layerComposited = false; 175 } 176 177 bool DrawingBuffer::layerComposited() const 178 { 179 return m_layerComposited; 180 } 181 182 void DrawingBuffer::markLayerComposited() 183 { 184 m_layerComposited = true; 185 } 186 187 WebGraphicsContext3D* DrawingBuffer::context() 188 { 189 return m_context.get(); 190 } 191 192 void DrawingBuffer::setIsHidden(bool hidden) 193 { 194 if (m_isHidden == hidden) 195 return; 196 m_isHidden = hidden; 197 if (m_isHidden) 198 freeRecycledMailboxes(); 199 } 200 201 void DrawingBuffer::freeRecycledMailboxes() 202 { 203 if (m_recycledMailboxQueue.isEmpty()) 204 return; 205 while (!m_recycledMailboxQueue.isEmpty()) 206 deleteMailbox(m_recycledMailboxQueue.takeLast()); 207 } 208 209 bool DrawingBuffer::prepareMailbox(WebExternalTextureMailbox* outMailbox, WebExternalBitmap* bitmap) 210 { 211 if (m_destructionInProgress) { 212 // It can be hit in the following sequence. 213 // 1. WebGL draws something. 214 // 2. The compositor begins the frame. 215 // 3. Javascript makes a context lost using WEBGL_lose_context extension. 216 // 4. Here. 217 return false; 218 } 219 ASSERT(!m_isHidden); 220 if (!m_contentsChanged) 221 return false; 222 223 // Resolve the multisampled buffer into m_colorBuffer texture. 224 if (m_multisampleMode != None) 225 commit(); 226 227 if (bitmap) { 228 bitmap->setSize(size()); 229 230 unsigned char* pixels = bitmap->pixels(); 231 bool needPremultiply = m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha; 232 WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing; 233 if (pixels) 234 readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op); 235 } 236 237 // We must restore the texture binding since creating new textures, 238 // consuming and producing mailboxes changes it. 239 ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding); 240 241 // First try to recycle an old buffer. 242 RefPtr<MailboxInfo> frontColorBufferMailbox = recycledMailbox(); 243 244 // No buffer available to recycle, create a new one. 245 if (!frontColorBufferMailbox) { 246 TextureInfo newTexture; 247 newTexture.textureId = createColorTexture(); 248 allocateTextureMemory(&newTexture, m_size); 249 // Bad things happened, abandon ship. 250 if (!newTexture.textureId) 251 return false; 252 253 frontColorBufferMailbox = createNewMailbox(newTexture); 254 } 255 256 if (m_preserveDrawingBuffer == Discard) { 257 std::swap(frontColorBufferMailbox->textureInfo, m_colorBuffer); 258 // It appears safe to overwrite the context's framebuffer binding in the Discard case since there will always be a 259 // WebGLRenderingContext::clearIfComposited() call made before the next draw call which restores the framebuffer binding. 260 // If this stops being true at some point, we should track the current framebuffer binding in the DrawingBuffer and restore 261 // it after attaching the new back buffer here. 262 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 263 if (m_multisampleMode == ImplicitResolve) 264 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); 265 else 266 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); 267 } else { 268 m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); 269 } 270 271 if (m_multisampleMode != None && !m_framebufferBinding) 272 bind(); 273 else 274 restoreFramebufferBinding(); 275 276 m_contentsChanged = false; 277 278 m_context->produceTextureDirectCHROMIUM(frontColorBufferMailbox->textureInfo.textureId, GL_TEXTURE_2D, frontColorBufferMailbox->mailbox.name); 279 m_context->flush(); 280 frontColorBufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); 281 frontColorBufferMailbox->mailbox.allowOverlay = frontColorBufferMailbox->textureInfo.imageId != 0; 282 markLayerComposited(); 283 284 // set m_parentDrawingBuffer to make sure 'this' stays alive as long as it has live mailboxes 285 ASSERT(!frontColorBufferMailbox->m_parentDrawingBuffer); 286 frontColorBufferMailbox->m_parentDrawingBuffer = this; 287 *outMailbox = frontColorBufferMailbox->mailbox; 288 m_frontColorBuffer = frontColorBufferMailbox->textureInfo; 289 return true; 290 } 291 292 void DrawingBuffer::mailboxReleased(const WebExternalTextureMailbox& mailbox, bool lostResource) 293 { 294 if (m_destructionInProgress || m_context->isContextLost() || lostResource || m_isHidden) { 295 mailboxReleasedWithoutRecycling(mailbox); 296 return; 297 } 298 299 for (size_t i = 0; i < m_textureMailboxes.size(); i++) { 300 RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; 301 if (nameEquals(mailboxInfo->mailbox, mailbox)) { 302 mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; 303 ASSERT(mailboxInfo->m_parentDrawingBuffer.get() == this); 304 mailboxInfo->m_parentDrawingBuffer.clear(); 305 m_recycledMailboxQueue.prepend(mailboxInfo->mailbox); 306 return; 307 } 308 } 309 ASSERT_NOT_REACHED(); 310 } 311 312 void DrawingBuffer::mailboxReleasedWithoutRecycling(const WebExternalTextureMailbox& mailbox) 313 { 314 ASSERT(m_textureMailboxes.size()); 315 // Ensure not to call the destructor until deleteMailbox() is completed. 316 RefPtr<DrawingBuffer> self = this; 317 deleteMailbox(mailbox); 318 } 319 320 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox() 321 { 322 if (m_recycledMailboxQueue.isEmpty()) 323 return PassRefPtr<MailboxInfo>(); 324 325 WebExternalTextureMailbox mailbox; 326 while (!m_recycledMailboxQueue.isEmpty()) { 327 mailbox = m_recycledMailboxQueue.takeLast(); 328 // Never have more than one mailbox in the released state. 329 if (!m_recycledMailboxQueue.isEmpty()) 330 deleteMailbox(mailbox); 331 } 332 333 RefPtr<MailboxInfo> mailboxInfo; 334 for (size_t i = 0; i < m_textureMailboxes.size(); i++) { 335 if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { 336 mailboxInfo = m_textureMailboxes[i]; 337 break; 338 } 339 } 340 ASSERT(mailboxInfo); 341 342 if (mailboxInfo->mailbox.syncPoint) { 343 m_context->waitSyncPoint(mailboxInfo->mailbox.syncPoint); 344 mailboxInfo->mailbox.syncPoint = 0; 345 } 346 347 if (mailboxInfo->size != m_size) { 348 m_context->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureInfo.textureId); 349 allocateTextureMemory(&mailboxInfo->textureInfo, m_size); 350 mailboxInfo->size = m_size; 351 } 352 353 return mailboxInfo.release(); 354 } 355 356 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(const TextureInfo& info) 357 { 358 RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo()); 359 m_context->genMailboxCHROMIUM(returnMailbox->mailbox.name); 360 returnMailbox->textureInfo = info; 361 returnMailbox->size = m_size; 362 m_textureMailboxes.append(returnMailbox); 363 return returnMailbox.release(); 364 } 365 366 void DrawingBuffer::deleteMailbox(const WebExternalTextureMailbox& mailbox) 367 { 368 for (size_t i = 0; i < m_textureMailboxes.size(); i++) { 369 if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { 370 if (mailbox.syncPoint) 371 m_context->waitSyncPoint(mailbox.syncPoint); 372 373 deleteChromiumImageForTexture(&m_textureMailboxes[i]->textureInfo); 374 375 m_context->deleteTexture(m_textureMailboxes[i]->textureInfo.textureId); 376 m_textureMailboxes.remove(i); 377 return; 378 } 379 } 380 ASSERT_NOT_REACHED(); 381 } 382 383 bool DrawingBuffer::initialize(const IntSize& size) 384 { 385 if (m_context->isContextLost()) { 386 // Need to try to restore the context again later. 387 return false; 388 } 389 390 if (m_requestedAttributes.alpha) { 391 m_internalColorFormat = GL_RGBA; 392 m_colorFormat = GL_RGBA; 393 m_internalRenderbufferFormat = GL_RGBA8_OES; 394 } else { 395 m_internalColorFormat = GL_RGB; 396 m_colorFormat = GL_RGB; 397 m_internalRenderbufferFormat = GL_RGB8_OES; 398 } 399 400 m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); 401 402 int maxSampleCount = 0; 403 m_multisampleMode = None; 404 if (m_requestedAttributes.antialias && m_multisampleExtensionSupported) { 405 m_context->getIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSampleCount); 406 m_multisampleMode = ExplicitResolve; 407 if (m_extensionsUtil->supportsExtension("GL_EXT_multisampled_render_to_texture")) 408 m_multisampleMode = ImplicitResolve; 409 } 410 m_sampleCount = std::min(4, maxSampleCount); 411 412 m_fbo = m_context->createFramebuffer(); 413 414 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 415 m_colorBuffer.textureId = createColorTexture(); 416 if (m_multisampleMode == ImplicitResolve) 417 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); 418 else 419 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); 420 createSecondaryBuffers(); 421 // We first try to initialize everything with the requested attributes. 422 if (!reset(size)) 423 return false; 424 // If that succeeds, we then see what we actually got and update our actual attributes to reflect that. 425 m_actualAttributes = m_requestedAttributes; 426 if (m_requestedAttributes.alpha) { 427 WGC3Dint alphaBits = 0; 428 m_context->getIntegerv(GL_ALPHA_BITS, &alphaBits); 429 m_actualAttributes.alpha = alphaBits > 0; 430 } 431 if (m_requestedAttributes.depth) { 432 WGC3Dint depthBits = 0; 433 m_context->getIntegerv(GL_DEPTH_BITS, &depthBits); 434 m_actualAttributes.depth = depthBits > 0; 435 } 436 if (m_requestedAttributes.stencil) { 437 WGC3Dint stencilBits = 0; 438 m_context->getIntegerv(GL_STENCIL_BITS, &stencilBits); 439 m_actualAttributes.stencil = stencilBits > 0; 440 } 441 m_actualAttributes.antialias = multisample(); 442 return true; 443 } 444 445 bool DrawingBuffer::copyToPlatformTexture(WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer) 446 { 447 GLint textureId = m_colorBuffer.textureId; 448 if (fromFrontBuffer && m_frontColorBuffer.textureId) 449 textureId = m_frontColorBuffer.textureId; 450 451 if (m_contentsChanged) { 452 if (m_multisampleMode != None) { 453 commit(); 454 if (!m_framebufferBinding) 455 bind(); 456 else 457 restoreFramebufferBinding(); 458 } 459 m_context->flush(); 460 } 461 462 if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level)) 463 return false; 464 465 // Contexts may be in a different share group. We must transfer the texture through a mailbox first 466 RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); 467 m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); 468 m_context->produceTextureDirectCHROMIUM(textureId, GL_TEXTURE_2D, bufferMailbox->mailbox.name); 469 m_context->flush(); 470 471 bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); 472 473 context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); 474 Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); 475 476 bool unpackPremultiplyAlphaNeeded = false; 477 bool unpackUnpremultiplyAlphaNeeded = false; 478 if (m_actualAttributes.alpha && m_actualAttributes.premultipliedAlpha && !premultiplyAlpha) 479 unpackUnpremultiplyAlphaNeeded = true; 480 else if (m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha && premultiplyAlpha) 481 unpackPremultiplyAlphaNeeded = true; 482 483 context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded); 484 context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded); 485 context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, flipY); 486 context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); 487 context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false); 488 context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); 489 context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); 490 491 context->deleteTexture(sourceTexture); 492 493 context->flush(); 494 m_context->waitSyncPoint(context->insertSyncPoint()); 495 496 return true; 497 } 498 499 Platform3DObject DrawingBuffer::framebuffer() const 500 { 501 return m_fbo; 502 } 503 504 WebLayer* DrawingBuffer::platformLayer() 505 { 506 if (!m_layer) { 507 m_layer = adoptPtr(Platform::current()->compositorSupport()->createExternalTextureLayer(this)); 508 509 m_layer->setOpaque(!m_actualAttributes.alpha); 510 m_layer->setBlendBackgroundColor(m_actualAttributes.alpha); 511 m_layer->setPremultipliedAlpha(m_actualAttributes.premultipliedAlpha); 512 GraphicsLayer::registerContentsLayer(m_layer->layer()); 513 } 514 515 return m_layer->layer(); 516 } 517 518 void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) 519 { 520 if (m_context->getGraphicsResetStatusARB() != GL_NO_ERROR) 521 return; 522 523 if (!imageBuffer) 524 return; 525 Platform3DObject tex = imageBuffer->getBackingTexture(); 526 if (tex) { 527 RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); 528 m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); 529 m_context->produceTextureDirectCHROMIUM(m_frontColorBuffer.textureId, GL_TEXTURE_2D, bufferMailbox->mailbox.name); 530 m_context->flush(); 531 532 bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); 533 OwnPtr<WebGraphicsContext3DProvider> provider = 534 adoptPtr(Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); 535 if (!provider) 536 return; 537 WebGraphicsContext3D* context = provider->context3d(); 538 if (!context) 539 return; 540 541 context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); 542 Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); 543 context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, 544 tex, 0, GL_RGBA, GL_UNSIGNED_BYTE); 545 context->deleteTexture(sourceTexture); 546 context->flush(); 547 m_context->waitSyncPoint(context->insertSyncPoint()); 548 imageBuffer->didModifyBackingTexture(); 549 550 return; 551 } 552 553 Platform3DObject framebuffer = m_context->createFramebuffer(); 554 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); 555 // We don't need to bind a copy of m_frontColorBuffer since the texture parameters are untouched. 556 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_frontColorBuffer.textureId, 0); 557 558 paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); 559 m_context->deleteFramebuffer(framebuffer); 560 // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding). 561 restoreFramebufferBinding(); 562 } 563 564 void DrawingBuffer::clearPlatformLayer() 565 { 566 if (m_layer) 567 m_layer->clearTexture(); 568 569 m_context->flush(); 570 } 571 572 void DrawingBuffer::beginDestruction() 573 { 574 ASSERT(!m_destructionInProgress); 575 m_destructionInProgress = true; 576 577 clearPlatformLayer(); 578 579 while (!m_recycledMailboxQueue.isEmpty()) 580 deleteMailbox(m_recycledMailboxQueue.takeLast()); 581 582 if (m_multisampleFBO) 583 m_context->deleteFramebuffer(m_multisampleFBO); 584 585 if (m_fbo) 586 m_context->deleteFramebuffer(m_fbo); 587 588 if (m_multisampleColorBuffer) 589 m_context->deleteRenderbuffer(m_multisampleColorBuffer); 590 591 if (m_depthStencilBuffer) 592 m_context->deleteRenderbuffer(m_depthStencilBuffer); 593 594 if (m_depthBuffer) 595 m_context->deleteRenderbuffer(m_depthBuffer); 596 597 if (m_stencilBuffer) 598 m_context->deleteRenderbuffer(m_stencilBuffer); 599 600 if (m_colorBuffer.textureId) { 601 deleteChromiumImageForTexture(&m_colorBuffer); 602 m_context->deleteTexture(m_colorBuffer.textureId); 603 } 604 605 setSize(IntSize()); 606 607 m_colorBuffer = TextureInfo(); 608 m_frontColorBuffer = TextureInfo(); 609 m_multisampleColorBuffer = 0; 610 m_depthStencilBuffer = 0; 611 m_depthBuffer = 0; 612 m_stencilBuffer = 0; 613 m_multisampleFBO = 0; 614 m_fbo = 0; 615 m_contextEvictionManager.clear(); 616 617 if (m_layer) 618 GraphicsLayer::unregisterContentsLayer(m_layer->layer()); 619 } 620 621 unsigned DrawingBuffer::createColorTexture() 622 { 623 unsigned offscreenColorTexture = m_context->createTexture(); 624 if (!offscreenColorTexture) 625 return 0; 626 627 m_context->bindTexture(GL_TEXTURE_2D, offscreenColorTexture); 628 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 629 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 630 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 631 m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 632 633 return offscreenColorTexture; 634 } 635 636 void DrawingBuffer::createSecondaryBuffers() 637 { 638 // create a multisample FBO 639 if (m_multisampleMode == ExplicitResolve) { 640 m_multisampleFBO = m_context->createFramebuffer(); 641 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); 642 m_multisampleColorBuffer = m_context->createRenderbuffer(); 643 } 644 } 645 646 bool DrawingBuffer::resizeFramebuffer(const IntSize& size) 647 { 648 // resize regular FBO 649 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 650 651 m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer.textureId); 652 653 allocateTextureMemory(&m_colorBuffer, size); 654 655 if (m_multisampleMode == ImplicitResolve) 656 m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); 657 else 658 m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); 659 660 m_context->bindTexture(GL_TEXTURE_2D, 0); 661 662 if (m_multisampleMode != ExplicitResolve) 663 resizeDepthStencil(size); 664 if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 665 return false; 666 667 return true; 668 } 669 670 bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) 671 { 672 if (m_multisampleMode == ExplicitResolve) { 673 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); 674 675 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleColorBuffer); 676 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, m_internalRenderbufferFormat, size.width(), size.height()); 677 678 if (m_context->getError() == GL_OUT_OF_MEMORY) 679 return false; 680 681 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleColorBuffer); 682 resizeDepthStencil(size); 683 if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 684 return false; 685 } 686 687 return true; 688 } 689 690 void DrawingBuffer::resizeDepthStencil(const IntSize& size) 691 { 692 if (!m_requestedAttributes.depth && !m_requestedAttributes.stencil) 693 return; 694 695 if (m_packedDepthStencilExtensionSupported) { 696 if (!m_depthStencilBuffer) 697 m_depthStencilBuffer = m_context->createRenderbuffer(); 698 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer); 699 if (m_multisampleMode == ImplicitResolve) 700 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); 701 else if (m_multisampleMode == ExplicitResolve) 702 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); 703 else 704 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); 705 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); 706 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); 707 } else { 708 if (m_requestedAttributes.depth) { 709 if (!m_depthBuffer) 710 m_depthBuffer = m_context->createRenderbuffer(); 711 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); 712 if (m_multisampleMode == ImplicitResolve) 713 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); 714 else if (m_multisampleMode == ExplicitResolve) 715 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); 716 else 717 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height()); 718 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); 719 } 720 if (m_requestedAttributes.stencil) { 721 if (!m_stencilBuffer) 722 m_stencilBuffer = m_context->createRenderbuffer(); 723 m_context->bindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer); 724 if (m_multisampleMode == ImplicitResolve) 725 m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); 726 else if (m_multisampleMode == ExplicitResolve) 727 m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); 728 else 729 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size.width(), size.height()); 730 m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer); 731 } 732 } 733 m_context->bindRenderbuffer(GL_RENDERBUFFER, 0); 734 } 735 736 737 738 void DrawingBuffer::clearFramebuffers(GLbitfield clearMask) 739 { 740 // We will clear the multisample FBO, but we also need to clear the non-multisampled buffer. 741 if (m_multisampleFBO) { 742 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 743 m_context->clear(GL_COLOR_BUFFER_BIT); 744 } 745 746 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); 747 m_context->clear(clearMask); 748 } 749 750 void DrawingBuffer::setSize(const IntSize& size) 751 { 752 if (m_size == size) 753 return; 754 755 s_currentResourceUsePixels += pixelDelta(size, m_size); 756 m_size = size; 757 } 758 759 int DrawingBuffer::pixelDelta(const IntSize& newSize, const IntSize& curSize) 760 { 761 return (std::max(0, newSize.width()) * std::max(0, newSize.height())) - (std::max(0, curSize.width()) * std::max(0, curSize.height())); 762 } 763 764 IntSize DrawingBuffer::adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize) 765 { 766 IntSize adjustedSize = desiredSize; 767 768 // Clamp if the desired size is greater than the maximum texture size for the device. 769 if (adjustedSize.height() > maxTextureSize) 770 adjustedSize.setHeight(maxTextureSize); 771 772 if (adjustedSize.width() > maxTextureSize) 773 adjustedSize.setWidth(maxTextureSize); 774 775 // Try progressively smaller sizes until we find a size that fits or reach a scale limit. 776 int scaleAttempts = 0; 777 while ((s_currentResourceUsePixels + pixelDelta(adjustedSize, curSize)) > s_maximumResourceUsePixels) { 778 scaleAttempts++; 779 if (scaleAttempts > s_maxScaleAttempts) 780 return IntSize(); 781 782 adjustedSize.scale(s_resourceAdjustedRatio); 783 784 if (adjustedSize.isEmpty()) 785 return IntSize(); 786 } 787 788 return adjustedSize; 789 } 790 791 IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) 792 { 793 IntSize adjustedSize = adjustSize(size, m_size, m_maxTextureSize); 794 if (!adjustedSize.isEmpty()) { 795 evictContext = false; 796 return adjustedSize; // Buffer fits without evicting a context. 797 } 798 799 // Speculatively adjust the pixel budget to see if the buffer would fit should the oldest context be evicted. 800 IntSize oldestSize = m_contextEvictionManager->oldestContextSize(); 801 int pixelDelta = oldestSize.width() * oldestSize.height(); 802 803 s_currentResourceUsePixels -= pixelDelta; 804 adjustedSize = adjustSize(size, m_size, m_maxTextureSize); 805 s_currentResourceUsePixels += pixelDelta; 806 807 evictContext = !adjustedSize.isEmpty(); 808 return adjustedSize; 809 } 810 811 bool DrawingBuffer::reset(const IntSize& newSize) 812 { 813 ASSERT(!newSize.isEmpty()); 814 IntSize adjustedSize; 815 bool evictContext = false; 816 bool isNewContext = m_size.isEmpty(); 817 if (s_allowContextEvictionOnCreate && isNewContext) 818 adjustedSize = adjustSizeWithContextEviction(newSize, evictContext); 819 else 820 adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize); 821 822 if (adjustedSize.isEmpty()) 823 return false; 824 825 if (evictContext) 826 m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost."); 827 828 if (adjustedSize != m_size) { 829 do { 830 // resize multisample FBO 831 if (!resizeMultisampleFramebuffer(adjustedSize) || !resizeFramebuffer(adjustedSize)) { 832 adjustedSize.scale(s_resourceAdjustedRatio); 833 continue; 834 } 835 break; 836 } while (!adjustedSize.isEmpty()); 837 838 setSize(adjustedSize); 839 840 if (adjustedSize.isEmpty()) 841 return false; 842 } 843 844 m_context->disable(GL_SCISSOR_TEST); 845 m_context->clearColor(0, 0, 0, 0); 846 m_context->colorMask(true, true, true, true); 847 848 GLbitfield clearMask = GL_COLOR_BUFFER_BIT; 849 if (m_actualAttributes.depth) { 850 m_context->clearDepth(1.0f); 851 clearMask |= GL_DEPTH_BUFFER_BIT; 852 m_context->depthMask(true); 853 } 854 if (m_actualAttributes.stencil) { 855 m_context->clearStencil(0); 856 clearMask |= GL_STENCIL_BUFFER_BIT; 857 m_context->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); 858 } 859 860 clearFramebuffers(clearMask); 861 return true; 862 } 863 864 void DrawingBuffer::commit(long x, long y, long width, long height) 865 { 866 if (width < 0) 867 width = m_size.width(); 868 if (height < 0) 869 height = m_size.height(); 870 871 if (m_multisampleFBO && !m_contentsChangeCommitted) { 872 m_context->bindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO); 873 m_context->bindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo); 874 875 if (m_scissorEnabled) 876 m_context->disable(GL_SCISSOR_TEST); 877 878 // Use NEAREST, because there is no scale performed during the blit. 879 m_context->blitFramebufferCHROMIUM(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); 880 881 if (m_scissorEnabled) 882 m_context->enable(GL_SCISSOR_TEST); 883 } 884 885 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); 886 m_contentsChangeCommitted = true; 887 } 888 889 void DrawingBuffer::restoreFramebufferBinding() 890 { 891 if (!m_framebufferBinding) 892 return; 893 894 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding); 895 } 896 897 bool DrawingBuffer::multisample() const 898 { 899 return m_multisampleMode != None; 900 } 901 902 void DrawingBuffer::bind() 903 { 904 m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); 905 } 906 907 void DrawingBuffer::setPackAlignment(GLint param) 908 { 909 m_packAlignment = param; 910 } 911 912 void DrawingBuffer::paintRenderingResultsToCanvas(ImageBuffer* imageBuffer) 913 { 914 paintFramebufferToCanvas(framebuffer(), size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); 915 } 916 917 PassRefPtr<Uint8ClampedArray> DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height) 918 { 919 if (m_actualAttributes.premultipliedAlpha) 920 return nullptr; 921 922 width = size().width(); 923 height = size().height(); 924 925 Checked<int, RecordOverflow> dataSize = 4; 926 dataSize *= width; 927 dataSize *= height; 928 if (dataSize.hasOverflowed()) 929 return nullptr; 930 931 RefPtr<Uint8ClampedArray> pixels = Uint8ClampedArray::createUninitialized(width * height * 4); 932 933 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer()); 934 readBackFramebuffer(pixels->data(), width, height, ReadbackRGBA, WebGLImageConversion::AlphaDoNothing); 935 flipVertically(pixels->data(), width, height); 936 937 return pixels.release(); 938 } 939 940 void DrawingBuffer::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) 941 { 942 unsigned char* pixels = 0; 943 944 const SkBitmap& canvasBitmap = imageBuffer->bitmap(); 945 const SkBitmap* readbackBitmap = 0; 946 ASSERT(canvasBitmap.colorType() == kN32_SkColorType); 947 if (canvasBitmap.width() == width && canvasBitmap.height() == height) { 948 // This is the fastest and most common case. We read back 949 // directly into the canvas's backing store. 950 readbackBitmap = &canvasBitmap; 951 m_resizingBitmap.reset(); 952 } else { 953 // We need to allocate a temporary bitmap for reading back the 954 // pixel data. We will then use Skia to rescale this bitmap to 955 // the size of the canvas's backing store. 956 if (m_resizingBitmap.width() != width || m_resizingBitmap.height() != height) { 957 if (!m_resizingBitmap.tryAllocN32Pixels(width, height)) 958 return; 959 } 960 readbackBitmap = &m_resizingBitmap; 961 } 962 963 // Read back the frame buffer. 964 SkAutoLockPixels bitmapLock(*readbackBitmap); 965 pixels = static_cast<unsigned char*>(readbackBitmap->getPixels()); 966 967 m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); 968 readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing); 969 flipVertically(pixels, width, height); 970 971 readbackBitmap->notifyPixelsChanged(); 972 if (m_resizingBitmap.readyToDraw()) { 973 // We need to draw the resizing bitmap into the canvas's backing store. 974 SkCanvas canvas(canvasBitmap); 975 SkRect dst; 976 dst.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(canvasBitmap.width()), SkIntToScalar(canvasBitmap.height())); 977 canvas.drawBitmapRect(m_resizingBitmap, 0, dst); 978 } 979 } 980 981 void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, WebGLImageConversion::AlphaOp op) 982 { 983 if (m_packAlignment > 4) 984 m_context->pixelStorei(GL_PACK_ALIGNMENT, 1); 985 m_context->readPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 986 if (m_packAlignment > 4) 987 m_context->pixelStorei(GL_PACK_ALIGNMENT, m_packAlignment); 988 989 size_t bufferSize = 4 * width * height; 990 991 if (readbackOrder == ReadbackSkia) { 992 #if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT 993 // Swizzle red and blue channels to match SkBitmap's byte ordering. 994 // TODO(kbr): expose GL_BGRA as extension. 995 for (size_t i = 0; i < bufferSize; i += 4) { 996 std::swap(pixels[i], pixels[i + 2]); 997 } 998 #endif 999 } 1000 1001 if (op == WebGLImageConversion::AlphaDoPremultiply) { 1002 for (size_t i = 0; i < bufferSize; i += 4) { 1003 pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); 1004 pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); 1005 pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); 1006 } 1007 } else if (op != WebGLImageConversion::AlphaDoNothing) { 1008 ASSERT_NOT_REACHED(); 1009 } 1010 } 1011 1012 void DrawingBuffer::flipVertically(uint8_t* framebuffer, int width, int height) 1013 { 1014 m_scanline.resize(width * 4); 1015 uint8* scanline = &m_scanline[0]; 1016 unsigned rowBytes = width * 4; 1017 unsigned count = height / 2; 1018 for (unsigned i = 0; i < count; i++) { 1019 uint8* rowA = framebuffer + i * rowBytes; 1020 uint8* rowB = framebuffer + (height - i - 1) * rowBytes; 1021 memcpy(scanline, rowB, rowBytes); 1022 memcpy(rowB, rowA, rowBytes); 1023 memcpy(rowA, scanline, rowBytes); 1024 } 1025 } 1026 1027 void DrawingBuffer::texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint unpackAlignment) 1028 { 1029 ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8); 1030 m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0); 1031 } 1032 1033 void DrawingBuffer::allocateTextureMemory(TextureInfo* info, const IntSize& size) 1034 { 1035 if (RuntimeEnabledFeatures::webGLImageChromiumEnabled()) { 1036 deleteChromiumImageForTexture(info); 1037 1038 info->imageId = m_context->createImageCHROMIUM(size.width(), size.height(), GL_RGBA8_OES, GC3D_IMAGE_SCANOUT_CHROMIUM); 1039 if (info->imageId) { 1040 m_context->bindTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); 1041 return; 1042 } 1043 } 1044 1045 texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); 1046 } 1047 1048 void DrawingBuffer::deleteChromiumImageForTexture(TextureInfo* info) 1049 { 1050 if (info->imageId) { 1051 m_context->releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); 1052 m_context->destroyImageCHROMIUM(info->imageId); 1053 info->imageId = 0; 1054 } 1055 } 1056 1057 } // namespace blink 1058