diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp | 772 |
1 files changed, 541 insertions, 231 deletions
diff --git a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp index 54c13e20d7e..0ec4bf91790 100644 --- a/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp +++ b/chromium/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp @@ -32,33 +32,41 @@ #include "platform/graphics/gpu/DrawingBuffer.h" +#include "platform/RuntimeEnabledFeatures.h" #include <algorithm> #include "platform/TraceEvent.h" -#include "platform/graphics/Extensions3D.h" #include "platform/graphics/GraphicsLayer.h" +#include "platform/graphics/gpu/Extensions3DUtil.h" #include "public/platform/Platform.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebExternalBitmap.h" #include "public/platform/WebExternalTextureLayer.h" #include "public/platform/WebGraphicsContext3D.h" +#include "public/platform/WebGraphicsContext3DProvider.h" +#ifndef NDEBUG +#include "wtf/RefCountedLeakCounter.h" +#endif using namespace std; namespace WebCore { +namespace { // Global resource ceiling (expressed in terms of pixels) for DrawingBuffer creation and resize. // When this limit is set, DrawingBuffer::create() and DrawingBuffer::reset() calls that would // exceed the global cap will instead clear the buffer. -static const int s_maximumResourceUsePixels = 16 * 1024 * 1024; -static int s_currentResourceUsePixels = 0; -static const float s_resourceAdjustedRatio = 0.5; +const int s_maximumResourceUsePixels = 16 * 1024 * 1024; +int s_currentResourceUsePixels = 0; +const float s_resourceAdjustedRatio = 0.5; -static const bool s_allowContextEvictionOnCreate = true; -static const int s_maxScaleAttempts = 3; +const bool s_allowContextEvictionOnCreate = true; +const int s_maxScaleAttempts = 3; + +DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, drawingBufferCounter, ("DrawingBuffer")); class ScopedTextureUnit0BindingRestorer { public: - ScopedTextureUnit0BindingRestorer(GraphicsContext3D* context, GC3Denum activeTextureUnit, Platform3DObject textureUnitZeroId) + ScopedTextureUnit0BindingRestorer(blink::WebGraphicsContext3D* context, GLenum activeTextureUnit, Platform3DObject textureUnitZeroId) : m_context(context) , m_oldActiveTextureUnit(activeTextureUnit) , m_oldTextureUnitZeroId(textureUnitZeroId) @@ -72,48 +80,58 @@ public: } private: - GraphicsContext3D* m_context; - GC3Denum m_oldActiveTextureUnit; + blink::WebGraphicsContext3D* m_context; + GLenum m_oldActiveTextureUnit; Platform3DObject m_oldTextureUnitZeroId; }; -PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager) +} // namespace + +PassRefPtr<DrawingBuffer> DrawingBuffer::create(PassOwnPtr<blink::WebGraphicsContext3D> context, const IntSize& size, PreserveDrawingBuffer preserve, blink::WebGraphicsContext3D::Attributes requestedAttributes, PassRefPtr<ContextEvictionManager> contextEvictionManager) { - Extensions3D* extensions = context->extensions(); - bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") - && extensions->supports("GL_ANGLE_framebuffer_multisample") - && extensions->supports("GL_OES_rgb8_rgba8"); + ASSERT(context); + OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get()); + if (!extensionsUtil) { + // This might be the first time we notice that the WebGraphicsContext3D is lost. + return nullptr; + } + bool multisampleSupported = extensionsUtil->supportsExtension("GL_CHROMIUM_framebuffer_multisample") + && extensionsUtil->supportsExtension("GL_OES_rgb8_rgba8"); if (multisampleSupported) { - extensions->ensureEnabled("GL_ANGLE_framebuffer_blit"); - extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample"); - extensions->ensureEnabled("GL_OES_rgb8_rgba8"); + extensionsUtil->ensureExtensionEnabled("GL_CHROMIUM_framebuffer_multisample"); + extensionsUtil->ensureExtensionEnabled("GL_OES_rgb8_rgba8"); } - bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth_stencil"); + bool packedDepthStencilSupported = extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil"); if (packedDepthStencilSupported) - extensions->ensureEnabled("GL_OES_packed_depth_stencil"); + extensionsUtil->ensureExtensionEnabled("GL_OES_packed_depth_stencil"); - RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size, multisampleSupported, packedDepthStencilSupported, preserve, contextEvictionManager)); + RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, extensionsUtil.release(), multisampleSupported, packedDepthStencilSupported, preserve, requestedAttributes, contextEvictionManager)); + if (!drawingBuffer->initialize(size)) { + drawingBuffer->beginDestruction(); + return PassRefPtr<DrawingBuffer>(); + } return drawingBuffer.release(); } -DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, - const IntSize& size, - bool multisampleExtensionSupported, - bool packedDepthStencilExtensionSupported, - PreserveDrawingBuffer preserve, - PassRefPtr<ContextEvictionManager> contextEvictionManager) +DrawingBuffer::DrawingBuffer(PassOwnPtr<blink::WebGraphicsContext3D> context, + PassOwnPtr<Extensions3DUtil> extensionsUtil, + bool multisampleExtensionSupported, + bool packedDepthStencilExtensionSupported, + PreserveDrawingBuffer preserve, + blink::WebGraphicsContext3D::Attributes requestedAttributes, + PassRefPtr<ContextEvictionManager> contextEvictionManager) : m_preserveDrawingBuffer(preserve) , m_scissorEnabled(false) , m_texture2DBinding(0) , m_framebufferBinding(0) , m_activeTextureUnit(GL_TEXTURE0) , m_context(context) + , m_extensionsUtil(extensionsUtil) , m_size(-1, -1) + , m_requestedAttributes(requestedAttributes) , m_multisampleExtensionSupported(multisampleExtensionSupported) , m_packedDepthStencilExtensionSupported(packedDepthStencilExtensionSupported) , m_fbo(0) - , m_colorBuffer(0) - , m_frontColorBuffer(0) , m_depthStencilBuffer(0) , m_depthBuffer(0) , m_stencilBuffer(0) @@ -121,54 +139,85 @@ DrawingBuffer::DrawingBuffer(GraphicsContext3D* context, , m_multisampleColorBuffer(0) , m_contentsChanged(true) , m_contentsChangeCommitted(false) + , m_layerComposited(false) + , m_multisampleMode(None) , m_internalColorFormat(0) , m_colorFormat(0) , m_internalRenderbufferFormat(0) , m_maxTextureSize(0) + , m_sampleCount(0) + , m_packAlignment(4) + , m_destructionInProgress(false) , m_contextEvictionManager(contextEvictionManager) { // Used by browser tests to detect the use of a DrawingBuffer. TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation"); - initialize(size); +#ifndef NDEBUG + drawingBufferCounter.increment(); +#endif } DrawingBuffer::~DrawingBuffer() { - releaseResources(); + ASSERT(m_destructionInProgress); + ASSERT(m_textureMailboxes.isEmpty()); + m_layer.clear(); + m_context.clear(); +#ifndef NDEBUG + drawingBufferCounter.decrement(); +#endif } void DrawingBuffer::markContentsChanged() { m_contentsChanged = true; m_contentsChangeCommitted = false; + m_layerComposited = false; +} + +bool DrawingBuffer::layerComposited() const +{ + return m_layerComposited; +} + +void DrawingBuffer::markLayerComposited() +{ + m_layerComposited = true; } blink::WebGraphicsContext3D* DrawingBuffer::context() { - if (!m_context) - return 0; - return m_context->webContext(); + return m_context.get(); } bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap) { - if (!m_context || !m_contentsChanged || !m_lastColorBuffer) + if (!m_contentsChanged) return false; + if (m_destructionInProgress) { + // It can be hit in the following sequence. + // 1. WebGL draws something. + // 2. The compositor begins the frame. + // 3. Javascript makes a context lost using WEBGL_lose_context extension. + // 4. Here. + return false; + } + m_context->makeContextCurrent(); - // Resolve the multisampled buffer into the texture referenced by m_lastColorBuffer mailbox. - if (multisample()) + // Resolve the multisampled buffer into m_colorBuffer texture. + if (m_multisampleMode != None) commit(); if (bitmap) { bitmap->setSize(size()); unsigned char* pixels = bitmap->pixels(); - bool needPremultiply = m_attributes.alpha && !m_attributes.premultipliedAlpha; - GraphicsContext3D::AlphaOp op = needPremultiply ? GraphicsContext3D::AlphaDoPremultiply : GraphicsContext3D::AlphaDoNothing; + bool needPremultiply = m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha; + WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing; if (pixels) - m_context->readBackFramebuffer(pixels, size().width(), size().height(), GraphicsContext3D::ReadbackSkia, op); + readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op); } // We must restore the texture binding since creating new textures, @@ -176,134 +225,221 @@ bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding); // First try to recycle an old buffer. - RefPtr<MailboxInfo> nextFrontColorBuffer = recycledMailbox(); + RefPtr<MailboxInfo> frontColorBufferMailbox = recycledMailbox(); // No buffer available to recycle, create a new one. - if (!nextFrontColorBuffer) { - unsigned newColorBuffer = createColorTexture(m_size); + if (!frontColorBufferMailbox) { + TextureInfo newTexture; + newTexture.textureId = createColorTexture(); + allocateTextureMemory(&newTexture, m_size); // Bad things happened, abandon ship. - if (!newColorBuffer) + if (!newTexture.textureId) return false; - nextFrontColorBuffer = createNewMailbox(newColorBuffer); + frontColorBufferMailbox = createNewMailbox(newTexture); } if (m_preserveDrawingBuffer == Discard) { - m_colorBuffer = nextFrontColorBuffer->textureId; - swap(nextFrontColorBuffer, m_lastColorBuffer); + swap(frontColorBufferMailbox->textureInfo, m_colorBuffer); // It appears safe to overwrite the context's framebuffer binding in the Discard case since there will always be a // WebGLRenderingContext::clearIfComposited() call made before the next draw call which restores the framebuffer binding. // If this stops being true at some point, we should track the current framebuffer binding in the DrawingBuffer and restore // it after attaching the new back buffer here. m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); } else { - Extensions3D* extensions = m_context->extensions(); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer, nextFrontColorBuffer->textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); + m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); } - if (multisample() && !m_framebufferBinding) + if (m_multisampleMode != None && !m_framebufferBinding) bind(); else restoreFramebufferBinding(); m_contentsChanged = false; - context()->bindTexture(GL_TEXTURE_2D, nextFrontColorBuffer->textureId); - context()->produceTextureCHROMIUM(GL_TEXTURE_2D, nextFrontColorBuffer->mailbox.name); - context()->flush(); - m_context->markLayerComposited(); - - *outMailbox = nextFrontColorBuffer->mailbox; - m_frontColorBuffer = nextFrontColorBuffer->textureId; + m_context->bindTexture(GL_TEXTURE_2D, frontColorBufferMailbox->textureInfo.textureId); + m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, frontColorBufferMailbox->mailbox.name); + m_context->flush(); + frontColorBufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + frontColorBufferMailbox->mailbox.allowOverlay = frontColorBufferMailbox->textureInfo.imageId != 0; + markLayerComposited(); + + // set m_parentDrawingBuffer to make sure 'this' stays alive as long as it has live mailboxes + ASSERT(!frontColorBufferMailbox->m_parentDrawingBuffer); + frontColorBufferMailbox->m_parentDrawingBuffer = this; + *outMailbox = frontColorBufferMailbox->mailbox; + m_frontColorBuffer = frontColorBufferMailbox->textureInfo; return true; } void DrawingBuffer::mailboxReleased(const blink::WebExternalTextureMailbox& mailbox) { + if (m_destructionInProgress) { + mailboxReleasedWhileDestructionInProgress(mailbox); + return; + } + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { - RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; - if (!memcmp(mailboxInfo->mailbox.name, mailbox.name, sizeof(mailbox.name))) { - mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; - m_recycledMailboxes.append(mailboxInfo.release()); - return; - } - } - ASSERT_NOT_REACHED(); + RefPtr<MailboxInfo> mailboxInfo = m_textureMailboxes[i]; + if (nameEquals(mailboxInfo->mailbox, mailbox)) { + mailboxInfo->mailbox.syncPoint = mailbox.syncPoint; + ASSERT(mailboxInfo->m_parentDrawingBuffer.get() == this); + mailboxInfo->m_parentDrawingBuffer.clear(); + m_recycledMailboxQueue.prepend(mailboxInfo->mailbox); + return; + } + } + ASSERT_NOT_REACHED(); +} + +void DrawingBuffer::mailboxReleasedWhileDestructionInProgress(const blink::WebExternalTextureMailbox& mailbox) +{ + ASSERT(m_textureMailboxes.size()); + m_context->makeContextCurrent(); + // Ensure not to call the destructor until deleteMailbox() is completed. + RefPtr<DrawingBuffer> self = this; + deleteMailbox(mailbox); } PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::recycledMailbox() { - if (!m_context || m_recycledMailboxes.isEmpty()) + if (m_recycledMailboxQueue.isEmpty()) return PassRefPtr<MailboxInfo>(); - RefPtr<MailboxInfo> mailboxInfo = m_recycledMailboxes.last().release(); - m_recycledMailboxes.removeLast(); + blink::WebExternalTextureMailbox mailbox = m_recycledMailboxQueue.takeLast(); + RefPtr<MailboxInfo> mailboxInfo; + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { + if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { + mailboxInfo = m_textureMailboxes[i]; + break; + } + } + ASSERT(mailboxInfo); if (mailboxInfo->mailbox.syncPoint) { - context()->waitSyncPoint(mailboxInfo->mailbox.syncPoint); + m_context->waitSyncPoint(mailboxInfo->mailbox.syncPoint); mailboxInfo->mailbox.syncPoint = 0; } - context()->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureId); - context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailboxInfo->mailbox.name); - if (mailboxInfo->size != m_size) { - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); + m_context->bindTexture(GL_TEXTURE_2D, mailboxInfo->textureInfo.textureId); + allocateTextureMemory(&mailboxInfo->textureInfo, m_size); mailboxInfo->size = m_size; } return mailboxInfo.release(); } -PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(unsigned textureId) +PassRefPtr<DrawingBuffer::MailboxInfo> DrawingBuffer::createNewMailbox(const TextureInfo& info) { RefPtr<MailboxInfo> returnMailbox = adoptRef(new MailboxInfo()); - context()->genMailboxCHROMIUM(returnMailbox->mailbox.name); - returnMailbox->textureId = textureId; + m_context->genMailboxCHROMIUM(returnMailbox->mailbox.name); + returnMailbox->textureInfo = info; returnMailbox->size = m_size; m_textureMailboxes.append(returnMailbox); return returnMailbox.release(); } -void DrawingBuffer::initialize(const IntSize& size) +void DrawingBuffer::deleteMailbox(const blink::WebExternalTextureMailbox& mailbox) { - ASSERT(m_context); - m_attributes = m_context->getContextAttributes(); + for (size_t i = 0; i < m_textureMailboxes.size(); i++) { + if (nameEquals(m_textureMailboxes[i]->mailbox, mailbox)) { + if (mailbox.syncPoint) + m_context->waitSyncPoint(mailbox.syncPoint); + + deleteChromiumImageForTexture(&m_textureMailboxes[i]->textureInfo); + + m_context->deleteTexture(m_textureMailboxes[i]->textureInfo.textureId); + m_textureMailboxes.remove(i); + return; + } + } + ASSERT_NOT_REACHED(); +} - if (m_attributes.alpha) { +bool DrawingBuffer::initialize(const IntSize& size) +{ + if (!m_context->makeContextCurrent()) { + // Most likely the GPU process exited and the attempt to reconnect to it failed. + // Need to try to restore the context again later. + return false; + } + + if (m_context->isContextLost()) { + // Need to try to restore the context again later. + return false; + } + + if (m_requestedAttributes.alpha) { m_internalColorFormat = GL_RGBA; m_colorFormat = GL_RGBA; - m_internalRenderbufferFormat = Extensions3D::RGBA8_OES; + m_internalRenderbufferFormat = GL_RGBA8_OES; } else { m_internalColorFormat = GL_RGB; m_colorFormat = GL_RGB; - m_internalRenderbufferFormat = Extensions3D::RGB8_OES; + m_internalRenderbufferFormat = GL_RGB8_OES; } m_context->getIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); + int maxSampleCount = 0; + m_multisampleMode = None; + if (m_requestedAttributes.antialias && m_multisampleExtensionSupported) { + m_context->getIntegerv(GL_MAX_SAMPLES_ANGLE, &maxSampleCount); + m_multisampleMode = ExplicitResolve; + if (m_extensionsUtil->supportsExtension("GL_EXT_multisampled_render_to_texture")) + m_multisampleMode = ImplicitResolve; + } + m_sampleCount = std::min(4, maxSampleCount); + m_fbo = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_colorBuffer = createColorTexture(); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + m_colorBuffer.textureId = createColorTexture(); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); createSecondaryBuffers(); - reset(size); - m_lastColorBuffer = createNewMailbox(m_colorBuffer); -} - -unsigned DrawingBuffer::frontColorBuffer() const -{ - return m_frontColorBuffer; + // We first try to initialize everything with the requested attributes. + if (!reset(size)) + return false; + // If that succeeds, we then see what we actually got and update our actual attributes to reflect that. + m_actualAttributes = m_requestedAttributes; + if (m_requestedAttributes.alpha) { + blink::WGC3Dint alphaBits = 0; + m_context->getIntegerv(GL_ALPHA_BITS, &alphaBits); + m_actualAttributes.alpha = alphaBits > 0; + } + if (m_requestedAttributes.depth) { + blink::WGC3Dint depthBits = 0; + m_context->getIntegerv(GL_DEPTH_BITS, &depthBits); + m_actualAttributes.depth = depthBits > 0; + } + if (m_requestedAttributes.stencil) { + blink::WGC3Dint stencilBits = 0; + m_context->getIntegerv(GL_STENCIL_BITS, &stencilBits); + m_actualAttributes.stencil = stencilBits > 0; + } + m_actualAttributes.antialias = multisample(); + return true; } -bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3DObject texture, GC3Denum internalFormat, GC3Denum destType, GC3Dint level, bool premultiplyAlpha, bool flipY) +bool DrawingBuffer::copyToPlatformTexture(blink::WebGraphicsContext3D* context, Platform3DObject texture, GLenum internalFormat, GLenum destType, GLint level, bool premultiplyAlpha, bool flipY, bool fromFrontBuffer) { - if (!m_context || !m_context->makeContextCurrent()) + if (!m_context->makeContextCurrent()) return false; + + GLint textureId = m_colorBuffer.textureId; + if (fromFrontBuffer) + textureId = m_frontColorBuffer.textureId; + if (m_contentsChanged) { - if (multisample()) { + if (m_multisampleMode != None) { commit(); if (!m_framebufferBinding) bind(); @@ -312,30 +448,43 @@ bool DrawingBuffer::copyToPlatformTexture(GraphicsContext3D& context, Platform3D } m_context->flush(); } - Platform3DObject sourceTexture = colorBuffer(); - if (!context.makeContextCurrent()) + if (!Extensions3DUtil::canUseCopyTextureCHROMIUM(internalFormat, destType, level)) return false; - Extensions3D* extensions = context.extensions(); - if (!extensions->supports("GL_CHROMIUM_copy_texture") || !extensions->supports("GL_CHROMIUM_flipy") - || !extensions->canUseCopyTextureCHROMIUM(internalFormat, destType, level)) + + // Contexts may be in a different share group. We must transfer the texture through a mailbox first + RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); + m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); + m_context->produceTextureDirectCHROMIUM(textureId, GL_TEXTURE_2D, bufferMailbox->mailbox.name); + m_context->flush(); + + bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + + if (!context->makeContextCurrent()) return false; + context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); + Platform3DObject sourceTexture = context->createAndConsumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + bool unpackPremultiplyAlphaNeeded = false; bool unpackUnpremultiplyAlphaNeeded = false; - if (m_attributes.alpha && m_attributes.premultipliedAlpha && !premultiplyAlpha) + if (m_actualAttributes.alpha && m_actualAttributes.premultipliedAlpha && !premultiplyAlpha) unpackUnpremultiplyAlphaNeeded = true; - else if (m_attributes.alpha && !m_attributes.premultipliedAlpha && premultiplyAlpha) + else if (m_actualAttributes.alpha && !m_actualAttributes.premultipliedAlpha && premultiplyAlpha) unpackPremultiplyAlphaNeeded = true; - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded); - context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded); - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, flipY); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); - context.pixelStorei(Extensions3D::UNPACK_FLIP_Y_CHROMIUM, false); - context.pixelStorei(Extensions3D::UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); - context.pixelStorei(Extensions3D::UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); - context.flush(); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, unpackUnpremultiplyAlphaNeeded); + context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, unpackPremultiplyAlphaNeeded); + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, flipY); + context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, texture, level, internalFormat, destType); + context->pixelStorei(GC3D_UNPACK_FLIP_Y_CHROMIUM, false); + context->pixelStorei(GC3D_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM, false); + context->pixelStorei(GC3D_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM, false); + + context->deleteTexture(sourceTexture); + + context->flush(); + m_context->waitSyncPoint(context->insertSyncPoint()); return true; } @@ -347,15 +496,12 @@ Platform3DObject DrawingBuffer::framebuffer() const blink::WebLayer* DrawingBuffer::platformLayer() { - if (!m_context) - return 0; - if (!m_layer) { m_layer = adoptPtr(blink::Platform::current()->compositorSupport()->createExternalTextureLayer(this)); - m_layer->setOpaque(!m_attributes.alpha); - m_layer->setBlendBackgroundColor(m_attributes.alpha); - m_layer->setPremultipliedAlpha(m_attributes.premultipliedAlpha); + m_layer->setOpaque(!m_actualAttributes.alpha); + m_layer->setBlendBackgroundColor(m_actualAttributes.alpha); + m_layer->setPremultipliedAlpha(m_actualAttributes.premultipliedAlpha); GraphicsLayer::registerContentsLayer(m_layer->layer()); } @@ -364,17 +510,40 @@ blink::WebLayer* DrawingBuffer::platformLayer() void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) { - if (!m_context || !m_context->makeContextCurrent() || m_context->extensions()->getGraphicsResetStatusARB() != GL_NO_ERROR) + if (!m_context->makeContextCurrent() || m_context->getGraphicsResetStatusARB() != GL_NO_ERROR) return; - Extensions3D* extensions = m_context->extensions(); - if (!imageBuffer) return; Platform3DObject tex = imageBuffer->getBackingTexture(); if (tex) { - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer, + RefPtr<MailboxInfo> bufferMailbox = adoptRef(new MailboxInfo()); + m_context->genMailboxCHROMIUM(bufferMailbox->mailbox.name); + m_context->bindTexture(GL_TEXTURE_2D, m_frontColorBuffer.textureId); + m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + m_context->flush(); + + bufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); + OwnPtr<blink::WebGraphicsContext3DProvider> provider = + adoptPtr(blink::Platform::current()->createSharedOffscreenGraphicsContext3DProvider()); + if (!provider) + return; + blink::WebGraphicsContext3D* context = provider->context3d(); + if (!context || !context->makeContextCurrent()) + return; + + Platform3DObject sourceTexture = context->createTexture(); + GLint boundTexture = 0; + context->getIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); + context->bindTexture(GL_TEXTURE_2D, sourceTexture); + context->waitSyncPoint(bufferMailbox->mailbox.syncPoint); + context->consumeTextureCHROMIUM(GL_TEXTURE_2D, bufferMailbox->mailbox.name); + context->copyTextureCHROMIUM(GL_TEXTURE_2D, sourceTexture, tex, 0, GL_RGBA, GL_UNSIGNED_BYTE); + context->bindTexture(GL_TEXTURE_2D, boundTexture); + context->deleteTexture(sourceTexture); + context->flush(); + m_context->waitSyncPoint(context->insertSyncPoint()); return; } @@ -382,20 +551,21 @@ void DrawingBuffer::paintCompositedResultsToCanvas(ImageBuffer* imageBuffer) // We have to make a copy of it here and bind that copy instead. // FIXME: That's not true any more, provided we don't change texture // parameters. - unsigned sourceTexture = createColorTexture(m_size); - extensions->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE); + unsigned sourceTexture = createColorTexture(); + texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, m_size.width(), m_size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); + m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_frontColorBuffer.textureId, sourceTexture, 0, GL_RGBA, GL_UNSIGNED_BYTE); // Since we're using the same context as WebGL, we have to restore any state we change (in this case, just the framebuffer binding). // FIXME: The WebGLRenderingContext tracks the current framebuffer binding, it would be slightly more efficient to use this value // rather than querying it off of the context. - GC3Dint previousFramebuffer = 0; + GLint previousFramebuffer = 0; m_context->getIntegerv(GL_FRAMEBUFFER_BINDING, &previousFramebuffer); Platform3DObject framebuffer = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sourceTexture, 0); - extensions->paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_attributes.premultipliedAlpha, imageBuffer); + paintFramebufferToCanvas(framebuffer, size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); m_context->deleteFramebuffer(framebuffer); m_context->deleteTexture(sourceTexture); @@ -407,45 +577,48 @@ void DrawingBuffer::clearPlatformLayer() if (m_layer) m_layer->clearTexture(); - if (m_context) - m_context->flush(); + m_context->flush(); } -void DrawingBuffer::releaseResources() +void DrawingBuffer::beginDestruction() { - if (m_context) { - m_context->makeContextCurrent(); + ASSERT(!m_destructionInProgress); + m_destructionInProgress = true; - clearPlatformLayer(); + m_context->makeContextCurrent(); - for (size_t i = 0; i < m_textureMailboxes.size(); i++) - m_context->deleteTexture(m_textureMailboxes[i]->textureId); + clearPlatformLayer(); - if (m_multisampleColorBuffer) - m_context->deleteRenderbuffer(m_multisampleColorBuffer); + while (!m_recycledMailboxQueue.isEmpty()) + deleteMailbox(m_recycledMailboxQueue.takeLast()); - if (m_depthStencilBuffer) - m_context->deleteRenderbuffer(m_depthStencilBuffer); + if (m_multisampleFBO) + m_context->deleteFramebuffer(m_multisampleFBO); - if (m_depthBuffer) - m_context->deleteRenderbuffer(m_depthBuffer); + if (m_fbo) + m_context->deleteFramebuffer(m_fbo); - if (m_stencilBuffer) - m_context->deleteRenderbuffer(m_stencilBuffer); + if (m_multisampleColorBuffer) + m_context->deleteRenderbuffer(m_multisampleColorBuffer); - if (m_multisampleFBO) - m_context->deleteFramebuffer(m_multisampleFBO); + if (m_depthStencilBuffer) + m_context->deleteRenderbuffer(m_depthStencilBuffer); - if (m_fbo) - m_context->deleteFramebuffer(m_fbo); + if (m_depthBuffer) + m_context->deleteRenderbuffer(m_depthBuffer); - m_context.clear(); + if (m_stencilBuffer) + m_context->deleteRenderbuffer(m_stencilBuffer); + + if (m_colorBuffer.textureId) { + deleteChromiumImageForTexture(&m_colorBuffer); + m_context->deleteTexture(m_colorBuffer.textureId); } setSize(IntSize()); - m_colorBuffer = 0; - m_frontColorBuffer = 0; + m_colorBuffer = TextureInfo(); + m_frontColorBuffer = TextureInfo(); m_multisampleColorBuffer = 0; m_depthStencilBuffer = 0; m_depthBuffer = 0; @@ -454,21 +627,12 @@ void DrawingBuffer::releaseResources() m_fbo = 0; m_contextEvictionManager.clear(); - m_lastColorBuffer.clear(); - m_recycledMailboxes.clear(); - m_textureMailboxes.clear(); - - if (m_layer) { + if (m_layer) GraphicsLayer::unregisterContentsLayer(m_layer->layer()); - m_layer.clear(); - } } -unsigned DrawingBuffer::createColorTexture(const IntSize& size) +unsigned DrawingBuffer::createColorTexture() { - if (!m_context) - return 0; - unsigned offscreenColorTexture = m_context->createTexture(); if (!offscreenColorTexture) return 0; @@ -478,8 +642,6 @@ unsigned DrawingBuffer::createColorTexture(const IntSize& size) m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); m_context->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (!size.isEmpty()) - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); return offscreenColorTexture; } @@ -487,7 +649,7 @@ unsigned DrawingBuffer::createColorTexture(const IntSize& size) void DrawingBuffer::createSecondaryBuffers() { // create a multisample FBO - if (multisample()) { + if (m_multisampleMode == ExplicitResolve) { m_multisampleFBO = m_context->createFramebuffer(); m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); m_multisampleColorBuffer = m_context->createRenderbuffer(); @@ -499,17 +661,19 @@ bool DrawingBuffer::resizeFramebuffer(const IntSize& size) // resize regular FBO m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); - m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer); - m_context->texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); - if (m_lastColorBuffer) - m_lastColorBuffer->size = size; + m_context->bindTexture(GL_TEXTURE_2D, m_colorBuffer.textureId); + + allocateTextureMemory(&m_colorBuffer, size); - m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); + if (m_multisampleMode == ImplicitResolve) + m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0, m_sampleCount); + else + m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer.textureId, 0); m_context->bindTexture(GL_TEXTURE_2D, 0); - if (!multisample()) - resizeDepthStencil(size, 0); + if (m_multisampleMode != ExplicitResolve) + resizeDepthStencil(size); if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return false; @@ -518,22 +682,17 @@ bool DrawingBuffer::resizeFramebuffer(const IntSize& size) bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) { - if (multisample()) { - int maxSampleCount = 0; - - m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount); - int sampleCount = std::min(4, maxSampleCount); - + if (m_multisampleMode == ExplicitResolve) { m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_multisampleColorBuffer); - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, m_internalRenderbufferFormat, size.width(), size.height()); + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, m_internalRenderbufferFormat, size.width(), size.height()); if (m_context->getError() == GL_OUT_OF_MEMORY) return false; m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_multisampleColorBuffer); - resizeDepthStencil(size, sampleCount); + resizeDepthStencil(size); if (m_context->checkFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) return false; } @@ -541,35 +700,44 @@ bool DrawingBuffer::resizeMultisampleFramebuffer(const IntSize& size) return true; } -void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount) +void DrawingBuffer::resizeDepthStencil(const IntSize& size) { - if (m_attributes.depth && m_attributes.stencil && m_packedDepthStencilExtensionSupported) { + if (!m_requestedAttributes.depth && !m_requestedAttributes.stencil) + return; + + if (m_packedDepthStencilExtensionSupported) { if (!m_depthStencilBuffer) m_depthStencilBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); else - m_context->renderbufferStorage(GL_RENDERBUFFER, Extensions3D::DEPTH24_STENCIL8, size.width(), size.height()); + m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer); } else { - if (m_attributes.depth) { + if (m_requestedAttributes.depth) { if (!m_depthBuffer) m_depthBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_DEPTH_COMPONENT16, size.width(), size.height()); else m_context->renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer); } - if (m_attributes.stencil) { + if (m_requestedAttributes.stencil) { if (!m_stencilBuffer) m_stencilBuffer = m_context->createRenderbuffer(); m_context->bindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer); - if (multisample()) - m_context->extensions()->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); + if (m_multisampleMode == ImplicitResolve) + m_context->renderbufferStorageMultisampleEXT(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); + else if (m_multisampleMode == ExplicitResolve) + m_context->renderbufferStorageMultisampleCHROMIUM(GL_RENDERBUFFER, m_sampleCount, GL_STENCIL_INDEX8, size.width(), size.height()); else m_context->renderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size.width(), size.height()); m_context->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer); @@ -580,48 +748,46 @@ void DrawingBuffer::resizeDepthStencil(const IntSize& size, int sampleCount) -void DrawingBuffer::clearFramebuffers(GC3Dbitfield clearMask) +void DrawingBuffer::clearFramebuffers(GLbitfield clearMask) { - if (!m_context) - return; - - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); - - m_context->clear(clearMask); - - // The multisample fbo was just cleared, but we also need to clear the non-multisampled buffer too. + // We will clear the multisample FBO, but we also need to clear the non-multisampled buffer. if (m_multisampleFBO) { m_context->bindFramebuffer(GL_FRAMEBUFFER, m_fbo); m_context->clear(GL_COLOR_BUFFER_BIT); - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); } + + m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); + m_context->clear(clearMask); } -void DrawingBuffer::setSize(const IntSize& size) { +void DrawingBuffer::setSize(const IntSize& size) +{ if (m_size == size) return; - s_currentResourceUsePixels += pixelDelta(size); + s_currentResourceUsePixels += pixelDelta(size, m_size); m_size = size; } -int DrawingBuffer::pixelDelta(const IntSize& size) { - return (max(0, size.width()) * max(0, size.height())) - (max(0, m_size.width()) * max(0, m_size.height())); +int DrawingBuffer::pixelDelta(const IntSize& newSize, const IntSize& curSize) +{ + return (max(0, newSize.width()) * max(0, newSize.height())) - (max(0, curSize.width()) * max(0, curSize.height())); } -IntSize DrawingBuffer::adjustSize(const IntSize& size) { - IntSize adjustedSize = size; +IntSize DrawingBuffer::adjustSize(const IntSize& desiredSize, const IntSize& curSize, int maxTextureSize) +{ + IntSize adjustedSize = desiredSize; // Clamp if the desired size is greater than the maximum texture size for the device. - if (adjustedSize.height() > m_maxTextureSize) - adjustedSize.setHeight(m_maxTextureSize); + if (adjustedSize.height() > maxTextureSize) + adjustedSize.setHeight(maxTextureSize); - if (adjustedSize.width() > m_maxTextureSize) - adjustedSize.setWidth(m_maxTextureSize); + if (adjustedSize.width() > maxTextureSize) + adjustedSize.setWidth(maxTextureSize); // Try progressively smaller sizes until we find a size that fits or reach a scale limit. int scaleAttempts = 0; - while ((s_currentResourceUsePixels + pixelDelta(adjustedSize)) > s_maximumResourceUsePixels) { + while ((s_currentResourceUsePixels + pixelDelta(adjustedSize, curSize)) > s_maximumResourceUsePixels) { scaleAttempts++; if (scaleAttempts > s_maxScaleAttempts) return IntSize(); @@ -635,8 +801,9 @@ IntSize DrawingBuffer::adjustSize(const IntSize& size) { return adjustedSize; } -IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) { - IntSize adjustedSize = adjustSize(size); +IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& evictContext) +{ + IntSize adjustedSize = adjustSize(size, m_size, m_maxTextureSize); if (!adjustedSize.isEmpty()) { evictContext = false; return adjustedSize; // Buffer fits without evicting a context. @@ -647,28 +814,26 @@ IntSize DrawingBuffer::adjustSizeWithContextEviction(const IntSize& size, bool& int pixelDelta = oldestSize.width() * oldestSize.height(); s_currentResourceUsePixels -= pixelDelta; - adjustedSize = adjustSize(size); + adjustedSize = adjustSize(size, m_size, m_maxTextureSize); s_currentResourceUsePixels += pixelDelta; evictContext = !adjustedSize.isEmpty(); return adjustedSize; } -void DrawingBuffer::reset(const IntSize& newSize) +bool DrawingBuffer::reset(const IntSize& newSize) { - if (!m_context) - return; - + ASSERT(!newSize.isEmpty()); IntSize adjustedSize; bool evictContext = false; bool isNewContext = m_size.isEmpty(); if (s_allowContextEvictionOnCreate && isNewContext) adjustedSize = adjustSizeWithContextEviction(newSize, evictContext); else - adjustedSize = adjustSize(newSize); + adjustedSize = adjustSize(newSize, m_size, m_maxTextureSize); if (adjustedSize.isEmpty()) - return; + return false; if (evictContext) m_contextEvictionManager->forciblyLoseOldestContext("WARNING: WebGL contexts have exceeded the maximum allowed backbuffer area. Oldest context will be lost."); @@ -686,33 +851,31 @@ void DrawingBuffer::reset(const IntSize& newSize) setSize(adjustedSize); if (adjustedSize.isEmpty()) - return; + return false; } m_context->disable(GL_SCISSOR_TEST); m_context->clearColor(0, 0, 0, 0); m_context->colorMask(true, true, true, true); - GC3Dbitfield clearMask = GL_COLOR_BUFFER_BIT; - if (m_attributes.depth) { + GLbitfield clearMask = GL_COLOR_BUFFER_BIT; + if (m_actualAttributes.depth) { m_context->clearDepth(1.0f); clearMask |= GL_DEPTH_BUFFER_BIT; m_context->depthMask(true); } - if (m_attributes.stencil) { + if (m_actualAttributes.stencil) { m_context->clearStencil(0); clearMask |= GL_STENCIL_BUFFER_BIT; m_context->stencilMaskSeparate(GL_FRONT, 0xFFFFFFFF); } clearFramebuffers(clearMask); + return true; } void DrawingBuffer::commit(long x, long y, long width, long height) { - if (!m_context) - return; - if (width < 0) width = m_size.width(); if (height < 0) @@ -721,14 +884,14 @@ void DrawingBuffer::commit(long x, long y, long width, long height) m_context->makeContextCurrent(); if (m_multisampleFBO && !m_contentsChangeCommitted) { - m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFBO); - m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo); + m_context->bindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, m_multisampleFBO); + m_context->bindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, m_fbo); if (m_scissorEnabled) m_context->disable(GL_SCISSOR_TEST); // Use NEAREST, because there is no scale performed during the blit. - m_context->extensions()->blitFramebuffer(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + m_context->blitFramebufferCHROMIUM(x, y, width, height, x, y, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); if (m_scissorEnabled) m_context->enable(GL_SCISSOR_TEST); @@ -740,7 +903,7 @@ void DrawingBuffer::commit(long x, long y, long width, long height) void DrawingBuffer::restoreFramebufferBinding() { - if (!m_context || !m_framebufferBinding) + if (!m_framebufferBinding) return; m_context->bindFramebuffer(GL_FRAMEBUFFER, m_framebufferBinding); @@ -748,15 +911,162 @@ void DrawingBuffer::restoreFramebufferBinding() bool DrawingBuffer::multisample() const { - return m_attributes.antialias && m_multisampleExtensionSupported; + return m_multisampleMode != None; } void DrawingBuffer::bind() { - if (!m_context) - return; - m_context->bindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo); } +void DrawingBuffer::setPackAlignment(GLint param) +{ + m_packAlignment = param; +} + +void DrawingBuffer::paintRenderingResultsToCanvas(ImageBuffer* imageBuffer) +{ + paintFramebufferToCanvas(framebuffer(), size().width(), size().height(), !m_actualAttributes.premultipliedAlpha, imageBuffer); +} + +PassRefPtr<Uint8ClampedArray> DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height) +{ + if (m_actualAttributes.premultipliedAlpha) + return nullptr; + + width = size().width(); + height = size().height(); + + Checked<int, RecordOverflow> dataSize = 4; + dataSize *= width; + dataSize *= height; + if (dataSize.hasOverflowed()) + return nullptr; + + RefPtr<Uint8ClampedArray> pixels = Uint8ClampedArray::createUninitialized(width * height * 4); + + m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer()); + readBackFramebuffer(pixels->data(), width, height, ReadbackRGBA, WebGLImageConversion::AlphaDoNothing); + flipVertically(pixels->data(), width, height); + + return pixels.release(); +} + +void DrawingBuffer::paintFramebufferToCanvas(int framebuffer, int width, int height, bool premultiplyAlpha, ImageBuffer* imageBuffer) +{ + unsigned char* pixels = 0; + + const SkBitmap& canvasBitmap = imageBuffer->bitmap(); + const SkBitmap* readbackBitmap = 0; + ASSERT(canvasBitmap.colorType() == kPMColor_SkColorType); + if (canvasBitmap.width() == width && canvasBitmap.height() == height) { + // This is the fastest and most common case. We read back + // directly into the canvas's backing store. + readbackBitmap = &canvasBitmap; + m_resizingBitmap.reset(); + } else { + // We need to allocate a temporary bitmap for reading back the + // pixel data. We will then use Skia to rescale this bitmap to + // the size of the canvas's backing store. + if (m_resizingBitmap.width() != width || m_resizingBitmap.height() != height) { + if (!m_resizingBitmap.allocN32Pixels(width, height)) + return; + } + readbackBitmap = &m_resizingBitmap; + } + + // Read back the frame buffer. + SkAutoLockPixels bitmapLock(*readbackBitmap); + pixels = static_cast<unsigned char*>(readbackBitmap->getPixels()); + + m_context->bindFramebuffer(GL_FRAMEBUFFER, framebuffer); + readBackFramebuffer(pixels, width, height, ReadbackSkia, premultiplyAlpha ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing); + flipVertically(pixels, width, height); + + readbackBitmap->notifyPixelsChanged(); + if (m_resizingBitmap.readyToDraw()) { + // We need to draw the resizing bitmap into the canvas's backing store. + SkCanvas canvas(canvasBitmap); + SkRect dst; + dst.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(canvasBitmap.width()), SkIntToScalar(canvasBitmap.height())); + canvas.drawBitmapRect(m_resizingBitmap, 0, dst); + } +} + +void DrawingBuffer::readBackFramebuffer(unsigned char* pixels, int width, int height, ReadbackOrder readbackOrder, WebGLImageConversion::AlphaOp op) +{ + if (m_packAlignment > 4) + m_context->pixelStorei(GL_PACK_ALIGNMENT, 1); + m_context->readPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + if (m_packAlignment > 4) + m_context->pixelStorei(GL_PACK_ALIGNMENT, m_packAlignment); + + size_t bufferSize = 4 * width * height; + + if (readbackOrder == ReadbackSkia) { +#if (SK_R32_SHIFT == 16) && !SK_B32_SHIFT + // Swizzle red and blue channels to match SkBitmap's byte ordering. + // TODO(kbr): expose GL_BGRA as extension. + for (size_t i = 0; i < bufferSize; i += 4) { + std::swap(pixels[i], pixels[i + 2]); + } +#endif + } + + if (op == WebGLImageConversion::AlphaDoPremultiply) { + for (size_t i = 0; i < bufferSize; i += 4) { + pixels[i + 0] = std::min(255, pixels[i + 0] * pixels[i + 3] / 255); + pixels[i + 1] = std::min(255, pixels[i + 1] * pixels[i + 3] / 255); + pixels[i + 2] = std::min(255, pixels[i + 2] * pixels[i + 3] / 255); + } + } else if (op != WebGLImageConversion::AlphaDoNothing) { + ASSERT_NOT_REACHED(); + } +} + +void DrawingBuffer::flipVertically(uint8_t* framebuffer, int width, int height) +{ + m_scanline.resize(width * 4); + uint8* scanline = &m_scanline[0]; + unsigned rowBytes = width * 4; + unsigned count = height / 2; + for (unsigned i = 0; i < count; i++) { + uint8* rowA = framebuffer + i * rowBytes; + uint8* rowB = framebuffer + (height - i - 1) * rowBytes; + memcpy(scanline, rowB, rowBytes); + memcpy(rowB, rowA, rowBytes); + memcpy(rowA, scanline, rowBytes); + } +} + +void DrawingBuffer::texImage2DResourceSafe(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint unpackAlignment) +{ + ASSERT(unpackAlignment == 1 || unpackAlignment == 2 || unpackAlignment == 4 || unpackAlignment == 8); + m_context->texImage2D(target, level, internalformat, width, height, border, format, type, 0); +} + +void DrawingBuffer::allocateTextureMemory(TextureInfo* info, const IntSize& size) +{ + if (RuntimeEnabledFeatures::webGLImageChromiumEnabled()) { + deleteChromiumImageForTexture(info); + + info->imageId = m_context->createImageCHROMIUM(size.width(), size.height(), GL_RGBA8_OES, GC3D_IMAGE_SCANOUT_CHROMIUM); + if (info->imageId) { + m_context->bindTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); + return; + } + } + + texImage2DResourceSafe(GL_TEXTURE_2D, 0, m_internalColorFormat, size.width(), size.height(), 0, m_colorFormat, GL_UNSIGNED_BYTE); +} + +void DrawingBuffer::deleteChromiumImageForTexture(TextureInfo* info) +{ + if (info->imageId) { + m_context->releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, info->imageId); + m_context->destroyImageCHROMIUM(info->imageId); + info->imageId = 0; + } +} + } // namespace WebCore |