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 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