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 <algorithm>
     36 #include "platform/TraceEvent.h"
     37 #include "platform/graphics/Extensions3D.h"
     38 #include "platform/graphics/GraphicsLayer.h"
     39 #include "public/platform/Platform.h"
     40 #include "public/platform/WebCompositorSupport.h"
     41 #include "public/platform/WebExternalBitmap.h"
     42 #include "public/platform/WebExternalTextureLayer.h"
     43 #include "public/platform/WebGraphicsContext3D.h"
     44 
     45 using namespace std;
     46 
     47 namespace WebCore {
     48 
     49 // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer creation and resize.
     50 // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() calls that would
     51 // exceed the global cap will instead clear the buffer.
     52 static const int s_maximumResourceUsePixels = 16 * 1024 * 1024;
     53 static int s_currentResourceUsePixels = 0;
     54 static const float s_resourceAdjustedRatio = 0.5;
     55 
     56 static const bool s_allowContextEvictionOnCreate = true;
     57 static const int s_maxScaleAttempts = 3;
     58 
     59 class ScopedTextureUnit0BindingRestorer {
     60 public:
     61     ScopedTextureUnit0BindingRestorer(GraphicsContext3D* context, GC3Denum activeTextureUnit, Platform3DObject textureUnitZeroId)
     62         : m_context(context)
     63         , m_oldActiveTextureUnit(activeTextureUnit)
     64         , m_oldTextureUnitZeroId(textureUnitZeroId)
     65     {
     66         m_context->activeTexture(GL_TEXTURE0);
     67     }
     68     ~ScopedTextureUnit0BindingRestorer()
     69     {
     70         m_context->bindTexture(GL_TEXTURE_2D, m_oldTextureUnitZeroId);
     71         m_context->activeTexture(m_oldActiveTextureUnit);
     72     }
     73 
     74 private:
     75     GraphicsContext3D* m_context;
     76     GC3Denum m_oldActiveTextureUnit;
     77     Platform3DObject m_oldTextureUnitZeroId;
     78 };
     79 
     80 PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager)
     81 {
     82     Extensions3D* extensions = context->extensions();
     83     bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit")
     84         && extensions->supports("GL_ANGLE_framebuffer_multisample")
     85         && extensions->supports("GL_OES_rgb8_rgba8");
     86     if (multisampleSupported) {
     87         extensions->ensureEnabled("GL_ANGLE_framebuffer_blit");
     88         extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample");
     89         extensions->ensureEnabled("GL_OES_rgb8_rgba8");
     90     }
     91     bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth_stencil");
     92     if (packedDepthStencilSupported)
     93         extensions->ensureEnabled("GL_OES_packed_depth_stencil");
     94 
     95     RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size, multisampleSupported, packedDepthStencilSupported, preserve, contextEvictionManager));
     96     return drawingBuffer.release();
     97 }
     98 
     99 DrawingBuffer::DrawingBuffer(GraphicsContext3D* context,
    100                              const IntSize& size,
    101                              bool multisampleExtensionSupported,
    102                              bool packedDepthStencilExtensionSupported,
    103                              PreserveDrawingBuffer preserve,
    104                              PassRefPtr<ContextEvictionManager> contextEvictionManager)
    105     : m_preserveDrawingBuffer(preserve)
    106     , m_scissorEnabled(false)
    107     , m_texture2DBinding(0)
    108     , m_framebufferBinding(0)
    109     , m_activeTextureUnit(GL_TEXTURE0)
    110     , m_context(context)
    111     , m_size(-1, -1)
    112     , m_multisampleExtensionSupported(multisampleExtensionSupported)
    113     , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported)
    114     , m_fbo(0)
    115     , m_colorBuffer(0)
    116     , m_frontColorBuffer(0)
    117     , m_depthStencilBuffer(0)
    118     , m_depthBuffer(0)
    119     , m_stencilBuffer(0)
    120     , m_multisampleFBO(0)
    121     , m_multisampleColorBuffer(0)
    122     , m_contentsChanged(true)
    123     , m_contentsChangeCommitted(false)
    124     , m_internalColorFormat(0)
    125     , m_colorFormat(0)
    126     , m_internalRenderbufferFormat(0)
    127     , m_maxTextureSize(0)
    128     , m_contextEvictionManager(contextEvictionManager)
    129 {
    130     // Used by browser tests to detect the use of a DrawingBuffer.
    131     TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation");
    132     initialize(size);
    133 }
    134 
    135 DrawingBuffer::~DrawingBuffer()
    136 {
    137     releaseResources();
    138 }
    139 
    140 void DrawingBuffer::markContentsChanged()
    141 {
    142     m_contentsChanged = true;
    143     m_contentsChangeCommitted = false;
    144 }
    145 
    146 blink::WebGraphicsContext3D* DrawingBuffer::context()
    147 {
    148     if (!m_context)
    149         return 0;
    150     return m_context->webContext();
    151 }
    152 
    153 bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap)
    154 {
    155     if (!m_context || !m_contentsChanged || !m_lastColorBuffer)
    156         return false;
    157 
    158     m_context->makeContextCurrent();
    159 
    160     // Resolve the multisampled buffer into the texture referenced by m_lastColorBuffer mailbox.
    161     if (multisample())
    162         commit();
    163 
    164     if (bitmap) {
    165         bitmap->setSize(size());
    166 
    167         unsigned char* pixels = bitmap->pixels();
    168         bool needPremultiply = m_attributes.alpha && !m_attributes.premultipliedAlpha;
    169         GraphicsContext3D::AlphaOp op = needPremultiply ? GraphicsContext3D::AlphaDoPremultiply : GraphicsContext3D::AlphaDoNothing;
    170         if (pixels)
    171             m_context->readBackFramebuffer(pixels, size().width(), size().height(), GraphicsContext3D::ReadbackSkia, op);
    172     }
    173 
    174     // We must restore the texture binding since creating new textures,
    175     // consuming and producing mailboxes changes it.
    176     ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding);
    177 
    178     // First try to recycle an old buffer.
    179     RefPtr<MailboxInfo> nextFrontColorBuffer = recycledMailbox();
    180 
    181     // No buffer available to recycle, create a new one.
    182     if (!nextFrontColorBuffer) {
    183         unsigned newColorBuffer = createColorTexture(m_size);
    184         // Bad things happened, abandon ship.
    185         if (!newColorBuffer)
    186             return false;
    187 
    188         nextFrontColorBuffer = createNewMailbox(newColorBuffer);
    189     }
    190 
    191     if (m_preserveDrawingBuffer == Discard) {
    192         m_colorBuffer = nextFrontColorBuffer->textureId;
    193         swap(nextFrontColorBuffer, m_lastColorBuffer);
    194         // It appears safe to overwrite the context's framebuffer binding in the Discard case since there will always be a
    195         // WebGLRenderingContext::clearIfComposited() call made before the next draw call which restores the framebuffer binding.
    196         // If this stops being true at some point, we should track the current framebuffer binding in the DrawingBuffer and restore
    197         // it after attaching the new back buffer here.
    198         m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    199         m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0);
    200     } else {
    201         Extensions3D* extensions = m_context->extensions();
    202         extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer, nextFrontColorBuffer->textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE);
    203     }
    204 
    205     if (multisample() && !m_framebufferBinding)
    206         bind();
    207     else
    208         restoreFramebufferBinding();
    209 
    210     m_contentsChanged = false;
    211 
    212     context()->bindTexture(GL_TEXTURE_2D, nextFrontColorBuffer->textureId);
    213     context()->produceTextureCHROMIUM(GL_TEXTURE_2D, nextFrontColorBuffer->mailbox.name);
    214     context()->flush();
    215     m_context->markLayerComposited();
    216 
    217     *outMailbox = nextFrontColorBuffer->mailbox;
    218     m_frontColorBuffer = nextFrontColorBuffer->textureId;
    219     return true;
    220 }
    221 
    222 void DrawingBuffer::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox)
    223 {
    224     for (size_t i = 0; i < m_textureMailboxes.size(); i++) {
    225          RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i];
    226          if (!memcmp(mailboxInfo->mailbox.name, mailbox.name, sizeof(mailbox.name))) {
    227              mailboxInfo->mailbox.syncPoint = mailbox.syncPoint;
    228              m_recycledMailboxes.append(mailboxInfo.release());
    229              return;
    230          }
    231      }
    232      ASSERT_NOT_REACHED();
    233 }
    234 
    235 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox()
    236 {
    237     if (!m_context || m_recycledMailboxes.isEmpty())
    238         return PassRefPtr<MailboxInfo>();
    239 
    240     RefPtr<MailboxInfo> mailboxInfo = m_recycledMailboxes.last().release();
    241     m_recycledMailboxes.removeLast();
    242 
    243     if (mailboxInfo->mailbox.syncPoint) {
    244         context()->waitSyncPoint(mailboxInfo->mailbox.syncPoint);
    245         mailboxInfo->mailbox.syncPoint = 0;
    246     }
    247 
    248     context()->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureId);
    249     context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->mailbox.name);
    250 
    251     if (mailboxInfo->size != m_size) {
    252         m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE);
    253         mailboxInfo->size = m_size;
    254     }
    255 
    256     return mailboxInfo.release();
    257 }
    258 
    259 PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(unsigned textureId)
    260 {
    261     RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo());
    262     context()->genMailboxCHROMIUM(returnMailbox->mailbox.name);
    263     returnMailbox->textureId = textureId;
    264     returnMailbox->size = m_size;
    265     m_textureMailboxes.append(returnMailbox);
    266     return returnMailbox.release();
    267 }
    268 
    269 void DrawingBuffer::initialize(const IntSize& size)
    270 {
    271     ASSERT(m_context);
    272     m_attributes = m_context->getContextAttributes();
    273 
    274     if (m_attributes.alpha) {
    275         m_internalColorFormat = GL_RGBA;
    276         m_colorFormat = GL_RGBA;
    277         m_internalRenderbufferFormat = Extensions3D::RGBA8_OES;
    278     } else {
    279         m_internalColorFormat = GL_RGB;
    280         m_colorFormat = GL_RGB;
    281         m_internalRenderbufferFormat = Extensions3D::RGB8_OES;
    282     }
    283 
    284     m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
    285 
    286     m_fbo = m_context->createFramebuffer();
    287 
    288     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    289     m_colorBuffer = createColorTexture();
    290     m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0);
    291     createSecondaryBuffers();
    292     reset(size);
    293     m_lastColorBuffer = createNewMailbox(m_colorBuffer);
    294 }
    295 
    296 unsigned DrawingBuffer::frontColorBuffer() const
    297 {
    298     return m_frontColorBuffer;
    299 }
    300 
    301 bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3DObject texture, GC3Denum internalFormat, GC3Denum destType, GC3Dint level, bool premultiplyAlpha, bool flipY)
    302 {
    303     if (!m_context || !m_context->makeContextCurrent())
    304         return false;
    305     if (m_contentsChanged) {
    306         if (multisample()) {
    307             commit();
    308             if (!m_framebufferBinding)
    309                 bind();
    310             else
    311                 restoreFramebufferBinding();
    312         }
    313         m_context->flush();
    314     }
    315     Platform3DObject sourceTexture = colorBuffer();
    316 
    317     if (!context.makeContextCurrent())
    318         return false;
    319     Extensions3D* extensions = context.extensions();
    320     if (!extensions->supports("GL_CHROMIUM_copy_texture") || !extensions->supports("GL_CHROMIUM_flipy")
    321         || !extensions->canUseCopyTextureCHROMIUM(internalFormat, destType, level))
    322         return false;
    323 
    324     bool unpackPremultiplyAlphaNeeded = false;
    325     bool unpackUnpremultiplyAlphaNeeded = false;
    326     if (m_attributes.alpha && m_attributes.premultipliedAlpha && !premultiplyAlpha)
    327         unpackUnpremultiplyAlphaNeeded = true;
    328     else if (m_attributes.alpha && !m_attributes.premultipliedAlpha && premultiplyAlpha)
    329         unpackPremultiplyAlphaNeeded = true;
    330 
    331     context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded);
    332     context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded);
    333     context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, flipY);
    334     extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType);
    335     context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, false);
    336     context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false);
    337     context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false);
    338     context.flush();
    339 
    340     return true;
    341 }
    342 
    343 Platform3DObject DrawingBuffer::framebuffer() const
    344 {
    345     return m_fbo;
    346 }
    347 
    348 blink::WebLayer* DrawingBuffer::platformLayer()
    349 {
    350     if (!m_context)
    351         return 0;
    352 
    353     if (!m_layer) {
    354         m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this));
    355 
    356         m_layer->setOpaque(!m_attributes.alpha);
    357         m_layer->setBlendBackgroundColor(m_attributes.alpha);
    358         m_layer->setPremultipliedAlpha(m_attributes.premultipliedAlpha);
    359         GraphicsLayer::registerContentsLayer(m_layer->layer());
    360     }
    361 
    362     return m_layer->layer();
    363 }
    364 
    365 void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer)
    366 {
    367     if (!m_context || !m_context->makeContextCurrent() || m_context->extensions()->getGraphicsResetStatusARB() != GL_NO_ERROR)
    368         return;
    369 
    370     Extensions3D* extensions = m_context->extensions();
    371 
    372     if (!imageBuffer)
    373         return;
    374     Platform3DObject tex = imageBuffer->getBackingTexture();
    375     if (tex) {
    376         extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer,
    377             tex, 0, GL_RGBA, GL_UNSIGNED_BYTE);
    378         return;
    379     }
    380 
    381     // Since the m_frontColorBuffer was produced and sent to the compositor, it cannot be bound to an fbo.
    382     // We have to make a copy of it here and bind that copy instead.
    383     // FIXME: That's not true any more, provided we don't change texture
    384     // parameters.
    385     unsigned sourceTexture = createColorTexture(m_size);
    386     extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE);
    387 
    388     // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding).
    389     // FIXME: The WebGLRenderingContext tracks the current framebuffer binding, it would be slightly more efficient to use this value
    390     // rather than querying it off of the context.
    391     GC3Dint previousFramebuffer = 0;
    392     m_context->getIntegerv(GL_FRAMEBUFFER_BINDING, &previousFramebuffer);
    393 
    394     Platform3DObject framebuffer = m_context->createFramebuffer();
    395     m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer);
    396     m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 0);
    397 
    398     extensions->paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_attributes.premultipliedAlpha, imageBuffer);
    399     m_context->deleteFramebuffer(framebuffer);
    400     m_context->deleteTexture(sourceTexture);
    401 
    402     m_context->bindFramebuffer(GL_FRAMEBUFFER, previousFramebuffer);
    403 }
    404 
    405 void DrawingBuffer::clearPlatformLayer()
    406 {
    407     if (m_layer)
    408         m_layer->clearTexture();
    409 
    410     if (m_context)
    411         m_context->flush();
    412 }
    413 
    414 void DrawingBuffer::releaseResources()
    415 {
    416     if (m_context) {
    417         m_context->makeContextCurrent();
    418 
    419         clearPlatformLayer();
    420 
    421         for (size_t i = 0; i < m_textureMailboxes.size(); i++)
    422             m_context->deleteTexture(m_textureMailboxes[i]->textureId);
    423 
    424         if (m_multisampleColorBuffer)
    425             m_context->deleteRenderbuffer(m_multisampleColorBuffer);
    426 
    427         if (m_depthStencilBuffer)
    428             m_context->deleteRenderbuffer(m_depthStencilBuffer);
    429 
    430         if (m_depthBuffer)
    431             m_context->deleteRenderbuffer(m_depthBuffer);
    432 
    433         if (m_stencilBuffer)
    434             m_context->deleteRenderbuffer(m_stencilBuffer);
    435 
    436         if (m_multisampleFBO)
    437             m_context->deleteFramebuffer(m_multisampleFBO);
    438 
    439         if (m_fbo)
    440             m_context->deleteFramebuffer(m_fbo);
    441 
    442         m_context.clear();
    443     }
    444 
    445     setSize(IntSize());
    446 
    447     m_colorBuffer = 0;
    448     m_frontColorBuffer = 0;
    449     m_multisampleColorBuffer = 0;
    450     m_depthStencilBuffer = 0;
    451     m_depthBuffer = 0;
    452     m_stencilBuffer = 0;
    453     m_multisampleFBO = 0;
    454     m_fbo = 0;
    455     m_contextEvictionManager.clear();
    456 
    457     m_lastColorBuffer.clear();
    458     m_recycledMailboxes.clear();
    459     m_textureMailboxes.clear();
    460 
    461     if (m_layer) {
    462         GraphicsLayer::unregisterContentsLayer(m_layer->layer());
    463         m_layer.clear();
    464     }
    465 }
    466 
    467 unsigned DrawingBuffer::createColorTexture(const IntSize& size)
    468 {
    469     if (!m_context)
    470         return 0;
    471 
    472     unsigned offscreenColorTexture = m_context->createTexture();
    473     if (!offscreenColorTexture)
    474         return 0;
    475 
    476     m_context->bindTexture(GL_TEXTURE_2D, offscreenColorTexture);
    477     m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    478     m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    479     m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    480     m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    481     if (!size.isEmpty())
    482         m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE);
    483 
    484     return offscreenColorTexture;
    485 }
    486 
    487 void DrawingBuffer::createSecondaryBuffers()
    488 {
    489     // create a multisample FBO
    490     if (multisample()) {
    491         m_multisampleFBO = m_context->createFramebuffer();
    492         m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
    493         m_multisampleColorBuffer = m_context->createRenderbuffer();
    494     }
    495 }
    496 
    497 bool DrawingBuffer::resizeFramebuffer(const IntSize& size)
    498 {
    499     // resize regular FBO
    500     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    501 
    502     m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer);
    503     m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE);
    504     if (m_lastColorBuffer)
    505         m_lastColorBuffer->size = size;
    506 
    507     m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0);
    508 
    509     m_context->bindTexture(GL_TEXTURE_2D, 0);
    510 
    511     if (!multisample())
    512         resizeDepthStencil(size, 0);
    513     if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    514         return false;
    515 
    516     return true;
    517 }
    518 
    519 bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size)
    520 {
    521     if (multisample()) {
    522         int maxSampleCount = 0;
    523 
    524         m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount);
    525         int sampleCount = std::min(4, maxSampleCount);
    526 
    527         m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
    528 
    529         m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleColorBuffer);
    530         m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, m_internalRenderbufferFormat, size.width(), size.height());
    531 
    532         if (m_context->getError() == GL_OUT_OF_MEMORY)
    533             return false;
    534 
    535         m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleColorBuffer);
    536         resizeDepthStencil(size, sampleCount);
    537         if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    538             return false;
    539     }
    540 
    541     return true;
    542 }
    543 
    544 void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount)
    545 {
    546     if (m_attributes.depth && m_attributes.stencil && m_packedDepthStencilExtensionSupported) {
    547         if (!m_depthStencilBuffer)
    548             m_depthStencilBuffer = m_context->createRenderbuffer();
    549         m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
    550         if (multisample())
    551             m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height());
    552         else
    553             m_context->renderbufferStorage(GL_RENDERBUFFER, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height());
    554         m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
    555         m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
    556     } else {
    557         if (m_attributes.depth) {
    558             if (!m_depthBuffer)
    559                 m_depthBuffer = m_context->createRenderbuffer();
    560             m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
    561             if (multisample())
    562                 m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height());
    563             else
    564                 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height());
    565             m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
    566         }
    567         if (m_attributes.stencil) {
    568             if (!m_stencilBuffer)
    569                 m_stencilBuffer = m_context->createRenderbuffer();
    570             m_context->bindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
    571             if (multisample())
    572                 m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_STENCIL_INDEX8, size.width(), size.height());
    573             else
    574                 m_context->renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size.width(), size.height());
    575             m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer);
    576         }
    577     }
    578     m_context->bindRenderbuffer(GL_RENDERBUFFER, 0);
    579 }
    580 
    581 
    582 
    583 void DrawingBuffer::clearFramebuffers(GC3Dbitfield clearMask)
    584 {
    585     if (!m_context)
    586         return;
    587 
    588     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
    589 
    590     m_context->clear(clearMask);
    591 
    592     // The multisample fbo was just cleared, but we also need to clear the non-multisampled buffer too.
    593     if (m_multisampleFBO) {
    594         m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    595         m_context->clear(GL_COLOR_BUFFER_BIT);
    596         m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
    597     }
    598 }
    599 
    600 void DrawingBuffer::setSize(const IntSize& size) {
    601     if (m_size == size)
    602         return;
    603 
    604     s_currentResourceUsePixels += pixelDelta(size);
    605     m_size = size;
    606 }
    607 
    608 int DrawingBuffer::pixelDelta(const IntSize& size) {
    609     return (max(0, size.width()) * max(0, size.height())) - (max(0, m_size.width()) * max(0, m_size.height()));
    610 }
    611 
    612 IntSize DrawingBuffer::adjustSize(const IntSize& size) {
    613     IntSize adjustedSize = size;
    614 
    615     // Clamp if the desired size is greater than the maximum texture size for the device.
    616     if (adjustedSize.height() > m_maxTextureSize)
    617         adjustedSize.setHeight(m_maxTextureSize);
    618 
    619     if (adjustedSize.width() > m_maxTextureSize)
    620         adjustedSize.setWidth(m_maxTextureSize);
    621 
    622     // Try progressively smaller sizes until we find a size that fits or reach a scale limit.
    623     int scaleAttempts = 0;
    624     while ((s_currentResourceUsePixels + pixelDelta(adjustedSize)) > s_maximumResourceUsePixels) {
    625         scaleAttempts++;
    626         if (scaleAttempts > s_maxScaleAttempts)
    627             return IntSize();
    628 
    629         adjustedSize.scale(s_resourceAdjustedRatio);
    630 
    631         if (adjustedSize.isEmpty())
    632             return IntSize();
    633     }
    634 
    635     return adjustedSize;
    636 }
    637 
    638 IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) {
    639     IntSize adjustedSize = adjustSize(size);
    640     if (!adjustedSize.isEmpty()) {
    641         evictContext = false;
    642         return adjustedSize; // Buffer fits without evicting a context.
    643     }
    644 
    645     // Speculatively adjust the pixel budget to see if the buffer would fit should the oldest context be evicted.
    646     IntSize oldestSize = m_contextEvictionManager->oldestContextSize();
    647     int pixelDelta = oldestSize.width() * oldestSize.height();
    648 
    649     s_currentResourceUsePixels -= pixelDelta;
    650     adjustedSize = adjustSize(size);
    651     s_currentResourceUsePixels += pixelDelta;
    652 
    653     evictContext = !adjustedSize.isEmpty();
    654     return adjustedSize;
    655 }
    656 
    657 void DrawingBuffer::reset(const IntSize& newSize)
    658 {
    659     if (!m_context)
    660         return;
    661 
    662     IntSize adjustedSize;
    663     bool evictContext = false;
    664     bool isNewContext = m_size.isEmpty();
    665     if (s_allowContextEvictionOnCreate && isNewContext)
    666         adjustedSize = adjustSizeWithContextEviction(newSize, evictContext);
    667     else
    668         adjustedSize = adjustSize(newSize);
    669 
    670     if (adjustedSize.isEmpty())
    671         return;
    672 
    673     if (evictContext)
    674         m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost.");
    675 
    676     if (adjustedSize != m_size) {
    677         do {
    678             // resize multisample FBO
    679             if (!resizeMultisampleFramebuffer(adjustedSize) || !resizeFramebuffer(adjustedSize)) {
    680                 adjustedSize.scale(s_resourceAdjustedRatio);
    681                 continue;
    682             }
    683             break;
    684         } while (!adjustedSize.isEmpty());
    685 
    686         setSize(adjustedSize);
    687 
    688         if (adjustedSize.isEmpty())
    689             return;
    690     }
    691 
    692     m_context->disable(GL_SCISSOR_TEST);
    693     m_context->clearColor(0, 0, 0, 0);
    694     m_context->colorMask(true, true, true, true);
    695 
    696     GC3Dbitfield clearMask = GL_COLOR_BUFFER_BIT;
    697     if (m_attributes.depth) {
    698         m_context->clearDepth(1.0f);
    699         clearMask |= GL_DEPTH_BUFFER_BIT;
    700         m_context->depthMask(true);
    701     }
    702     if (m_attributes.stencil) {
    703         m_context->clearStencil(0);
    704         clearMask |= GL_STENCIL_BUFFER_BIT;
    705         m_context->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
    706     }
    707 
    708     clearFramebuffers(clearMask);
    709 }
    710 
    711 void DrawingBuffer::commit(long x, long y, long width, long height)
    712 {
    713     if (!m_context)
    714         return;
    715 
    716     if (width < 0)
    717         width = m_size.width();
    718     if (height < 0)
    719         height = m_size.height();
    720 
    721     m_context->makeContextCurrent();
    722 
    723     if (m_multisampleFBO && !m_contentsChangeCommitted) {
    724         m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFBO);
    725         m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo);
    726 
    727         if (m_scissorEnabled)
    728             m_context->disable(GL_SCISSOR_TEST);
    729 
    730         // Use NEAREST, because there is no scale performed during the blit.
    731         m_context->extensions()->blitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    732 
    733         if (m_scissorEnabled)
    734             m_context->enable(GL_SCISSOR_TEST);
    735     }
    736 
    737     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo);
    738     m_contentsChangeCommitted = true;
    739 }
    740 
    741 void DrawingBuffer::restoreFramebufferBinding()
    742 {
    743     if (!m_context || !m_framebufferBinding)
    744         return;
    745 
    746     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding);
    747 }
    748 
    749 bool DrawingBuffer::multisample() const
    750 {
    751     return m_attributes.antialias && m_multisampleExtensionSupported;
    752 }
    753 
    754 void DrawingBuffer::bind()
    755 {
    756     if (!m_context)
    757         return;
    758 
    759     m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
    760 }
    761 
    762 } // namespace WebCore
    763