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