content/canvas/src/WebGLRenderbuffer.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/canvas/src/WebGLRenderbuffer.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,244 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "WebGLContext.h"
    1.10 +#include "WebGLRenderbuffer.h"
    1.11 +#include "WebGLTexture.h"
    1.12 +#include "mozilla/dom/WebGLRenderingContextBinding.h"
    1.13 +#include "GLContext.h"
    1.14 +#include "ScopedGLHelpers.h"
    1.15 +
    1.16 +using namespace mozilla;
    1.17 +using namespace mozilla::gl;
    1.18 +
    1.19 +static GLenum
    1.20 +DepthStencilDepthFormat(GLContext* gl) {
    1.21 +    // We might not be able to get 24-bit, so let's pretend!
    1.22 +    if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
    1.23 +        return LOCAL_GL_DEPTH_COMPONENT16;
    1.24 +
    1.25 +    return LOCAL_GL_DEPTH_COMPONENT24;
    1.26 +}
    1.27 +
    1.28 +static bool
    1.29 +SupportsDepthStencil(GLContext* gl) {
    1.30 +    return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
    1.31 +           gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
    1.32 +}
    1.33 +
    1.34 +static bool
    1.35 +NeedsDepthStencilEmu(GLContext* gl, GLenum internalFormat) {
    1.36 +    MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
    1.37 +    if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
    1.38 +        return false;
    1.39 +
    1.40 +    return !SupportsDepthStencil(gl);
    1.41 +}
    1.42 +
    1.43 +JSObject*
    1.44 +WebGLRenderbuffer::WrapObject(JSContext *cx) {
    1.45 +    return dom::WebGLRenderbufferBinding::Wrap(cx, this);
    1.46 +}
    1.47 +
    1.48 +WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
    1.49 +    : WebGLContextBoundObject(context)
    1.50 +    , mPrimaryRB(0)
    1.51 +    , mSecondaryRB(0)
    1.52 +    , mInternalFormat(0)
    1.53 +    , mInternalFormatForGL(0)
    1.54 +    , mHasEverBeenBound(false)
    1.55 +    , mImageDataStatus(WebGLImageDataStatus::NoImageData)
    1.56 +{
    1.57 +    SetIsDOMBinding();
    1.58 +    mContext->MakeContextCurrent();
    1.59 +
    1.60 +    mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
    1.61 +    if (!SupportsDepthStencil(mContext->gl))
    1.62 +        mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);
    1.63 +
    1.64 +    mContext->mRenderbuffers.insertBack(this);
    1.65 +}
    1.66 +
    1.67 +void
    1.68 +WebGLRenderbuffer::Delete() {
    1.69 +    mContext->MakeContextCurrent();
    1.70 +
    1.71 +    mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
    1.72 +    if (mSecondaryRB)
    1.73 +        mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);
    1.74 +
    1.75 +    LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
    1.76 +}
    1.77 +
    1.78 +int64_t
    1.79 +WebGLRenderbuffer::MemoryUsage() const {
    1.80 +    int64_t pixels = int64_t(Width()) * int64_t(Height());
    1.81 +
    1.82 +    GLenum primaryFormat = InternalFormatForGL();
    1.83 +    // If there is no defined format, we're not taking up any memory
    1.84 +    if (!primaryFormat) {
    1.85 +        return 0;
    1.86 +    }
    1.87 +
    1.88 +    int64_t secondarySize = 0;
    1.89 +    if (mSecondaryRB) {
    1.90 +        if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
    1.91 +            primaryFormat = DepthStencilDepthFormat(mContext->gl);
    1.92 +            secondarySize = 1*pixels; // STENCIL_INDEX8
    1.93 +        } else {
    1.94 +            secondarySize = 1*1*2; // 1x1xRGBA4
    1.95 +        }
    1.96 +    }
    1.97 +
    1.98 +    int64_t primarySize = 0;
    1.99 +    switch (primaryFormat) {
   1.100 +        case LOCAL_GL_STENCIL_INDEX8:
   1.101 +            primarySize = 1*pixels;
   1.102 +            break;
   1.103 +        case LOCAL_GL_RGBA4:
   1.104 +        case LOCAL_GL_RGB5_A1:
   1.105 +        case LOCAL_GL_RGB565:
   1.106 +        case LOCAL_GL_DEPTH_COMPONENT16:
   1.107 +            primarySize = 2*pixels;
   1.108 +            break;
   1.109 +        case LOCAL_GL_RGB8:
   1.110 +        case LOCAL_GL_DEPTH_COMPONENT24:
   1.111 +            primarySize = 3*pixels;
   1.112 +            break;
   1.113 +        case LOCAL_GL_RGBA8:
   1.114 +        case LOCAL_GL_SRGB8_ALPHA8_EXT:
   1.115 +        case LOCAL_GL_DEPTH24_STENCIL8:
   1.116 +        case LOCAL_GL_DEPTH_COMPONENT32:
   1.117 +            primarySize = 4*pixels;
   1.118 +            break;
   1.119 +        case LOCAL_GL_RGB16F:
   1.120 +            primarySize = 2*3*pixels;
   1.121 +            break;
   1.122 +        case LOCAL_GL_RGBA16F:
   1.123 +            primarySize = 2*4*pixels;
   1.124 +            break;
   1.125 +        case LOCAL_GL_RGB32F:
   1.126 +            primarySize = 4*3*pixels;
   1.127 +            break;
   1.128 +        case LOCAL_GL_RGBA32F:
   1.129 +            primarySize = 4*4*pixels;
   1.130 +            break;
   1.131 +        default:
   1.132 +            MOZ_ASSERT(false, "Unknown `primaryFormat`.");
   1.133 +            break;
   1.134 +    }
   1.135 +
   1.136 +    return primarySize + secondarySize;
   1.137 +}
   1.138 +
   1.139 +void
   1.140 +WebGLRenderbuffer::BindRenderbuffer() const {
   1.141 +    /* Do this explicitly here, since the meaning changes for depth-stencil emu.
   1.142 +     * Under normal circumstances, there's only one RB: `mPrimaryRB`.
   1.143 +     * `mSecondaryRB` is used when we have to pretend that the renderbuffer is
   1.144 +     * DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
   1.145 +     * STENCIL buffer `mSecondaryRB`.
   1.146 +     *
   1.147 +     * In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
   1.148 +     * we can only bind one of them at a time. We choose to unconditionally bind
   1.149 +     * the depth RB. When we need to ask about the stencil buffer (say, how many
   1.150 +     * stencil bits we have), we temporarily bind the stencil RB, so that it
   1.151 +     * looks like we're just asking the question of a combined DEPTH_STENCIL
   1.152 +     * buffer.
   1.153 +     */
   1.154 +    mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
   1.155 +}
   1.156 +
   1.157 +void
   1.158 +WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width, GLsizei height) const {
   1.159 +    GLContext* gl = mContext->gl;
   1.160 +
   1.161 +    GLenum primaryFormat = internalFormat;
   1.162 +    GLenum secondaryFormat = 0;
   1.163 +
   1.164 +    if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
   1.165 +        primaryFormat = DepthStencilDepthFormat(gl);
   1.166 +        secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
   1.167 +    }
   1.168 +
   1.169 +    gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);
   1.170 +
   1.171 +    if (!mSecondaryRB) {
   1.172 +        MOZ_ASSERT(!secondaryFormat);
   1.173 +        return;
   1.174 +    }
   1.175 +    // We can't leave the secondary RB unspecified either, since we should
   1.176 +    // handle the case where we attach a non-depth-stencil RB to a
   1.177 +    // depth-stencil attachment point, or attach this depth-stencil RB to a
   1.178 +    // non-depth-stencil attachment point.
   1.179 +    ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
   1.180 +    if (secondaryFormat) {
   1.181 +        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, secondaryFormat, width, height);
   1.182 +    } else {
   1.183 +        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
   1.184 +    }
   1.185 +}
   1.186 +
   1.187 +void
   1.188 +WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const {
   1.189 +    GLContext* gl = mContext->gl;
   1.190 +    if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
   1.191 +        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment, LOCAL_GL_RENDERBUFFER, mPrimaryRB);
   1.192 +        return;
   1.193 +    }
   1.194 +
   1.195 +    GLuint stencilRB = mPrimaryRB;
   1.196 +    if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
   1.197 +        printf_stderr("DEV-ONLY: Using secondary buffer to emulate DepthStencil.\n");
   1.198 +        MOZ_ASSERT(mSecondaryRB);
   1.199 +        stencilRB = mSecondaryRB;
   1.200 +    }
   1.201 +    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,   LOCAL_GL_RENDERBUFFER, mPrimaryRB);
   1.202 +    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, stencilRB);
   1.203 +}
   1.204 +
   1.205 +GLint
   1.206 +WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
   1.207 +    GLContext* gl = mContext->gl;
   1.208 +
   1.209 +    switch (pname) {
   1.210 +        case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: {
   1.211 +            if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
   1.212 +                if (gl->WorkAroundDriverBugs() &&
   1.213 +                    gl->Renderer() == GLRenderer::Tegra)
   1.214 +                {
   1.215 +                    return 8;
   1.216 +                }
   1.217 +
   1.218 +                ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
   1.219 +
   1.220 +                GLint i = 0;
   1.221 +                gl->fGetRenderbufferParameteriv(target, pname, &i);
   1.222 +                return i;
   1.223 +            }
   1.224 +            // Fall through otherwise.
   1.225 +        }
   1.226 +        case LOCAL_GL_RENDERBUFFER_WIDTH:
   1.227 +        case LOCAL_GL_RENDERBUFFER_HEIGHT:
   1.228 +        case LOCAL_GL_RENDERBUFFER_RED_SIZE:
   1.229 +        case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
   1.230 +        case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
   1.231 +        case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
   1.232 +        case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE: {
   1.233 +            GLint i = 0;
   1.234 +            gl->fGetRenderbufferParameteriv(target, pname, &i);
   1.235 +            return i;
   1.236 +        }
   1.237 +    }
   1.238 +
   1.239 +    MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
   1.240 +    return 0;
   1.241 +}
   1.242 +
   1.243 +
   1.244 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
   1.245 +
   1.246 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
   1.247 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)

mercurial