Beispiel #1
0
WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GC3Denum attachment) const
{
    if (!object())
        return 0;
    WebGLAttachment* attachmentObject = getAttachment(attachment);
    return attachmentObject ? attachmentObject->getObject() : 0;
}
Beispiel #2
0
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GC3Denum attachment)
{
    ASSERT(isBound());
    if (!object())
        return;

    WebGLAttachment* attachmentObject = getAttachment(attachment);
    if (attachmentObject) {
        attachmentObject->onDetached(context()->graphicsContext3D());
        m_attachments.remove(attachment);
        drawBuffersIfNecessary(false);
        switch (attachment) {
        case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
            attach(GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
            attach(GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
            break;
        case GraphicsContext3D::DEPTH_ATTACHMENT:
            attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::DEPTH_ATTACHMENT);
            break;
        case GraphicsContext3D::STENCIL_ATTACHMENT:
            attach(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT, GraphicsContext3D::STENCIL_ATTACHMENT);
            break;
        }
    }
}
bool WebGLFramebuffer::hasStencilBuffer() const
{
    WebGLAttachment* attachment = getAttachment(GL_STENCIL_ATTACHMENT);
    if (!attachment)
        attachment = getAttachment(GL_DEPTH_STENCIL_ATTACHMENT);
    return attachment && attachment->valid();
}
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, GLenum attachment)
{
    ASSERT(isBound(target));
    if (!m_object)
        return;

    WebGLAttachment* attachmentObject = getAttachment(attachment);
    if (attachmentObject) {
        attachmentObject->onDetached(context()->webContext());
        m_attachments.remove(attachment);
        drawBuffersIfNecessary(false);
        switch (attachment) {
        case GL_DEPTH_STENCIL_ATTACHMENT:
            attach(target, GL_DEPTH_ATTACHMENT, GL_DEPTH_ATTACHMENT);
            attach(target, GL_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
            break;
        case GL_DEPTH_ATTACHMENT:
            attach(target, GL_DEPTH_STENCIL_ATTACHMENT, GL_DEPTH_ATTACHMENT);
            break;
        case GL_STENCIL_ATTACHMENT:
            attach(target, GL_DEPTH_STENCIL_ATTACHMENT, GL_STENCIL_ATTACHMENT);
            break;
        }
    }
}
WebGLSharedObject* WebGLFramebuffer::getAttachmentObject(GLenum attachment) const
{
    if (!m_object)
        return nullptr;
    WebGLAttachment* attachmentObject = getAttachment(attachment);
    return attachmentObject ? attachmentObject->object() : nullptr;
}
void WebGLFramebuffer::attach(GLenum target, GLenum attachment, GLenum attachmentPoint)
{
    ASSERT(isBound(target));
    WebGLAttachment* attachmentObject = getAttachment(attachment);
    if (attachmentObject)
        attachmentObject->attach(context()->webContext(), target, attachmentPoint);
}
Beispiel #7
0
void WebGLFramebuffer::attach(GC3Denum attachment, GC3Denum attachmentPoint)
{
    ASSERT(isBound());
    WebGLAttachment* attachmentObject = getAttachment(attachment);
    if (attachmentObject)
        attachmentObject->attach(context()->graphicsContext3D(), attachmentPoint);
}
Beispiel #8
0
bool WebGLFramebuffer::hasStencilBuffer() const
{
    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::STENCIL_ATTACHMENT);
    if (!attachment)
        attachment = getAttachment(GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT);
    return attachment && attachment->isValid();
}
GLenum WebGLFramebuffer::colorBufferFormat() const
{
    if (!m_object)
        return 0;
    WebGLAttachment* attachment = getAttachment(GL_COLOR_ATTACHMENT0);
    if (!attachment)
        return 0;
    return attachment->format();
}
Beispiel #10
0
GC3Denum WebGLFramebuffer::getColorBufferFormat() const
{
    if (!object())
        return 0;
    WebGLAttachment* attachment = getAttachment(GraphicsContext3D::COLOR_ATTACHMENT0);
    if (!attachment)
        return 0;
    return attachment->getFormat();
}
bool WebGLFramebuffer::getReadBufferFormatAndType(GLenum* format, GLenum* type) const
{
    if (m_readBuffer == GL_NONE)
        return false;
    WebGLAttachment* image = getAttachment(m_readBuffer);
    if (!image)
        return false;
    if (format)
        *format = image->format();
    if (type)
        *type = image->type();
    return true;
}
Beispiel #12
0
GC3Denum WebGLFramebuffer::checkStatus(const char** reason) const
{
    unsigned int count = 0;
    GC3Dsizei width = 0, height = 0;
    bool haveDepth = false;
    bool haveStencil = false;
    bool haveDepthStencil = false;
    for (AttachmentMap::const_iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
        WebGLAttachment* attachment = it->value.get();
        if (!isAttachmentComplete(attachment, it->key, reason))
            return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        if (!attachment->isValid()) {
            *reason = "attachment is not valid";
            return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
        }
        if (!attachment->getFormat()) {
            *reason = "attachment is an unsupported format";
            return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        }
        switch (it->key) {
        case GraphicsContext3D::DEPTH_ATTACHMENT:
            haveDepth = true;
            break;
        case GraphicsContext3D::STENCIL_ATTACHMENT:
            haveStencil = true;
            break;
        case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
            haveDepthStencil = true;
            break;
        }
        if (!count) {
            width = attachment->getWidth();
            height = attachment->getHeight();
        } else {
            if (width != attachment->getWidth() || height != attachment->getHeight()) {
                *reason = "attachments do not have the same dimensions";
                return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
            }
        }
        ++count;
    }
    if (!count) {
        *reason = "no attachments";
        return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    }
    if (!width || !height) {
        *reason = "framebuffer has a 0 dimension";
        return GraphicsContext3D::FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    }
    // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
        *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
        return GraphicsContext3D::FRAMEBUFFER_UNSUPPORTED;
    }
    return GraphicsContext3D::FRAMEBUFFER_COMPLETE;
}
Beispiel #13
0
GLenum WebGLFramebuffer::checkStatus(const char** reason) const
{
    unsigned count = 0;
    GLsizei width = 0, height = 0;
    bool haveDepth = false;
    bool haveStencil = false;
    bool haveDepthStencil = false;
    for (const auto& it : m_attachments) {
        WebGLAttachment* attachment = it.value.get();
        if (!isAttachmentComplete(attachment, it.key, reason))
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        if (!attachment->valid()) {
            *reason = "attachment is not valid";
            return GL_FRAMEBUFFER_UNSUPPORTED;
        }
        if (!attachment->format()) {
            *reason = "attachment is an unsupported format";
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        }
        switch (it.key) {
        case GL_DEPTH_ATTACHMENT:
            haveDepth = true;
            break;
        case GL_STENCIL_ATTACHMENT:
            haveStencil = true;
            break;
        case GC3D_DEPTH_STENCIL_ATTACHMENT_WEBGL:
            haveDepthStencil = true;
            break;
        }
        if (!count) {
            width = attachment->width();
            height = attachment->height();
        } else {
            if (width != attachment->width() || height != attachment->height()) {
                *reason = "attachments do not have the same dimensions";
                return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
            }
        }
        ++count;
    }
    if (!count) {
        *reason = "no attachments";
        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    }
    if (!width || !height) {
        *reason = "framebuffer has a 0 dimension";
        return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    }
    // WebGL specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    if ((haveDepthStencil && (haveDepth || haveStencil)) || (haveDepth && haveStencil)) {
        *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
        return GL_FRAMEBUFFER_UNSUPPORTED;
    }
    return GL_FRAMEBUFFER_COMPLETE;
}
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(GLenum target, WebGLSharedObject* attachment)
{
    ASSERT(isBound(target));
    if (!m_object)
        return;
    if (!attachment)
        return;

    bool checkMore = true;
    while (checkMore) {
        checkMore = false;
        for (const auto& it : m_attachments) {
            WebGLAttachment* attachmentObject = it.value.get();
            if (attachmentObject->isSharedObject(attachment)) {
                GLenum attachmentType = it.key;
                attachmentObject->unattach(context()->webContext(), target, attachmentType);
                removeAttachmentFromBoundFramebuffer(target, attachmentType);
                checkMore = true;
                break;
            }
        }
    }
}
Beispiel #15
0
void WebGLFramebuffer::removeAttachmentFromBoundFramebuffer(WebGLSharedObject* attachment)
{
    ASSERT(isBound());
    if (!object())
        return;
    if (!attachment)
        return;

    bool checkMore = true;
    while (checkMore) {
        checkMore = false;
        for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
            WebGLAttachment* attachmentObject = it->value.get();
            if (attachmentObject->isSharedObject(attachment)) {
                GC3Denum attachmentType = it->key;
                attachmentObject->unattach(context()->graphicsContext3D(), attachmentType);
                removeAttachmentFromBoundFramebuffer(attachmentType);
                checkMore = true;
                break;
            }
        }
    }
}
GLenum WebGLFramebuffer::checkStatus(const char** reason) const
{
    unsigned count = 0;
    GLsizei width = 0, height = 0, depth = 0;
    WebGLAttachment* depthAttachment = nullptr;
    WebGLAttachment* stencilAttachment = nullptr;
    WebGLAttachment* depthStencilAttachment = nullptr;
    bool isWebGL2OrHigher = context()->isWebGL2OrHigher();
    for (const auto& it : m_attachments) {
        WebGLAttachment* attachment = it.value.get();
        if (!isAttachmentComplete(attachment, it.key, reason))
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        if (!attachment->valid()) {
            *reason = "attachment is not valid";
            return GL_FRAMEBUFFER_UNSUPPORTED;
        }
        if (!attachment->format()) {
            *reason = "attachment is an unsupported format";
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        }
        switch (it.key) {
        case GL_DEPTH_ATTACHMENT:
            depthAttachment = attachment;
            break;
        case GL_STENCIL_ATTACHMENT:
            stencilAttachment = attachment;
            break;
        case GL_DEPTH_STENCIL_ATTACHMENT:
            depthStencilAttachment = attachment;
            break;
        }
        // Note: In GLES 3, images for a framebuffer need not to have the same dimensions to be framebuffer complete.
        // However, in Direct3D 11, on top of which OpenGL ES 3 behavior is emulated in Windows, all render targets
        // must have the same size in all dimensions. In order to have consistent WebGL 2 behaviors across platforms,
        // we generate FRAMEBUFFER_INCOMPLETE_DIMENSIONS in this situation.
        if (!count) {
            width = attachment->width();
            height = attachment->height();
            depth = attachment->depth();
        } else {
            if (width != attachment->width() || height != attachment->height() || depth != attachment->depth()) {
                *reason = "attachments do not have the same dimensions";
                return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
            }
        }
        ++count;
    }
    if (!count) {
        *reason = "no attachments";
        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    }
    // WebGL 1 specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    if (!isWebGL2OrHigher
        && ((depthStencilAttachment && (depthAttachment || stencilAttachment))
            || (depthAttachment && stencilAttachment))) {
        *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
        return GL_FRAMEBUFFER_UNSUPPORTED;
    }
    if (isWebGL2OrHigher
        && (depthAttachment && stencilAttachment && depthAttachment->object() != stencilAttachment->object())) {
        *reason = "both DEPTH/STENCIL attachments are present and not the same image";
        return GL_FRAMEBUFFER_UNSUPPORTED;
    }
    return GL_FRAMEBUFFER_COMPLETE;
}
GLenum WebGLFramebuffer::checkStatus(const char** reason) const
{
    unsigned count = 0;
    GLsizei width = 0, height = 0;
    WebGLAttachment* depthAttachment = nullptr;
    WebGLAttachment* stencilAttachment = nullptr;
    WebGLAttachment* depthStencilAttachment = nullptr;
    bool isWebGL2OrHigher = context()->isWebGL2OrHigher();
    for (const auto& it : m_attachments) {
        WebGLAttachment* attachment = it.value.get();
        if (!isAttachmentComplete(attachment, it.key, reason))
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        if (!attachment->valid()) {
            *reason = "attachment is not valid";
            return GL_FRAMEBUFFER_UNSUPPORTED;
        }
        if (!attachment->format()) {
            *reason = "attachment is an unsupported format";
            return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
        }
        switch (it.key) {
        case GL_DEPTH_ATTACHMENT:
            depthAttachment = attachment;
            break;
        case GL_STENCIL_ATTACHMENT:
            stencilAttachment = attachment;
            break;
        case GL_DEPTH_STENCIL_ATTACHMENT:
            depthStencilAttachment = attachment;
            break;
        }
        if (!isWebGL2OrHigher) {
            if (!count) {
                width = attachment->width();
                height = attachment->height();
            } else {
                if (width != attachment->width() || height != attachment->height()) {
                    *reason = "attachments do not have the same dimensions";
                    return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
                }
            }
        }
        ++count;
    }
    if (!count) {
        *reason = "no attachments";
        return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    }
    // WebGL 1 specific: no conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments.
    if (!isWebGL2OrHigher
        && ((depthStencilAttachment && (depthAttachment || stencilAttachment))
            || (depthAttachment && stencilAttachment))) {
        *reason = "conflicting DEPTH/STENCIL/DEPTH_STENCIL attachments";
        return GL_FRAMEBUFFER_UNSUPPORTED;
    }
    if (isWebGL2OrHigher
        && (depthAttachment && stencilAttachment && depthAttachment->object() != stencilAttachment->object())) {
        *reason = "both DEPTH/STENCIL attachments are present and not the same image";
        return GL_FRAMEBUFFER_UNSUPPORTED;
    }
    return GL_FRAMEBUFFER_COMPLETE;
}
bool WebGLFramebuffer::initializeAttachments(GraphicsContext3D* g3d, const char** reason)
{
    ASSERT(object());
    GC3Dbitfield mask = 0;

    for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
        GC3Denum attachmentType = it->key;
        WebGLAttachment* attachment = it->value.get();
        if (!attachment->isInitialized())
           mask |= GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
    }
    if (!mask)
        return true;

    // We only clear un-initialized renderbuffers when they are ready to be
    // read, i.e., when the framebuffer is complete.
    if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
        *reason = "framebuffer not complete";
        return false;
    }

    bool initColor = mask & GraphicsContext3D::COLOR_BUFFER_BIT;
    bool initDepth = mask & GraphicsContext3D::DEPTH_BUFFER_BIT;
    bool initStencil = mask & GraphicsContext3D::STENCIL_BUFFER_BIT;

    GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
    GC3Dint stencilClearValue = 0;
    GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
    GC3Duint stencilMask = 0xffffffff;
    GC3Dboolean isScissorEnabled = 0;
    GC3Dboolean isDitherEnabled = 0;
    if (initColor) {
        g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
        g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
        g3d->clearColor(0, 0, 0, 0);
        g3d->colorMask(true, true, true, true);
    }
    if (initDepth) {
        g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
        g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
        g3d->clearDepth(1.0f);
        g3d->depthMask(true);
    }
    if (initStencil) {
        g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
        g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask));
        g3d->clearStencil(0);
        g3d->stencilMask(0xffffffff);
    }
    isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
    g3d->disable(GraphicsContext3D::SCISSOR_TEST);
    isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
    g3d->disable(GraphicsContext3D::DITHER);

    g3d->clear(mask);

    if (initColor) {
        g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
        g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
    }
    if (initDepth) {
        g3d->clearDepth(depthClearValue);
        g3d->depthMask(depthMask);
    }
    if (initStencil) {
        g3d->clearStencil(stencilClearValue);
        g3d->stencilMask(stencilMask);
    }
    if (isScissorEnabled)
        g3d->enable(GraphicsContext3D::SCISSOR_TEST);
    else
        g3d->disable(GraphicsContext3D::SCISSOR_TEST);
    if (isDitherEnabled)
        g3d->enable(GraphicsContext3D::DITHER);
    else
        g3d->disable(GraphicsContext3D::DITHER);

    for (AttachmentMap::iterator it = m_attachments.begin(); it != m_attachments.end(); ++it) {
        GC3Denum attachmentType = it->key;
        WebGLAttachment* attachment = it->value.get();
        GC3Dbitfield bits = GraphicsContext3D::getClearBitsByAttachmentType(attachmentType);
        if (bits & mask)
            attachment->setInitialized();
    }
    return true;
}