Home | History | Annotate | Download | only in gpu
      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