bool DrawingBuffer::prepareMailbox(WebKit::WebExternalTextureMailbox* outMailbox, WebKit::WebExternalBitmap* bitmap) { if (!m_context || !m_contentsChanged || !m_lastColorBuffer) return false; m_context->makeContextCurrent(); // Resolve the multisampled buffer into the texture referenced by m_lastColorBuffer mailbox. if (multisample()) 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; if (pixels) m_context->readBackFramebuffer(pixels, size().width(), size().height(), GraphicsContext3D::ReadbackSkia, op); } // We must restore the texture binding since creating new textures, // consuming and producing mailboxes changes it. ScopedTextureUnit0BindingRestorer restorer(m_context.get(), m_activeTextureUnit, m_texture2DBinding); // First try to recycle an old buffer. RefPtr<MailboxInfo> nextFrontColorBuffer = recycledMailbox(); // No buffer available to recycle, create a new one. if (!nextFrontColorBuffer) { unsigned newColorBuffer = createColorTexture(m_size); // Bad things happened, abandon ship. if (!newColorBuffer) return false; nextFrontColorBuffer = createNewMailbox(newColorBuffer); } if (m_preserveDrawingBuffer == Discard) { m_colorBuffer = nextFrontColorBuffer->textureId; swap(nextFrontColorBuffer, m_lastColorBuffer); // 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(GraphicsContext3D::FRAMEBUFFER, m_fbo); m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0); } else { Extensions3D* extensions = m_context->extensions(); extensions->copyTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, m_colorBuffer, nextFrontColorBuffer->textureId, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE); } if (multisample() && !m_framebufferBinding) bind(); else restoreFramebufferBinding(); m_contentsChanged = false; context()->bindTexture(GraphicsContext3D::TEXTURE_2D, nextFrontColorBuffer->textureId); context()->produceTextureCHROMIUM(GraphicsContext3D::TEXTURE_2D, nextFrontColorBuffer->mailbox.name); context()->flush(); m_context->markLayerComposited(); *outMailbox = nextFrontColorBuffer->mailbox; m_frontColorBuffer = nextFrontColorBuffer->textureId; return true; }
bool DrawingBuffer::prepareMailbox(blink::WebExternalTextureMailbox* outMailbox, blink::WebExternalBitmap* bitmap) { if (!m_context || !m_contentsChanged) return false; m_context->makeContextCurrent(); // 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; WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing; if (pixels) readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op); } // We must restore the texture binding since creating new textures, // consuming and producing mailboxes changes it. ScopedTextureUnit0BindingRestorer restorer(m_context, m_activeTextureUnit, m_texture2DBinding); // First try to recycle an old buffer. RefPtr<MailboxInfo> frontColorBufferMailbox = recycledMailbox(); // No buffer available to recycle, create a new one. if (!frontColorBufferMailbox) { unsigned newColorBuffer = createColorTexture(m_size); // Bad things happened, abandon ship. if (!newColorBuffer) return false; frontColorBufferMailbox = createNewMailbox(newColorBuffer); } if (m_preserveDrawingBuffer == Discard) { swap(frontColorBufferMailbox->textureId, 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); if (m_multisampleMode == ImplicitResolve) m_context->framebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0, m_sampleCount); else m_context->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffer, 0); } else { m_context->copyTextureCHROMIUM(GL_TEXTURE_2D, m_colorBuffer, frontColorBufferMailbox->textureId, 0, GL_RGBA, GL_UNSIGNED_BYTE); } if (m_multisampleMode != None && !m_framebufferBinding) bind(); else restoreFramebufferBinding(); m_contentsChanged = false; m_context->bindTexture(GL_TEXTURE_2D, frontColorBufferMailbox->textureId); m_context->produceTextureCHROMIUM(GL_TEXTURE_2D, frontColorBufferMailbox->mailbox.name); m_context->flush(); frontColorBufferMailbox->mailbox.syncPoint = m_context->insertSyncPoint(); markLayerComposited(); *outMailbox = frontColorBufferMailbox->mailbox; m_frontColorBuffer = frontColorBufferMailbox->textureId; return true; }
bool DrawingBuffer::prepareMailbox(WebExternalTextureMailbox* outMailbox, WebExternalBitmap* bitmap) { 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; } ASSERT(!m_isHidden); if (!m_contentsChanged) return false; if (m_newMailboxCallback) (*m_newMailboxCallback)(); // Resolve the multisampled buffer into m_colorBuffer texture. if (m_antiAliasingMode != None) commit(); if (bitmap) { bitmap->setSize(size()); unsigned char* pixels = bitmap->pixels(); bool needPremultiply = m_wantAlphaChannel && !m_premultipliedAlpha; WebGLImageConversion::AlphaOp op = needPremultiply ? WebGLImageConversion::AlphaDoPremultiply : WebGLImageConversion::AlphaDoNothing; if (pixels) readBackFramebuffer(pixels, size().width(), size().height(), ReadbackSkia, op); } // 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<MailboxInfo> frontColorBufferMailbox = recycledMailbox(); // No buffer available to recycle, create a new one. if (!frontColorBufferMailbox) frontColorBufferMailbox = createNewMailbox(createTextureAndAllocateMemory(m_size)); if (m_preserveDrawingBuffer == Discard) { std::swap(frontColorBufferMailbox->textureInfo, m_colorBuffer); attachColorBufferToReadFramebuffer(); if (m_discardFramebufferSupported) { // Explicitly discard 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_gl->DiscardFramebufferEXT(GL_FRAMEBUFFER, 3, attachments); } } else { m_gl->CopyTextureCHROMIUM(m_colorBuffer.textureId, frontColorBufferMailbox->textureInfo.textureId, frontColorBufferMailbox->textureInfo.parameters.internalColorFormat, GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); } restoreFramebufferBindings(); m_contentsChanged = false; m_gl->ProduceTextureDirectCHROMIUM(frontColorBufferMailbox->textureInfo.textureId, frontColorBufferMailbox->textureInfo.parameters.target, frontColorBufferMailbox->mailbox.name); const GLuint64 fenceSync = m_gl->InsertFenceSyncCHROMIUM(); m_gl->Flush(); m_gl->GenSyncTokenCHROMIUM(fenceSync, frontColorBufferMailbox->mailbox.syncToken); frontColorBufferMailbox->mailbox.validSyncToken = true; frontColorBufferMailbox->mailbox.allowOverlay = frontColorBufferMailbox->textureInfo.imageId != 0; frontColorBufferMailbox->mailbox.textureTarget = frontColorBufferMailbox->textureInfo.parameters.target; frontColorBufferMailbox->mailbox.textureSize = WebSize(m_size.width(), m_size.height()); setBufferClearNeeded(true); // 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, frontColorBufferMailbox->mailbox }; return true; }