DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (d1ed7de67f5a)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "WebGLContext.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "GLContext.h"
#include "ScopedGLHelpers.h"

using namespace mozilla;
using namespace mozilla::gl;

static GLenum
DepthStencilDepthFormat(GLContext* gl) {
    // We might not be able to get 24-bit, so let's pretend!
    if (gl->IsGLES() && !gl->IsExtensionSupported(gl::GLContext::OES_depth24))
        return LOCAL_GL_DEPTH_COMPONENT16;

    return LOCAL_GL_DEPTH_COMPONENT24;
}

static bool
SupportsDepthStencil(GLContext* gl) {
    return gl->IsExtensionSupported(GLContext::EXT_packed_depth_stencil) ||
           gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil);
}

static bool
NeedsDepthStencilEmu(GLContext* gl, GLenum internalFormat) {
    MOZ_ASSERT(internalFormat != LOCAL_GL_DEPTH_STENCIL);
    if (internalFormat != LOCAL_GL_DEPTH24_STENCIL8)
        return false;

    return !SupportsDepthStencil(gl);
}

JSObject*
WebGLRenderbuffer::WrapObject(JSContext *cx) {
    return dom::WebGLRenderbufferBinding::Wrap(cx, this);
}

WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
    : WebGLBindableName()
    , WebGLContextBoundObject(context)
    , mPrimaryRB(0)
    , mSecondaryRB(0)
    , mInternalFormat(0)
    , mInternalFormatForGL(0)
    , mImageDataStatus(WebGLImageDataStatus::NoImageData)
{
    SetIsDOMBinding();
    mContext->MakeContextCurrent();

    mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
    if (!SupportsDepthStencil(mContext->gl))
        mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);

    mContext->mRenderbuffers.insertBack(this);
}

void
WebGLRenderbuffer::Delete() {
    mContext->MakeContextCurrent();

    mContext->gl->fDeleteRenderbuffers(1, &mPrimaryRB);
    if (mSecondaryRB)
        mContext->gl->fDeleteRenderbuffers(1, &mSecondaryRB);

    LinkedListElement<WebGLRenderbuffer>::removeFrom(mContext->mRenderbuffers);
}

int64_t
WebGLRenderbuffer::MemoryUsage() const {
    int64_t pixels = int64_t(Width()) * int64_t(Height());

    GLenum primaryFormat = InternalFormatForGL();
    // If there is no defined format, we're not taking up any memory
    if (!primaryFormat) {
        return 0;
    }

    int64_t secondarySize = 0;
    if (mSecondaryRB) {
        if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
            primaryFormat = DepthStencilDepthFormat(mContext->gl);
            secondarySize = 1*pixels; // STENCIL_INDEX8
        } else {
            secondarySize = 1*1*2; // 1x1xRGBA4
        }
    }

    int64_t primarySize = 0;
    switch (primaryFormat) {
        case LOCAL_GL_STENCIL_INDEX8:
            primarySize = 1*pixels;
            break;
        case LOCAL_GL_RGBA4:
        case LOCAL_GL_RGB5_A1:
        case LOCAL_GL_RGB565:
        case LOCAL_GL_DEPTH_COMPONENT16:
            primarySize = 2*pixels;
            break;
        case LOCAL_GL_RGB8:
        case LOCAL_GL_DEPTH_COMPONENT24:
            primarySize = 3*pixels;
            break;
        case LOCAL_GL_RGBA8:
        case LOCAL_GL_SRGB8_ALPHA8_EXT:
        case LOCAL_GL_DEPTH24_STENCIL8:
        case LOCAL_GL_DEPTH_COMPONENT32:
            primarySize = 4*pixels;
            break;
        case LOCAL_GL_RGB16F:
            primarySize = 2*3*pixels;
            break;
        case LOCAL_GL_RGBA16F:
            primarySize = 2*4*pixels;
            break;
        case LOCAL_GL_RGB32F:
            primarySize = 4*3*pixels;
            break;
        case LOCAL_GL_RGBA32F:
            primarySize = 4*4*pixels;
            break;
        default:
            MOZ_ASSERT(false, "Unknown `primaryFormat`.");
            break;
    }

    return primarySize + secondarySize;
}

void
WebGLRenderbuffer::BindRenderbuffer() const {
    /* Do this explicitly here, since the meaning changes for depth-stencil emu.
     * Under normal circumstances, there's only one RB: `mPrimaryRB`.
     * `mSecondaryRB` is used when we have to pretend that the renderbuffer is
     * DEPTH_STENCIL, when it's actually one DEPTH buffer `mPrimaryRB` and one
     * STENCIL buffer `mSecondaryRB`.
     *
     * In the DEPTH_STENCIL emulation case, we're actually juggling two RBs, but
     * we can only bind one of them at a time. We choose to unconditionally bind
     * the depth RB. When we need to ask about the stencil buffer (say, how many
     * stencil bits we have), we temporarily bind the stencil RB, so that it
     * looks like we're just asking the question of a combined DEPTH_STENCIL
     * buffer.
     */
    mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
}

void
WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width, GLsizei height) const {
    GLContext* gl = mContext->gl;

    GLenum primaryFormat = internalFormat;
    GLenum secondaryFormat = 0;

    if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
        primaryFormat = DepthStencilDepthFormat(gl);
        secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
    }

    gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);

    if (!mSecondaryRB) {
        MOZ_ASSERT(!secondaryFormat);
        return;
    }
    // We can't leave the secondary RB unspecified either, since we should
    // handle the case where we attach a non-depth-stencil RB to a
    // depth-stencil attachment point, or attach this depth-stencil RB to a
    // non-depth-stencil attachment point.
    ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
    if (secondaryFormat) {
        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, secondaryFormat, width, height);
    } else {
        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
    }
}

void
WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const {
    GLContext* gl = mContext->gl;
    if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment, LOCAL_GL_RENDERBUFFER, mPrimaryRB);
        return;
    }

    GLuint stencilRB = mPrimaryRB;
    if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
        printf_stderr("DEV-ONLY: Using secondary buffer to emulate DepthStencil.\n");
        MOZ_ASSERT(mSecondaryRB);
        stencilRB = mSecondaryRB;
    }
    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,   LOCAL_GL_RENDERBUFFER, mPrimaryRB);
    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, stencilRB);
}

GLint
WebGLRenderbuffer::GetRenderbufferParameter(GLenum target, GLenum pname) const {
    GLContext* gl = mContext->gl;

    switch (pname) {
        case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE: {
            if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
                if (gl->WorkAroundDriverBugs() &&
                    gl->Renderer() == GLRenderer::Tegra)
                {
                    return 8;
                }

                ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);

                GLint i = 0;
                gl->fGetRenderbufferParameteriv(target, pname, &i);
                return i;
            }
            // Fall through otherwise.
        }
        case LOCAL_GL_RENDERBUFFER_WIDTH:
        case LOCAL_GL_RENDERBUFFER_HEIGHT:
        case LOCAL_GL_RENDERBUFFER_RED_SIZE:
        case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
        case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
        case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
        case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE: {
            GLint i = 0;
            gl->fGetRenderbufferParameteriv(target, pname, &i);
            return i;
        }
    }

    MOZ_ASSERT(false, "This function should only be called with valid `pname`.");
    return 0;
}


NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)

NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)