| Index: third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp | 
| diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp | 
| index 3f203e79ab4e1599738b39018414a486acfb5f5c..9ba469948d72a2b9a97fab0cd50a2f9c12282000 100644 | 
| --- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp | 
| +++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp | 
| @@ -60,36 +60,13 @@ namespace { | 
|  | 
| const float s_resourceAdjustedRatio = 0.5; | 
|  | 
| -class ScopedTextureUnit0BindingRestorer { | 
| -  STACK_ALLOCATED(); | 
| -  WTF_MAKE_NONCOPYABLE(ScopedTextureUnit0BindingRestorer); | 
| - | 
| - public: | 
| -  ScopedTextureUnit0BindingRestorer(gpu::gles2::GLES2Interface* gl, | 
| -                                    GLenum activeTextureUnit, | 
| -                                    GLuint textureUnitZeroId) | 
| -      : m_gl(gl), | 
| -        m_oldActiveTextureUnit(activeTextureUnit), | 
| -        m_oldTextureUnitZeroId(textureUnitZeroId) { | 
| -    m_gl->ActiveTexture(GL_TEXTURE0); | 
| -  } | 
| -  ~ScopedTextureUnit0BindingRestorer() { | 
| -    m_gl->BindTexture(GL_TEXTURE_2D, m_oldTextureUnitZeroId); | 
| -    m_gl->ActiveTexture(m_oldActiveTextureUnit); | 
| -  } | 
| - | 
| - private: | 
| -  gpu::gles2::GLES2Interface* m_gl; | 
| -  GLenum m_oldActiveTextureUnit; | 
| -  GLuint m_oldTextureUnitZeroId; | 
| -}; | 
| - | 
| static bool shouldFailDrawingBufferCreationForTesting = false; | 
|  | 
| }  // namespace | 
|  | 
| PassRefPtr<DrawingBuffer> DrawingBuffer::create( | 
| std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, | 
| +    DrawingBufferStateTracker* drawingBufferRestoreSource, | 
| const IntSize& size, | 
| bool premultipliedAlpha, | 
| bool wantAlphaChannel, | 
| @@ -137,9 +114,9 @@ PassRefPtr<DrawingBuffer> DrawingBuffer::create( | 
|  | 
| RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer( | 
| std::move(contextProvider), std::move(extensionsUtil), | 
| -      discardFramebufferSupported, wantAlphaChannel, premultipliedAlpha, | 
| -      preserve, webGLVersion, wantDepthBuffer, wantStencilBuffer, | 
| -      chromiumImageUsage)); | 
| +      drawingBufferRestoreSource, discardFramebufferSupported, wantAlphaChannel, | 
| +      premultipliedAlpha, preserve, webGLVersion, wantDepthBuffer, | 
| +      wantStencilBuffer, chromiumImageUsage)); | 
| if (!drawingBuffer->initialize(size, multisampleSupported)) { | 
| drawingBuffer->beginDestruction(); | 
| return PassRefPtr<DrawingBuffer>(); | 
| @@ -154,6 +131,7 @@ void DrawingBuffer::forceNextDrawingBufferCreationToFail() { | 
| DrawingBuffer::DrawingBuffer( | 
| std::unique_ptr<WebGraphicsContext3DProvider> contextProvider, | 
| std::unique_ptr<Extensions3DUtil> extensionsUtil, | 
| +    DrawingBufferStateTracker* stateTracker, | 
| bool discardFramebufferSupported, | 
| bool wantAlphaChannel, | 
| bool premultipliedAlpha, | 
| @@ -162,7 +140,8 @@ DrawingBuffer::DrawingBuffer( | 
| bool wantDepth, | 
| bool wantStencil, | 
| ChromiumImageUsage chromiumImageUsage) | 
| -    : m_preserveDrawingBuffer(preserve), | 
| +    : m_stateTracker(stateTracker), | 
| +      m_preserveDrawingBuffer(preserve), | 
| m_webGLVersion(webGLVersion), | 
| m_contextProvider(std::move(contextProvider)), | 
| m_gl(m_contextProvider->contextGL()), | 
| @@ -174,8 +153,6 @@ DrawingBuffer::DrawingBuffer( | 
| m_wantDepth(wantDepth), | 
| m_wantStencil(wantStencil), | 
| m_chromiumImageUsage(chromiumImageUsage) { | 
| -  memset(m_colorMask, 0, 4 * sizeof(GLboolean)); | 
| -  memset(m_clearColor, 0, 4 * sizeof(GLfloat)); | 
| // Used by browser tests to detect the use of a DrawingBuffer. | 
| TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation", | 
| TRACE_EVENT_SCOPE_GLOBAL); | 
| @@ -217,7 +194,7 @@ void DrawingBuffer::setIsHidden(bool hidden) { | 
| return; | 
| m_isHidden = hidden; | 
| if (m_isHidden) | 
| -    m_recycledMailboxQueue.clear(); | 
| +    m_recycledColorBufferQueue.clear(); | 
| } | 
|  | 
| void DrawingBuffer::setFilterQuality(SkFilterQuality filterQuality) { | 
| @@ -229,7 +206,9 @@ void DrawingBuffer::setFilterQuality(SkFilterQuality filterQuality) { | 
| } | 
|  | 
| bool DrawingBuffer::requiresAlphaChannelToBePreserved() { | 
| -  return !m_drawFramebufferBinding && | 
| +  DrawingBufferRestoreState restoreState; | 
| +  m_stateTracker->GetDrawingBufferRestoreState(&restoreState); | 
| +  return !restoreState.drawFramebufferBinding && | 
| defaultBufferRequiresAlphaChannelToBePreserved(); | 
| } | 
|  | 
| @@ -265,6 +244,7 @@ std::unique_ptr<cc::SharedBitmap> DrawingBuffer::createOrRecycleBitmap() { | 
| bool DrawingBuffer::PrepareTextureMailbox( | 
| cc::TextureMailbox* outMailbox, | 
| std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| bool forceGpuResult = false; | 
| return prepareTextureMailboxInternal(outMailbox, outReleaseCallback, | 
| forceGpuResult); | 
| @@ -299,107 +279,124 @@ bool DrawingBuffer::prepareTextureMailboxInternal( | 
|  | 
| // Resolve the multisampled buffer into m_backColorBuffer texture. | 
| if (m_antiAliasingMode != None) | 
| -    commit(); | 
| +    resolveMultisampleFramebufferInternal(); | 
|  | 
| if (m_softwareRendering && !forceGpuResult) { | 
| -    std::unique_ptr<cc::SharedBitmap> bitmap = createOrRecycleBitmap(); | 
| -    if (!bitmap) | 
| -      return false; | 
| +    return finishPrepareTextureMailboxSoftware(outMailbox, outReleaseCallback); | 
| +  } else { | 
| +    return finishPrepareTextureMailboxGpu(outMailbox, outReleaseCallback); | 
| +  } | 
| +} | 
| + | 
| +bool DrawingBuffer::finishPrepareTextureMailboxSoftware( | 
| +    cc::TextureMailbox* outMailbox, | 
| +    std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) { | 
| +  std::unique_ptr<cc::SharedBitmap> bitmap = createOrRecycleBitmap(); | 
| +  if (!bitmap) | 
| +    return false; | 
| + | 
| +  // Read the framebuffer into |bitmap|. | 
| +  { | 
| unsigned char* pixels = bitmap->pixels(); | 
| DCHECK(pixels); | 
| - | 
| bool needPremultiply = m_wantAlphaChannel && !m_premultipliedAlpha; | 
| WebGLImageConversion::AlphaOp op = | 
| needPremultiply ? WebGLImageConversion::AlphaDoPremultiply | 
| : WebGLImageConversion::AlphaDoNothing; | 
| readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, | 
| op); | 
| +  } | 
|  | 
| -    *outMailbox = cc::TextureMailbox(bitmap.get(), m_size); | 
| +  *outMailbox = cc::TextureMailbox(bitmap.get(), m_size); | 
|  | 
| -    // This holds a ref on the DrawingBuffer that will keep it alive until the | 
| -    // mailbox is released (and while the release callback is running). It also | 
| -    // owns the SharedBitmap. | 
| -    auto func = WTF::bind(&DrawingBuffer::softwareMailboxReleased, | 
| -                          RefPtr<DrawingBuffer>(this), | 
| -                          WTF::passed(std::move(bitmap)), m_size); | 
| -    *outReleaseCallback = cc::SingleReleaseCallback::Create( | 
| -        convertToBaseCallback(std::move(func))); | 
| -    return true; | 
| -  } | 
| +  // This holds a ref on the DrawingBuffer that will keep it alive until the | 
| +  // mailbox is released (and while the release callback is running). It also | 
| +  // owns the SharedBitmap. | 
| +  auto func = WTF::bind(&DrawingBuffer::mailboxReleasedSoftware, | 
| +                        RefPtr<DrawingBuffer>(this), | 
| +                        WTF::passed(std::move(bitmap)), m_size); | 
| +  *outReleaseCallback = | 
| +      cc::SingleReleaseCallback::Create(convertToBaseCallback(std::move(func))); | 
| +  return true; | 
| +} | 
|  | 
| +bool DrawingBuffer::finishPrepareTextureMailboxGpu( | 
| +    cc::TextureMailbox* outMailbox, | 
| +    std::unique_ptr<cc::SingleReleaseCallback>* outReleaseCallback) { | 
| if (m_webGLVersion > WebGL1) { | 
| +    m_stateRestorer->setPixelUnpackBufferBindingDirty(); | 
| m_gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); | 
| } | 
|  | 
| -  // We must restore the texture binding since creating new textures, | 
| -  // consuming and producing mailboxes changes it. | 
| -  ScopedTextureUnit0BindingRestorer restorer(m_gl, m_activeTextureUnit, | 
| -                                             m_texture2DBinding); | 
| - | 
| -  // First try to recycle an old buffer. | 
| -  RefPtr<ColorBuffer> colorBufferForMailbox = takeRecycledMailbox(); | 
| - | 
| -  // No buffer available to recycle, create a new one. | 
| -  if (!colorBufferForMailbox) | 
| -    colorBufferForMailbox = createTextureAndAllocateMemory(m_size); | 
| - | 
| +  // Specify the buffer that we will put in the mailbox. | 
| +  RefPtr<ColorBuffer> colorBufferForMailbox; | 
| if (m_preserveDrawingBuffer == Discard) { | 
| -    std::swap(colorBufferForMailbox, m_backColorBuffer); | 
| +    // If we can discard the backbuffer, send the old backbuffer directly | 
| +    // into the mailbox, and allocate (or recycle) a new backbuffer. | 
| +    colorBufferForMailbox = m_backColorBuffer; | 
| +    m_backColorBuffer = createOrRecycleColorBuffer(); | 
| attachColorBufferToReadFramebuffer(); | 
|  | 
| +    // Explicitly specify that m_fbo (which is now bound to the just-allocated | 
| +    // m_backColorBuffer) is not initialized, to save GPU memory bandwidth for | 
| +    // tile-based GPU architectures. | 
| if (m_discardFramebufferSupported) { | 
| -      // Explicitly discard the framebuffer to save GPU memory bandwidth for | 
| -      // tile-based GPU arch. | 
| const GLenum attachments[3] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, | 
| GL_STENCIL_ATTACHMENT}; | 
| +      m_stateRestorer->setFramebufferBindingDirty(); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| m_gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments); | 
| } | 
| } else { | 
| +    // If we can't discard the backbuffer, create (or recycle) a buffer to put | 
| +    // in the mailbox, and copy backbuffer's contents there. | 
| +    colorBufferForMailbox = createOrRecycleColorBuffer(); | 
| m_gl->CopySubTextureCHROMIUM( | 
| m_backColorBuffer->textureId, colorBufferForMailbox->textureId, 0, 0, 0, | 
| 0, m_size.width(), m_size.height(), GL_FALSE, GL_FALSE, GL_FALSE); | 
| } | 
|  | 
| -  restoreFramebufferBindings(); | 
| -  restorePixelUnpackBufferBindings(); | 
| -  m_contentsChanged = false; | 
| - | 
| -  m_gl->ProduceTextureDirectCHROMIUM(colorBufferForMailbox->textureId, | 
| -                                     colorBufferForMailbox->parameters.target, | 
| -                                     colorBufferForMailbox->mailbox.name); | 
| -  const GLuint64 fenceSync = m_gl->InsertFenceSyncCHROMIUM(); | 
| +  // Put colorBufferForMailbox into its mailbox, and populate its | 
| +  // produceSyncToken with that point. | 
| +  { | 
| +    m_gl->ProduceTextureDirectCHROMIUM(colorBufferForMailbox->textureId, | 
| +                                       colorBufferForMailbox->parameters.target, | 
| +                                       colorBufferForMailbox->mailbox.name); | 
| +    const GLuint64 fenceSync = m_gl->InsertFenceSyncCHROMIUM(); | 
| #if OS(MACOSX) | 
| -  m_gl->DescheduleUntilFinishedCHROMIUM(); | 
| +    m_gl->DescheduleUntilFinishedCHROMIUM(); | 
| #endif | 
| -  m_gl->Flush(); | 
| -  gpu::SyncToken syncToken; | 
| -  m_gl->GenSyncTokenCHROMIUM(fenceSync, syncToken.GetData()); | 
| +    m_gl->Flush(); | 
| +    m_gl->GenSyncTokenCHROMIUM( | 
| +        fenceSync, colorBufferForMailbox->produceSyncToken.GetData()); | 
| +  } | 
|  | 
| -  bool isOverlayCandidate = colorBufferForMailbox->imageId != 0; | 
| -  bool secureOutputOnly = false; | 
| -  *outMailbox = cc::TextureMailbox(colorBufferForMailbox->mailbox, syncToken, | 
| -                                   colorBufferForMailbox->parameters.target, | 
| -                                   gfx::Size(m_size.width(), m_size.height()), | 
| -                                   isOverlayCandidate, secureOutputOnly); | 
| +  // Populate the output mailbox and callback. | 
| +  { | 
| +    bool isOverlayCandidate = colorBufferForMailbox->imageId != 0; | 
| +    bool secureOutputOnly = false; | 
| +    *outMailbox = cc::TextureMailbox( | 
| +        colorBufferForMailbox->mailbox, colorBufferForMailbox->produceSyncToken, | 
| +        colorBufferForMailbox->parameters.target, gfx::Size(m_size), | 
| +        isOverlayCandidate, secureOutputOnly); | 
|  | 
| -  // This holds a ref on the DrawingBuffer that will keep it alive until the | 
| -  // mailbox is released (and while the release callback is running). | 
| -  auto func = WTF::bind(&DrawingBuffer::gpuMailboxReleased, | 
| -                        RefPtr<DrawingBuffer>(this), colorBufferForMailbox); | 
| -  *outReleaseCallback = | 
| -      cc::SingleReleaseCallback::Create(convertToBaseCallback(std::move(func))); | 
| +    // This holds a ref on the DrawingBuffer that will keep it alive until the | 
| +    // mailbox is released (and while the release callback is running). | 
| +    auto func = WTF::bind(&DrawingBuffer::mailboxReleasedGpu, | 
| +                          RefPtr<DrawingBuffer>(this), colorBufferForMailbox); | 
| +    *outReleaseCallback = cc::SingleReleaseCallback::Create( | 
| +        convertToBaseCallback(std::move(func))); | 
| +  } | 
|  | 
| -  // Point |m_frontColorBuffer| to the buffer that we are presenting, and | 
| -  // update its sync token. | 
| -  colorBufferForMailbox->produceSyncToken = syncToken; | 
| +  // Point |m_frontColorBuffer| to the buffer that we are now presenting. | 
| m_frontColorBuffer = colorBufferForMailbox; | 
| + | 
| +  m_contentsChanged = false; | 
| setBufferClearNeeded(true); | 
| return true; | 
| } | 
|  | 
| -void DrawingBuffer::gpuMailboxReleased(RefPtr<ColorBuffer> colorBuffer, | 
| +void DrawingBuffer::mailboxReleasedGpu(RefPtr<ColorBuffer> colorBuffer, | 
| const gpu::SyncToken& syncToken, | 
| bool lostResource) { | 
| // If the mailbox has been returned by the compositor then it is no | 
| @@ -422,13 +419,13 @@ void DrawingBuffer::gpuMailboxReleased(RefPtr<ColorBuffer> colorBuffer, | 
| size_t cacheLimit = 1; | 
| if (shouldUseChromiumImage()) | 
| cacheLimit = 4; | 
| -  while (m_recycledMailboxQueue.size() >= cacheLimit) | 
| -    m_recycledMailboxQueue.takeLast(); | 
| +  while (m_recycledColorBufferQueue.size() >= cacheLimit) | 
| +    m_recycledColorBufferQueue.takeLast(); | 
|  | 
| -  m_recycledMailboxQueue.prepend(colorBuffer); | 
| +  m_recycledColorBufferQueue.prepend(colorBuffer); | 
| } | 
|  | 
| -void DrawingBuffer::softwareMailboxReleased( | 
| +void DrawingBuffer::mailboxReleasedSoftware( | 
| std::unique_ptr<cc::SharedBitmap> bitmap, | 
| const IntSize& size, | 
| const gpu::SyncToken& syncToken, | 
| @@ -442,6 +439,8 @@ void DrawingBuffer::softwareMailboxReleased( | 
| } | 
|  | 
| PassRefPtr<StaticBitmapImage> DrawingBuffer::transferToStaticBitmapImage() { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| + | 
| // This can be null if the context is lost before the first call to | 
| // grContext(). | 
| GrContext* grContext = m_contextProvider->grContext(); | 
| @@ -514,12 +513,12 @@ PassRefPtr<StaticBitmapImage> DrawingBuffer::transferToStaticBitmapImage() { | 
| std::move(skImage), skImageMailbox, skImageSyncToken); | 
| } | 
|  | 
| -DrawingBuffer::TextureParameters | 
| -DrawingBuffer::chromiumImageTextureParameters() { | 
| +DrawingBuffer::ColorBufferParameters | 
| +DrawingBuffer::gpuMemoryBufferColorBufferParameters() { | 
| #if OS(MACOSX) | 
| // A CHROMIUM_image backed texture requires a specialized set of parameters | 
| // on OSX. | 
| -  TextureParameters parameters; | 
| +  ColorBufferParameters parameters; | 
| parameters.target = GC3D_TEXTURE_RECTANGLE_ARB; | 
|  | 
| if (m_wantAlphaChannel) { | 
| @@ -541,12 +540,13 @@ DrawingBuffer::chromiumImageTextureParameters() { | 
| parameters.colorFormat = 0; | 
| return parameters; | 
| #else | 
| -  return defaultTextureParameters(); | 
| +  return textureColorBufferParameters(); | 
| #endif | 
| } | 
|  | 
| -DrawingBuffer::TextureParameters DrawingBuffer::defaultTextureParameters() { | 
| -  TextureParameters parameters; | 
| +DrawingBuffer::ColorBufferParameters | 
| +DrawingBuffer::textureColorBufferParameters() { | 
| +  ColorBufferParameters parameters; | 
| parameters.target = GL_TEXTURE_2D; | 
| if (m_wantAlphaChannel) { | 
| parameters.internalColorFormat = GL_RGBA; | 
| @@ -568,37 +568,65 @@ DrawingBuffer::TextureParameters DrawingBuffer::defaultTextureParameters() { | 
| return parameters; | 
| } | 
|  | 
| -PassRefPtr<DrawingBuffer::ColorBuffer> DrawingBuffer::takeRecycledMailbox() { | 
| -  if (m_recycledMailboxQueue.isEmpty()) | 
| -    return nullptr; | 
| - | 
| -  RefPtr<ColorBuffer> recycled = m_recycledMailboxQueue.takeLast(); | 
| -  DCHECK(recycled->size == m_size); | 
| -  if (recycled->receiveSyncToken.HasData()) | 
| -    m_gl->WaitSyncTokenCHROMIUM(recycled->receiveSyncToken.GetData()); | 
| -  return recycled; | 
| +PassRefPtr<DrawingBuffer::ColorBuffer> | 
| +DrawingBuffer::createOrRecycleColorBuffer() { | 
| +  if (!m_recycledColorBufferQueue.isEmpty()) { | 
| +    RefPtr<ColorBuffer> recycled = m_recycledColorBufferQueue.takeLast(); | 
| +    if (recycled->receiveSyncToken.HasData()) | 
| +      m_gl->WaitSyncTokenCHROMIUM(recycled->receiveSyncToken.GetData()); | 
| +    DCHECK(recycled->size == m_size); | 
| +    return recycled; | 
| +  } | 
| +  return createColorBuffer(m_size); | 
| } | 
|  | 
| DrawingBuffer::ColorBuffer::ColorBuffer(DrawingBuffer* drawingBuffer, | 
| -                                        const TextureParameters& parameters, | 
| -                                        const IntSize& size) | 
| -    : drawingBuffer(drawingBuffer), parameters(parameters), size(size) { | 
| +                                        const ColorBufferParameters& parameters, | 
| +                                        const IntSize& size, | 
| +                                        GLuint textureId, | 
| +                                        GLuint imageId) | 
| +    : drawingBuffer(drawingBuffer), | 
| +      parameters(parameters), | 
| +      size(size), | 
| +      textureId(textureId), | 
| +      imageId(imageId) { | 
| drawingBuffer->contextGL()->GenMailboxCHROMIUM(mailbox.name); | 
| } | 
|  | 
| DrawingBuffer::ColorBuffer::~ColorBuffer() { | 
| -  gpu::gles2::GLES2Interface* gl = drawingBuffer->contextGL(); | 
| +  gpu::gles2::GLES2Interface* gl = drawingBuffer->m_gl; | 
| if (receiveSyncToken.HasData()) | 
| gl->WaitSyncTokenCHROMIUM(receiveSyncToken.GetConstData()); | 
| if (imageId) { | 
| gl->BindTexture(parameters.target, textureId); | 
| gl->ReleaseTexImage2DCHROMIUM(parameters.target, imageId); | 
| gl->DestroyImageCHROMIUM(imageId); | 
| +    switch (parameters.target) { | 
| +      case GL_TEXTURE_2D: | 
| +        // Restore the texture binding for GL_TEXTURE_2D, since the client will | 
| +        // expect the previous state. | 
| +        if (drawingBuffer->m_stateTracker) { | 
| +          DrawingBufferRestoreState restoreState; | 
| +          drawingBuffer->m_stateTracker->GetDrawingBufferRestoreState( | 
| +              &restoreState); | 
| +          gl->BindTexture(GL_TEXTURE_2D, restoreState.activeTexture2DBinding); | 
| +        } | 
| +        break; | 
| +      case GC3D_TEXTURE_RECTANGLE_ARB: | 
| +        // Rectangle textures aren't exposed to WebGL, so don't bother | 
| +        // restoring this state (there is no meaningful way to restore it). | 
| +        break; | 
| +      default: | 
| +        NOTREACHED(); | 
| +        break; | 
| +    } | 
| } | 
| gl->DeleteTextures(1, &textureId); | 
| } | 
|  | 
| bool DrawingBuffer::initialize(const IntSize& size, bool useMultisampling) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| + | 
| if (m_gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR) { | 
| // Need to try to restore the context again later. | 
| return false; | 
| @@ -630,6 +658,7 @@ bool DrawingBuffer::initialize(const IntSize& size, bool useMultisampling) { | 
| m_antiAliasingMode == ScreenSpaceAntialiasing; | 
| m_sampleCount = std::min(4, maxSampleCount); | 
|  | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| m_gl->GenFramebuffers(1, &m_fbo); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| if (wantExplicitResolve()) { | 
| @@ -637,7 +666,7 @@ bool DrawingBuffer::initialize(const IntSize& size, bool useMultisampling) { | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); | 
| m_gl->GenRenderbuffers(1, &m_multisampleRenderbuffer); | 
| } | 
| -  if (!reset(size)) | 
| +  if (!resizeFramebufferInternal(size)) | 
| return false; | 
|  | 
| if (m_depthStencilBuffer) { | 
| @@ -662,11 +691,11 @@ bool DrawingBuffer::copyToPlatformTexture(gpu::gles2::GLES2Interface* gl, | 
| bool premultiplyAlpha, | 
| bool flipY, | 
| SourceDrawingBuffer sourceBuffer) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| + | 
| if (m_contentsChanged) { | 
| -    if (m_antiAliasingMode != None) { | 
| -      commit(); | 
| -      restoreFramebufferBindings(); | 
| -    } | 
| +    if (m_antiAliasingMode != None) | 
| +      resolveMultisampleFramebufferInternal(); | 
| m_gl->Flush(); | 
| } | 
|  | 
| @@ -722,10 +751,6 @@ bool DrawingBuffer::copyToPlatformTexture(gpu::gles2::GLES2Interface* gl, | 
| return true; | 
| } | 
|  | 
| -GLuint DrawingBuffer::framebuffer() const { | 
| -  return m_fbo; | 
| -} | 
| - | 
| WebLayer* DrawingBuffer::platformLayer() { | 
| if (!m_layer) { | 
| m_layer = wrapUnique( | 
| @@ -754,7 +779,7 @@ void DrawingBuffer::beginDestruction() { | 
| m_destructionInProgress = true; | 
|  | 
| clearPlatformLayer(); | 
| -  m_recycledMailboxQueue.clear(); | 
| +  m_recycledColorBufferQueue.clear(); | 
|  | 
| if (m_multisampleFBO) | 
| m_gl->DeleteFramebuffers(1, &m_multisampleFBO); | 
| @@ -779,26 +804,19 @@ void DrawingBuffer::beginDestruction() { | 
|  | 
| if (m_layer) | 
| GraphicsLayer::unregisterContentsLayer(m_layer->layer()); | 
| -} | 
|  | 
| -GLuint DrawingBuffer::createColorTexture(const TextureParameters& parameters) { | 
| -  GLuint offscreenColorTexture; | 
| -  m_gl->GenTextures(1, &offscreenColorTexture); | 
| -  m_gl->BindTexture(parameters.target, offscreenColorTexture); | 
| -  m_gl->TexParameteri(parameters.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
| -  m_gl->TexParameteri(parameters.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
| -  m_gl->TexParameteri(parameters.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
| -  m_gl->TexParameteri(parameters.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
| -  return offscreenColorTexture; | 
| +  m_stateTracker = nullptr; | 
| } | 
|  | 
| bool DrawingBuffer::resizeDefaultFramebuffer(const IntSize& size) { | 
| // Recreate m_backColorBuffer. | 
| -  m_backColorBuffer = createTextureAndAllocateMemory(size); | 
| +  m_backColorBuffer = createColorBuffer(size); | 
|  | 
| attachColorBufferToReadFramebuffer(); | 
|  | 
| if (wantExplicitResolve()) { | 
| +    m_stateRestorer->setFramebufferBindingDirty(); | 
| +    m_stateRestorer->setRenderbufferBindingDirty(); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); | 
| m_gl->BindRenderbuffer(GL_RENDERBUFFER, m_multisampleRenderbuffer); | 
| m_gl->RenderbufferStorageMultisampleCHROMIUM( | 
| @@ -813,6 +831,8 @@ bool DrawingBuffer::resizeDefaultFramebuffer(const IntSize& size) { | 
| } | 
|  | 
| if (wantDepthOrStencil()) { | 
| +    m_stateRestorer->setFramebufferBindingDirty(); | 
| +    m_stateRestorer->setRenderbufferBindingDirty(); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, | 
| m_multisampleFBO ? m_multisampleFBO : m_fbo); | 
| if (!m_depthStencilBuffer) | 
| @@ -839,17 +859,25 @@ bool DrawingBuffer::resizeDefaultFramebuffer(const IntSize& size) { | 
| } | 
|  | 
| if (wantExplicitResolve()) { | 
| +    m_stateRestorer->setFramebufferBindingDirty(); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); | 
| if (m_gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) | 
| return false; | 
| } | 
|  | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| return m_gl->CheckFramebufferStatus(GL_FRAMEBUFFER) == | 
| GL_FRAMEBUFFER_COMPLETE; | 
| } | 
|  | 
| void DrawingBuffer::clearFramebuffers(GLbitfield clearMask) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| +  clearFramebuffersInternal(clearMask); | 
| +} | 
| + | 
| +void DrawingBuffer::clearFramebuffersInternal(GLbitfield clearMask) { | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| // We will clear the multisample FBO, but we also need to clear the | 
| // non-multisampled buffer. | 
| if (m_multisampleFBO) { | 
| @@ -878,7 +906,12 @@ IntSize DrawingBuffer::adjustSize(const IntSize& desiredSize, | 
| return adjustedSize; | 
| } | 
|  | 
| -bool DrawingBuffer::reset(const IntSize& newSize) { | 
| +bool DrawingBuffer::resize(const IntSize& newSize) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| +  return resizeFramebufferInternal(newSize); | 
| +} | 
| + | 
| +bool DrawingBuffer::resizeFramebufferInternal(const IntSize& newSize) { | 
| CHECK(!newSize.isEmpty()); | 
| IntSize adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize); | 
| if (adjustedSize.isEmpty()) | 
| @@ -896,13 +929,14 @@ bool DrawingBuffer::reset(const IntSize& newSize) { | 
| m_size = adjustedSize; | 
| // Free all mailboxes, because they are now of the wrong size. Only the | 
| // first call in this loop has any effect. | 
| -    m_recycledMailboxQueue.clear(); | 
| +    m_recycledColorBufferQueue.clear(); | 
| m_recycledBitmaps.clear(); | 
|  | 
| if (adjustedSize.isEmpty()) | 
| return false; | 
| } | 
|  | 
| +  m_stateRestorer->setClearStateDirty(); | 
| m_gl->Disable(GL_SCISSOR_TEST); | 
| m_gl->ClearColor(0, 0, 0, | 
| defaultBufferRequiresAlphaChannelToBePreserved() ? 1 : 0); | 
| @@ -920,17 +954,25 @@ bool DrawingBuffer::reset(const IntSize& newSize) { | 
| m_gl->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); | 
| } | 
|  | 
| -  clearFramebuffers(clearMask); | 
| +  clearFramebuffersInternal(clearMask); | 
| return true; | 
| } | 
|  | 
| -void DrawingBuffer::commit() { | 
| +void DrawingBuffer::resolveAndBindForReadAndDraw() { | 
| +  { | 
| +    ScopedStateRestorer scopedStateRestorer(this); | 
| +    resolveMultisampleFramebufferInternal(); | 
| +  } | 
| +  m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| +} | 
| + | 
| +void DrawingBuffer::resolveMultisampleFramebufferInternal() { | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| if (wantExplicitResolve() && !m_contentsChangeCommitted) { | 
| +    m_stateRestorer->setClearStateDirty(); | 
| m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO); | 
| m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo); | 
| - | 
| -    if (m_scissorEnabled) | 
| -      m_gl->Disable(GL_SCISSOR_TEST); | 
| +    m_gl->Disable(GL_SCISSOR_TEST); | 
|  | 
| int width = m_size.width(); | 
| int height = m_size.height(); | 
| @@ -949,52 +991,18 @@ void DrawingBuffer::commit() { | 
| .disable_multisampling_color_mask_usage) { | 
| m_gl->ClearColor(0, 0, 0, 1); | 
| m_gl->ColorMask(false, false, false, true); | 
| -      m_gl->Clear(GL_COLOR_BUFFER_BIT); | 
| - | 
| -      m_gl->ClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2], | 
| -                       m_clearColor[3]); | 
| -      m_gl->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], | 
| -                      m_colorMask[3]); | 
| } | 
| - | 
| -    if (m_scissorEnabled) | 
| -      m_gl->Enable(GL_SCISSOR_TEST); | 
| } | 
|  | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| -  if (m_antiAliasingMode == ScreenSpaceAntialiasing) { | 
| +  if (m_antiAliasingMode == ScreenSpaceAntialiasing) | 
| m_gl->ApplyScreenSpaceAntialiasingCHROMIUM(); | 
| -  } | 
| m_contentsChangeCommitted = true; | 
| } | 
|  | 
| -void DrawingBuffer::restorePixelUnpackBufferBindings() { | 
| -  if (m_webGLVersion > WebGL1) { | 
| -    m_gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pixelUnpackBufferBinding); | 
| -  } | 
| -} | 
| - | 
| void DrawingBuffer::restoreFramebufferBindings() { | 
| -  if (m_drawFramebufferBinding && m_readFramebufferBinding) { | 
| -    if (m_drawFramebufferBinding == m_readFramebufferBinding) { | 
| -      m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_readFramebufferBinding); | 
| -    } else { | 
| -      m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebufferBinding); | 
| -      m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebufferBinding); | 
| -    } | 
| -    return; | 
| -  } | 
| -  if (!m_drawFramebufferBinding && !m_readFramebufferBinding) { | 
| -    bind(GL_FRAMEBUFFER); | 
| -    return; | 
| -  } | 
| -  if (!m_drawFramebufferBinding) { | 
| -    bind(GL_DRAW_FRAMEBUFFER); | 
| -    m_gl->BindFramebuffer(GL_READ_FRAMEBUFFER, m_readFramebufferBinding); | 
| -  } else { | 
| -    bind(GL_READ_FRAMEBUFFER); | 
| -    m_gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFramebufferBinding); | 
| -  } | 
| +  DrawingBufferRestoreState restoreState; | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| } | 
|  | 
| bool DrawingBuffer::multisample() const { | 
| @@ -1006,15 +1014,13 @@ void DrawingBuffer::bind(GLenum target) { | 
| wantExplicitResolve() ? m_multisampleFBO : m_fbo); | 
| } | 
|  | 
| -void DrawingBuffer::setPackAlignment(GLint param) { | 
| -  m_packAlignment = param; | 
| -} | 
| - | 
| bool DrawingBuffer::paintRenderingResultsToImageData( | 
| int& width, | 
| int& height, | 
| SourceDrawingBuffer sourceBuffer, | 
| WTF::ArrayBufferContents& contents) { | 
| +  ScopedStateRestorer scopedStateRestorer(this); | 
| + | 
| ASSERT(!m_premultipliedAlpha); | 
| width = size().width(); | 
| height = size().height(); | 
| @@ -1030,6 +1036,7 @@ bool DrawingBuffer::paintRenderingResultsToImageData( | 
| WTF::ArrayBufferContents::DontInitialize); | 
|  | 
| GLuint fbo = 0; | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| if (sourceBuffer == FrontBuffer && m_frontColorBuffer) { | 
| m_gl->GenFramebuffers(1, &fbo); | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); | 
| @@ -1037,7 +1044,7 @@ bool DrawingBuffer::paintRenderingResultsToImageData( | 
| m_frontColorBuffer->parameters.target, | 
| m_frontColorBuffer->textureId, 0); | 
| } else { | 
| -    m_gl->BindFramebuffer(GL_FRAMEBUFFER, framebuffer()); | 
| +    m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
| } | 
|  | 
| readBackFramebuffer(static_cast<unsigned char*>(pixels.data()), width, height, | 
| @@ -1050,8 +1057,6 @@ bool DrawingBuffer::paintRenderingResultsToImageData( | 
| m_gl->DeleteFramebuffers(1, &fbo); | 
| } | 
|  | 
| -  restoreFramebufferBindings(); | 
| - | 
| pixels.transfer(contents); | 
| return true; | 
| } | 
| @@ -1061,11 +1066,9 @@ void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, | 
| int height, | 
| ReadbackOrder readbackOrder, | 
| WebGLImageConversion::AlphaOp op) { | 
| -  if (m_packAlignment > 4) | 
| -    m_gl->PixelStorei(GL_PACK_ALIGNMENT, 1); | 
| +  m_stateRestorer->setPixelPackAlignmentDirty(); | 
| +  m_gl->PixelStorei(GL_PACK_ALIGNMENT, 1); | 
| m_gl->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | 
| -  if (m_packAlignment > 4) | 
| -    m_gl->PixelStorei(GL_PACK_ALIGNMENT, m_packAlignment); | 
|  | 
| size_t bufferSize = 4 * width * height; | 
|  | 
| @@ -1093,100 +1096,96 @@ void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, | 
| void DrawingBuffer::flipVertically(uint8_t* framebuffer, | 
| int width, | 
| int height) { | 
| -  m_scanline.resize(width * 4); | 
| -  uint8_t* scanline = &m_scanline[0]; | 
| +  std::vector<uint8_t> scanline(width * 4); | 
| unsigned rowBytes = width * 4; | 
| unsigned count = height / 2; | 
| for (unsigned i = 0; i < count; i++) { | 
| uint8_t* rowA = framebuffer + i * rowBytes; | 
| uint8_t* rowB = framebuffer + (height - i - 1) * rowBytes; | 
| -    memcpy(scanline, rowB, rowBytes); | 
| +    memcpy(scanline.data(), rowB, rowBytes); | 
| memcpy(rowB, rowA, rowBytes); | 
| -    memcpy(rowA, scanline, rowBytes); | 
| +    memcpy(rowA, scanline.data(), rowBytes); | 
| } | 
| } | 
|  | 
| -void DrawingBuffer::allocateConditionallyImmutableTexture(GLenum target, | 
| -                                                          GLenum internalformat, | 
| -                                                          GLsizei width, | 
| -                                                          GLsizei height, | 
| -                                                          GLint border, | 
| -                                                          GLenum format, | 
| -                                                          GLenum type) { | 
| -  if (m_storageTextureSupported) { | 
| -    GLenum internalStorageFormat = GL_NONE; | 
| -    if (internalformat == GL_RGB) { | 
| -      internalStorageFormat = GL_RGB8; | 
| -    } else if (internalformat == GL_RGBA) { | 
| -      internalStorageFormat = GL_RGBA8; | 
| -    } else { | 
| -      NOTREACHED(); | 
| -    } | 
| -    m_gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, internalStorageFormat, width, | 
| -                          height); | 
| -    return; | 
| +RefPtr<DrawingBuffer::ColorBuffer> DrawingBuffer::createColorBuffer( | 
| +    const IntSize& size) { | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| +  m_stateRestorer->setTextureBindingDirty(); | 
| + | 
| +  // Select the Parameters for the texture object. Allocate the backing | 
| +  // GpuMemoryBuffer and GLImage, if one is going to be used. | 
| +  ColorBufferParameters parameters; | 
| +  GLuint imageId = 0; | 
| +  if (shouldUseChromiumImage()) { | 
| +    parameters = gpuMemoryBufferColorBufferParameters(); | 
| +    imageId = m_gl->CreateGpuMemoryBufferImageCHROMIUM( | 
| +        size.width(), size.height(), parameters.creationInternalColorFormat, | 
| +        GC3D_SCANOUT_CHROMIUM); | 
| +  } else { | 
| +    parameters = textureColorBufferParameters(); | 
| } | 
| -  m_gl->TexImage2D(target, 0, internalformat, width, height, border, format, | 
| -                   type, 0); | 
| -} | 
| - | 
| -void DrawingBuffer::clearChromiumImageAlpha(const ColorBuffer& info) { | 
| -  if (m_wantAlphaChannel) | 
| -    return; | 
| -  if (!contextProvider()->getCapabilities().chromium_image_rgb_emulation) | 
| -    return; | 
| - | 
| -  GLuint fbo = 0; | 
| -  m_gl->GenFramebuffers(1, &fbo); | 
| -  m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); | 
| -  m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
| -                             info.parameters.target, info.textureId, 0); | 
| -  m_gl->ClearColor(0, 0, 0, 1); | 
| -  m_gl->ColorMask(false, false, false, true); | 
| -  m_gl->Clear(GL_COLOR_BUFFER_BIT); | 
| -  m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
| -                             info.parameters.target, 0, 0); | 
| -  m_gl->DeleteFramebuffers(1, &fbo); | 
| -  restoreFramebufferBindings(); | 
| -  m_gl->ClearColor(m_clearColor[0], m_clearColor[1], m_clearColor[2], | 
| -                   m_clearColor[3]); | 
| -  m_gl->ColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], | 
| -                  m_colorMask[3]); | 
| -} | 
|  | 
| -RefPtr<DrawingBuffer::ColorBuffer> | 
| -DrawingBuffer::createTextureAndAllocateMemory(const IntSize& size) { | 
| -  if (!shouldUseChromiumImage()) | 
| -    return createDefaultTextureAndAllocateMemory(size); | 
| +  // Allocate the texture for this object. | 
| +  GLuint textureId = 0; | 
| +  { | 
| +    m_gl->GenTextures(1, &textureId); | 
| +    m_gl->BindTexture(parameters.target, textureId); | 
| +    m_gl->TexParameteri(parameters.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 
| +    m_gl->TexParameteri(parameters.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 
| +    m_gl->TexParameteri(parameters.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
| +    m_gl->TexParameteri(parameters.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
| +  } | 
|  | 
| -  TextureParameters parameters = chromiumImageTextureParameters(); | 
| -  GLuint imageId = m_gl->CreateGpuMemoryBufferImageCHROMIUM( | 
| -      size.width(), size.height(), parameters.creationInternalColorFormat, | 
| -      GC3D_SCANOUT_CHROMIUM); | 
| -  GLuint textureId = createColorTexture(parameters); | 
| +  // If this is GpuMemoryBuffer-backed, then bind the texture to the | 
| +  // GpuMemoryBuffer's GLImage. Otherwise, allocate ordinary texture storage. | 
| if (imageId) { | 
| m_gl->BindTexImage2DCHROMIUM(parameters.target, imageId); | 
| +  } else { | 
| +    if (m_storageTextureSupported) { | 
| +      GLenum internalStorageFormat = GL_NONE; | 
| +      if (parameters.creationInternalColorFormat == GL_RGB) { | 
| +        internalStorageFormat = GL_RGB8; | 
| +      } else if (parameters.creationInternalColorFormat == GL_RGBA) { | 
| +        internalStorageFormat = GL_RGBA8; | 
| +      } else { | 
| +        NOTREACHED(); | 
| +      } | 
| +      m_gl->TexStorage2DEXT(GL_TEXTURE_2D, 1, internalStorageFormat, | 
| +                            size.width(), size.height()); | 
| +    } else { | 
| +      m_gl->TexImage2D(parameters.target, 0, | 
| +                       parameters.creationInternalColorFormat, size.width(), | 
| +                       size.height(), 0, parameters.colorFormat, | 
| +                       GL_UNSIGNED_BYTE, 0); | 
| +    } | 
| } | 
|  | 
| -  RefPtr<ColorBuffer> info(adoptRef(new ColorBuffer(this, parameters, size))); | 
| -  info->textureId = textureId; | 
| -  info->imageId = imageId; | 
| -  clearChromiumImageAlpha(*info); | 
| -  return info; | 
| -} | 
| +  // Clear the alpha channel if this is RGB emulated. | 
| +  if (imageId && !m_wantAlphaChannel && | 
| +      contextProvider()->getCapabilities().chromium_image_rgb_emulation) { | 
| +    GLuint fbo = 0; | 
|  | 
| -RefPtr<DrawingBuffer::ColorBuffer> | 
| -DrawingBuffer::createDefaultTextureAndAllocateMemory(const IntSize& size) { | 
| -  TextureParameters parameters = defaultTextureParameters(); | 
| -  RefPtr<ColorBuffer> info(adoptRef(new ColorBuffer(this, parameters, size))); | 
| -  info->textureId = createColorTexture(parameters); | 
| -  allocateConditionallyImmutableTexture( | 
| -      parameters.target, parameters.creationInternalColorFormat, size.width(), | 
| -      size.height(), 0, parameters.colorFormat, GL_UNSIGNED_BYTE); | 
| -  return info; | 
| +    m_stateRestorer->setClearStateDirty(); | 
| +    m_gl->GenFramebuffers(1, &fbo); | 
| +    m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); | 
| +    m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
| +                               parameters.target, textureId, 0); | 
| +    m_gl->ClearColor(0, 0, 0, 1); | 
| +    m_gl->ColorMask(false, false, false, true); | 
| +    m_gl->Clear(GL_COLOR_BUFFER_BIT); | 
| +    m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
| +                               parameters.target, 0, 0); | 
| +    m_gl->DeleteFramebuffers(1, &fbo); | 
| +  } | 
| + | 
| +  return adoptRef(new ColorBuffer(this, parameters, size, textureId, imageId)); | 
| } | 
|  | 
| void DrawingBuffer::attachColorBufferToReadFramebuffer() { | 
| +  m_stateRestorer->setFramebufferBindingDirty(); | 
| +  m_stateRestorer->setTextureBindingDirty(); | 
| + | 
| m_gl->BindFramebuffer(GL_FRAMEBUFFER, m_fbo); | 
|  | 
| GLenum target = m_backColorBuffer->parameters.target; | 
| @@ -1200,9 +1199,6 @@ void DrawingBuffer::attachColorBufferToReadFramebuffer() { | 
| else | 
| m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, id, | 
| 0); | 
| - | 
| -  restoreTextureBindings(); | 
| -  restoreFramebufferBindings(); | 
| } | 
|  | 
| bool DrawingBuffer::wantExplicitResolve() { | 
| @@ -1227,11 +1223,58 @@ GLenum DrawingBuffer::getMultisampledRenderbufferFormat() { | 
| return GL_RGB8_OES; | 
| } | 
|  | 
| -void DrawingBuffer::restoreTextureBindings() { | 
| -  // This class potentially modifies the bindings for GL_TEXTURE_2D and | 
| -  // GL_TEXTURE_RECTANGLE. Only GL_TEXTURE_2D needs to be restored since | 
| -  // the public interface for WebGL does not support GL_TEXTURE_RECTANGLE. | 
| -  m_gl->BindTexture(GL_TEXTURE_2D, m_texture2DBinding); | 
| +DrawingBuffer::ScopedStateRestorer::ScopedStateRestorer( | 
| +    DrawingBuffer* drawingBuffer) | 
| +    : m_drawingBuffer(drawingBuffer) { | 
| +  DCHECK(!m_drawingBuffer->m_stateRestorer); | 
| +  m_drawingBuffer->m_stateRestorer = this; | 
| +} | 
| + | 
| +DrawingBuffer::ScopedStateRestorer::~ScopedStateRestorer() { | 
| +  m_drawingBuffer->m_stateRestorer = nullptr; | 
| +  if (!m_drawingBuffer->m_stateTracker) | 
| +    return; | 
| + | 
| +  gpu::gles2::GLES2Interface* gl = m_drawingBuffer->m_gl; | 
| +  DrawingBufferRestoreState restoreState; | 
| +  m_drawingBuffer->m_stateTracker->GetDrawingBufferRestoreState(&restoreState); | 
| + | 
| +  if (m_clearStateDirty) { | 
| +    if (restoreState.scissorEnabled) | 
| +      gl->Enable(GL_SCISSOR_TEST); | 
| +    else | 
| +      gl->Disable(GL_SCISSOR_TEST); | 
| +    gl->ClearColor(restoreState.clearColor[0], restoreState.clearColor[1], | 
| +                   restoreState.clearColor[2], restoreState.clearColor[3]); | 
| +    gl->ClearDepthf(restoreState.clearDepth); | 
| +    gl->ClearStencil(restoreState.clearStencil); | 
| + | 
| +    gl->ColorMask(restoreState.colorMask[0], restoreState.colorMask[1], | 
| +                  restoreState.colorMask[2], restoreState.colorMask[3]); | 
| +    gl->DepthMask(restoreState.depthMask); | 
| +    gl->StencilMaskSeparate(GL_FRONT, restoreState.stencilMask); | 
| +  } | 
| +  if (m_pixelPackAlignmentDirty) | 
| +    gl->PixelStorei(GL_PACK_ALIGNMENT, restoreState.packAlignment); | 
| +  if (m_textureBindingDirty) | 
| +    gl->BindTexture(GL_TEXTURE_2D, restoreState.activeTexture2DBinding); | 
| +  if (m_renderbufferBindingDirty) | 
| +    gl->BindRenderbuffer(GL_RENDERBUFFER, restoreState.renderbufferBinding); | 
| +  if (m_framebufferBindingDirty) { | 
| +    if (restoreState.drawFramebufferBinding == | 
| +        restoreState.readFramebufferBinding) { | 
| +      gl->BindFramebuffer(GL_FRAMEBUFFER, restoreState.drawFramebufferBinding); | 
| +    } else { | 
| +      gl->BindFramebuffer(GL_READ_FRAMEBUFFER, | 
| +                          restoreState.readFramebufferBinding); | 
| +      gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, | 
| +                          restoreState.drawFramebufferBinding); | 
| +    } | 
| +  } | 
| +  if (m_pixelUnpackBufferBindingDirty) { | 
| +    gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, | 
| +                   restoreState.pixelUnpackBufferBinding); | 
| +  } | 
| } | 
|  | 
| bool DrawingBuffer::shouldUseChromiumImage() { | 
|  |