Example #1
0
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.config() == SkBitmap::kARGB_8888_Config);
    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) {
            m_resizingBitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
            if (!m_resizingBitmap.allocPixels())
                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);
    }
}
Example #2
0
PassRefPtr<Uint8ClampedArray> DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height)
{
    if (m_attributes.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();
}
Example #3
0
bool DrawingBuffer::paintRenderingResultsToImageData(int& width, int& height, SourceDrawingBuffer sourceBuffer, WTF::ArrayBufferContents& contents)
{
    ASSERT(!m_premultipliedAlpha);
    width = size().width();
    height = size().height();

    CheckedNumeric<int> dataSize = 4;
    dataSize *= width;
    dataSize *= height;
    if (!dataSize.IsValid())
        return false;

    WTF::ArrayBufferContents pixels(width * height, 4, WTF::ArrayBufferContents::NotShared, WTF::ArrayBufferContents::DontInitialize);

    GLuint fbo = 0;
    if (sourceBuffer == FrontBuffer && m_frontColorBuffer.texInfo.textureId) {
        m_gl->GenFramebuffers(1, &fbo);
        m_gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
        m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_frontColorBuffer.texInfo.parameters.target, m_frontColorBuffer.texInfo.textureId, 0);
    } else {
        m_gl->BindFramebuffer(GL_FRAMEBUFFER, framebuffer());
    }

    readBackFramebuffer(static_cast<unsigned char*>(pixels.data()), width, height, ReadbackRGBA, WebGLImageConversion::AlphaDoNothing);
    flipVertically(static_cast<uint8_t*>(pixels.data()), width, height);

    if (fbo) {
        m_gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_frontColorBuffer.texInfo.parameters.target, 0, 0);
        m_gl->DeleteFramebuffers(1, &fbo);
    }

    restoreFramebufferBindings();

    pixels.transfer(contents);
    return true;
}
Example #4
0
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;
}
Example #5
0
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;
}