Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(334)

Unified Diff: third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp

Issue 2402603002: State management cleanup (Closed)
Patch Set: Make state dirtying explosive Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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() {

Powered by Google App Engine
This is Rietveld 408576698