GLComponents::GLComponents(TexInternalFormat internalformat)
{
    TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
    mComponents = 0;

    switch (unsizedformat.get()) {
        case LOCAL_GL_RGBA:
        case LOCAL_GL_RGBA4:
        case LOCAL_GL_RGBA8:
        case LOCAL_GL_RGB5_A1:
        // Luminance + Alpha can be converted
        // to and from RGBA
        case LOCAL_GL_LUMINANCE_ALPHA:
            mComponents |= Components::Alpha;
        // Drops through
        case LOCAL_GL_RGB:
        case LOCAL_GL_RGB565:
        // Luminance can be converted to and from RGB
        case LOCAL_GL_LUMINANCE:
            mComponents |= Components::Red | Components::Green | Components::Blue;
            break;
        case LOCAL_GL_ALPHA:
            mComponents |= Components::Alpha;
            break;
        case LOCAL_GL_DEPTH_COMPONENT:
            mComponents |= Components::Depth;
            break;
        case LOCAL_GL_DEPTH_STENCIL:
            mComponents |= Components::Stencil;
            break;
        default:
            MOZ_ASSERT(false, "Unhandled case - GLComponents");
            break;
    }
}
void
UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
                                                        TexInternalFormat* out_internalformat,
                                                        TexType* out_type)
{
    MOZ_ASSERT(TypeFromInternalFormat(effectiveinternalformat) != LOCAL_GL_NONE);

    MOZ_ASSERT(out_internalformat);
    MOZ_ASSERT(out_type);

    GLenum internalformat = LOCAL_GL_NONE;
    GLenum type = LOCAL_GL_NONE;

    switch (effectiveinternalformat.get()) {

#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
    case table_effectiveinternalformat: \
        internalformat = table_internalformat; \
        type = table_type; \
        break;

#include "WebGLInternalFormatsTable.h"

        default:
            MOZ_CRASH(); // impossible to get here
    }

    *out_internalformat = internalformat;
    *out_type = type;
}
bool
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
{
    switch (format.get()) {
        case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
        case LOCAL_GL_ATC_RGB:
        case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
        case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
        case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
        case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
        case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
        case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
        case LOCAL_GL_ETC1_RGB8_OES:
            return true;
        default:
            return false;
    }
}
bool
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
{
    return IsCompressedTextureFormat(format.get());
}
/**
 * Return the bits per texel for format & type combination.
 * Assumes that format & type are a valid combination as checked with
 * ValidateTexImageFormatAndType().
 */
size_t
GetBitsPerTexel(TexInternalFormat effectiveinternalformat)
{
    switch (effectiveinternalformat.get()) {
    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
        return 2;

    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
    case LOCAL_GL_ATC_RGB:
    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
    case LOCAL_GL_ETC1_RGB8_OES:
        return 4;

    case LOCAL_GL_ALPHA8:
    case LOCAL_GL_LUMINANCE8:
    case LOCAL_GL_R8:
    case LOCAL_GL_R8I:
    case LOCAL_GL_R8UI:
    case LOCAL_GL_R8_SNORM:
    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
        return 8;

    case LOCAL_GL_LUMINANCE8_ALPHA8:
    case LOCAL_GL_RGBA4:
    case LOCAL_GL_RGB5_A1:
    case LOCAL_GL_DEPTH_COMPONENT16:
    case LOCAL_GL_RG8:
    case LOCAL_GL_R16I:
    case LOCAL_GL_R16UI:
    case LOCAL_GL_RGB565:
    case LOCAL_GL_R16F:
    case LOCAL_GL_RG8I:
    case LOCAL_GL_RG8UI:
    case LOCAL_GL_RG8_SNORM:
    case LOCAL_GL_ALPHA16F_EXT:
    case LOCAL_GL_LUMINANCE16F_EXT:
        return 16;

    case LOCAL_GL_RGB8:
    case LOCAL_GL_DEPTH_COMPONENT24:
    case LOCAL_GL_SRGB8:
    case LOCAL_GL_RGB8UI:
    case LOCAL_GL_RGB8I:
    case LOCAL_GL_RGB8_SNORM:
        return 24;

    case LOCAL_GL_RGBA8:
    case LOCAL_GL_RGB10_A2:
    case LOCAL_GL_R32F:
    case LOCAL_GL_RG16F:
    case LOCAL_GL_R32I:
    case LOCAL_GL_R32UI:
    case LOCAL_GL_RG16I:
    case LOCAL_GL_RG16UI:
    case LOCAL_GL_DEPTH24_STENCIL8:
    case LOCAL_GL_R11F_G11F_B10F:
    case LOCAL_GL_RGB9_E5:
    case LOCAL_GL_SRGB8_ALPHA8:
    case LOCAL_GL_DEPTH_COMPONENT32F:
    case LOCAL_GL_RGBA8UI:
    case LOCAL_GL_RGBA8I:
    case LOCAL_GL_RGBA8_SNORM:
    case LOCAL_GL_RGB10_A2UI:
    case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
    case LOCAL_GL_ALPHA32F_EXT:
    case LOCAL_GL_LUMINANCE32F_EXT:
        return 32;

    case LOCAL_GL_DEPTH32F_STENCIL8:
        return 40;

    case LOCAL_GL_RGB16F:
    case LOCAL_GL_RGB16UI:
    case LOCAL_GL_RGB16I:
        return 48;

    case LOCAL_GL_RG32F:
    case LOCAL_GL_RG32I:
    case LOCAL_GL_RG32UI:
    case LOCAL_GL_RGBA16F:
    case LOCAL_GL_RGBA16UI:
    case LOCAL_GL_RGBA16I:
    case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
        return 64;

    case LOCAL_GL_RGB32F:
    case LOCAL_GL_RGB32UI:
    case LOCAL_GL_RGB32I:
        return 96;

    case LOCAL_GL_RGBA32F:
    case LOCAL_GL_RGBA32UI:
    case LOCAL_GL_RGBA32I:
        return 128;

    default:
        MOZ_ASSERT(false, "Unhandled format");
        return 0;
    }
}
/**
 * Convert effective internalformat into GL function parameters
 * valid for underlying driver.
 */
void
DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
                                         TexInternalFormat effectiveinternalformat,
                                         GLenum* out_driverInternalFormat,
                                         GLenum* out_driverFormat,
                                         GLenum* out_driverType)
{
    MOZ_ASSERT(out_driverInternalFormat);
    MOZ_ASSERT(out_driverFormat);
    MOZ_ASSERT(out_driverType);

    TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
    TexType type = LOCAL_GL_NONE;

    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(effectiveinternalformat,
                                                            &unsizedinternalformat, &type);

    // driverType: almost always the generic type that we just got, except on ES
    // we must replace HALF_FLOAT by HALF_FLOAT_OES
    GLenum driverType = type.get();
    if (gl->IsGLES() && type == LOCAL_GL_HALF_FLOAT) {
        driverType = LOCAL_GL_HALF_FLOAT_OES;
    }

    // driverFormat: always just the unsized internalformat that we just got
    GLenum driverFormat = unsizedinternalformat.get();

    // driverInternalFormat: almost always the same as driverFormat, but on desktop GL,
    // in some cases we must pass a different value. On ES, they are equal by definition
    // as it is an error to pass internalformat!=format.
    GLenum driverInternalFormat = driverFormat;
    if (!gl->IsGLES()) {
        // Cases where desktop OpenGL requires a tweak to 'format'
        if (driverFormat == LOCAL_GL_SRGB) {
            driverFormat = LOCAL_GL_RGB;
        } else if (driverFormat == LOCAL_GL_SRGB_ALPHA) {
            driverFormat = LOCAL_GL_RGBA;
        }

        // WebGL2's new formats are not legal values for internalformat,
        // as using unsized internalformat is deprecated.
        if (driverFormat == LOCAL_GL_RED ||
            driverFormat == LOCAL_GL_RG ||
            driverFormat == LOCAL_GL_RED_INTEGER ||
            driverFormat == LOCAL_GL_RG_INTEGER ||
            driverFormat == LOCAL_GL_RGB_INTEGER ||
            driverFormat == LOCAL_GL_RGBA_INTEGER)
        {
            driverInternalFormat = effectiveinternalformat.get();
        }

        // Cases where desktop OpenGL requires a sized internalformat,
        // as opposed to the unsized internalformat that had the same
        // GLenum value as 'format', in order to get the precise
        // semantics that we want. For example, for floating-point formats,
        // we seem to need a sized internalformat to get non-clamped floating
        // point texture sampling. Can't find the spec reference for that,
        // but that's at least the case on my NVIDIA driver version 331.
        if (unsizedinternalformat == LOCAL_GL_DEPTH_COMPONENT ||
            unsizedinternalformat == LOCAL_GL_DEPTH_STENCIL ||
            type == LOCAL_GL_FLOAT ||
            type == LOCAL_GL_HALF_FLOAT)
        {
            driverInternalFormat = effectiveinternalformat.get();
        }
    }

    *out_driverInternalFormat = driverInternalFormat;
    *out_driverFormat = driverFormat;
    *out_driverType = driverType;
}
void
WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
                             GLint xoffset, GLint yoffset, GLint zoffset,
                             GLsizei width, GLsizei height, GLsizei depth,
                             GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
                             ErrorResult& rv)
{
    if (IsContextLost())
        return;

    if (pixels.IsNull())
        return ErrorInvalidValue("texSubImage3D: pixels must not be null!");

    const ArrayBufferView& view = pixels.Value();
    view.ComputeLengthAndData();

    const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
    const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;

    if (!ValidateTexImageTarget(rawTarget, func, dims))
        return;

    TexImageTarget texImageTarget(rawTarget);

    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
    if (!tex) {
        return ErrorInvalidOperation("texSubImage3D: no texture bound on active texture unit");
    }

    if (!tex->HasImageInfoAt(texImageTarget, level)) {
        return ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
    }

    const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
    const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
    TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
    TexType existingType = LOCAL_GL_NONE;
    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
                                                            &existingUnsizedInternalFormat,
                                                            &existingType);

    if (!ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
                          xoffset, yoffset, zoffset,
                          width, height, depth,
                          0, format, type, func, dims))
    {
        return;
    }

    if (type != existingType) {
        return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
    }

    js::Scalar::Type jsArrayType = JS_GetArrayBufferViewType(view.Obj());
    void* data = view.Data();
    size_t dataLength = view.Length();

    if (!ValidateTexInputData(type, jsArrayType, func, dims))
        return;

    const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
    MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
    size_t srcTexelSize = bitsPerTexel / 8;

    if (width == 0 || height == 0 || depth == 0)
        return; // no effect, we better return right now

    CheckedUint32 checked_neededByteLength =
        GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);

    if (!checked_neededByteLength.isValid())
        return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");

    uint32_t bytesNeeded = checked_neededByteLength.value();

    if (dataLength < bytesNeeded)
        return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);

    if (imageInfo.HasUninitializedImageData()) {
        bool coversWholeImage = xoffset == 0 &&
                                yoffset == 0 &&
                                zoffset == 0 &&
                                width == imageInfo.Width() &&
                                height == imageInfo.Height() &&
                                depth == imageInfo.Depth();
        if (coversWholeImage) {
            tex->SetImageDataStatus(texImageTarget, level, WebGLImageDataStatus::InitializedImageData);
        } else {
            tex->EnsureNoUninitializedImageData(texImageTarget, level);
        }
    }

    GLenum driverType = LOCAL_GL_NONE;
    GLenum driverInternalFormat = LOCAL_GL_NONE;
    GLenum driverFormat = LOCAL_GL_NONE;
    DriverFormatsFromEffectiveInternalFormat(gl,
                                             existingEffectiveInternalFormat,
                                             &driverInternalFormat,
                                             &driverFormat,
                                             &driverType);

    MakeContextCurrent();
    gl->fTexSubImage3D(texImageTarget.get(), level,
                       xoffset, yoffset, zoffset,
                       width, height, depth,
                       driverFormat, driverType, data);

}
Exemple #8
0
// `mask` from glClear.
static bool
ClearWithTempFB(WebGLContext* webgl, GLuint tex,
                TexImageTarget texImageTarget, GLint level,
                TexInternalFormat baseInternalFormat,
                GLsizei width, GLsizei height)
{
    MOZ_ASSERT(texImageTarget == LOCAL_GL_TEXTURE_2D);

    gl::GLContext* gl = webgl->GL();
    MOZ_ASSERT(gl->IsCurrent());

    gl::ScopedFramebuffer fb(gl);
    gl::ScopedBindFramebuffer autoFB(gl, fb.FB());
    GLbitfield mask = 0;

    switch (baseInternalFormat.get()) {
    case LOCAL_GL_LUMINANCE:
    case LOCAL_GL_LUMINANCE_ALPHA:
    case LOCAL_GL_ALPHA:
    case LOCAL_GL_RGB:
    case LOCAL_GL_RGBA:
    case LOCAL_GL_BGR:
    case LOCAL_GL_BGRA:
        mask = LOCAL_GL_COLOR_BUFFER_BIT;
        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                  texImageTarget.get(), tex, level);
        break;
    case LOCAL_GL_DEPTH_COMPONENT32_OES:
    case LOCAL_GL_DEPTH_COMPONENT24_OES:
    case LOCAL_GL_DEPTH_COMPONENT16:
    case LOCAL_GL_DEPTH_COMPONENT:
        mask = LOCAL_GL_DEPTH_BUFFER_BIT;
        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
                                  texImageTarget.get(), tex, level);
        break;

    case LOCAL_GL_DEPTH24_STENCIL8:
    case LOCAL_GL_DEPTH_STENCIL:
        mask = LOCAL_GL_DEPTH_BUFFER_BIT |
               LOCAL_GL_STENCIL_BUFFER_BIT;
        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
                                  texImageTarget.get(), tex, level);
        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
                                  texImageTarget.get(), tex, level);
        break;

    default:
        return false;
    }
    MOZ_ASSERT(mask);

    if (ClearByMask(webgl, mask))
        return true;

    // Failed to simply build an FB from the tex, but maybe it needs a
    // color buffer to be complete.

    if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
        // Nope, it already had one.
        return false;
    }

    gl::ScopedRenderbuffer rb(gl);
    {
        // Only GLES guarantees RGBA4.
        GLenum format = gl->IsGLES() ? LOCAL_GL_RGBA4 : LOCAL_GL_RGBA8;
        gl::ScopedBindRenderbuffer rbBinding(gl, rb.RB());
        gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, width, height);
    }

    gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
                                 LOCAL_GL_RENDERBUFFER, rb.RB());
    mask |= LOCAL_GL_COLOR_BUFFER_BIT;

    // Last chance!
    return ClearByMask(webgl, mask);
}
/**
 * Convert WebGL/ES format and type into GL internal
 * format valid for underlying driver.
 */
void
DriverFormatsFromFormatAndType(GLContext* gl, TexInternalFormat webGLInternalFormat, TexType webGLType,
                               GLenum* out_driverInternalFormat, GLenum* out_driverFormat)
{
    MOZ_ASSERT(out_driverInternalFormat);
    MOZ_ASSERT(out_driverFormat);

    // ES2 requires that format == internalformat; floating-point is
    // indicated purely by the type that's loaded.  For desktop GL, we
    // have to specify a floating point internal format.
    if (gl->IsGLES()) {
        *out_driverFormat = *out_driverInternalFormat = webGLInternalFormat.get();
        return;
    }

    GLenum internalFormat = LOCAL_GL_NONE;
    GLenum format = LOCAL_GL_NONE;

    if (webGLInternalFormat == LOCAL_GL_DEPTH_COMPONENT) {
        format = LOCAL_GL_DEPTH_COMPONENT;
        if (webGLType == LOCAL_GL_UNSIGNED_SHORT)
            internalFormat = LOCAL_GL_DEPTH_COMPONENT16;
        else if (webGLType == LOCAL_GL_UNSIGNED_INT)
            internalFormat = LOCAL_GL_DEPTH_COMPONENT32;
    } else if (webGLInternalFormat == LOCAL_GL_DEPTH_STENCIL) {
        format = LOCAL_GL_DEPTH_STENCIL;
        if (webGLType == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
            internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
    } else {
        switch (webGLType.get()) {
        case LOCAL_GL_UNSIGNED_BYTE:
        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
            format = internalFormat = webGLInternalFormat.get();
            break;

        case LOCAL_GL_FLOAT:
            switch (webGLInternalFormat.get()) {
            case LOCAL_GL_RGBA:
                format = LOCAL_GL_RGBA;
                internalFormat = LOCAL_GL_RGBA32F;
                break;

            case LOCAL_GL_RGB:
                format = LOCAL_GL_RGB;
                internalFormat = LOCAL_GL_RGB32F;
                break;

            case LOCAL_GL_ALPHA:
                format = LOCAL_GL_ALPHA;
                internalFormat = LOCAL_GL_ALPHA32F_ARB;
                break;

            case LOCAL_GL_LUMINANCE:
                format = LOCAL_GL_LUMINANCE;
                internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
                break;

            case LOCAL_GL_LUMINANCE_ALPHA:
                format = LOCAL_GL_LUMINANCE_ALPHA;
                internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
                break;
            }
            break;

        case LOCAL_GL_HALF_FLOAT_OES:
            switch (webGLInternalFormat.get()) {
            case LOCAL_GL_RGBA:
                format = LOCAL_GL_RGBA;
                internalFormat = LOCAL_GL_RGBA16F;
                break;

            case LOCAL_GL_RGB:
                format = LOCAL_GL_RGB;
                internalFormat = LOCAL_GL_RGB16F;
                break;

            case LOCAL_GL_ALPHA:
                format = LOCAL_GL_ALPHA;
                internalFormat = LOCAL_GL_ALPHA16F_ARB;
                break;

            case LOCAL_GL_LUMINANCE:
                format = LOCAL_GL_LUMINANCE;
                internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
                break;

            case LOCAL_GL_LUMINANCE_ALPHA:
                format = LOCAL_GL_LUMINANCE_ALPHA;
                internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
                break;
            }
            break;

        default:
            break;
        }

        // Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
        // requires that format == internalformat, but GL will fail in this case.
        // GL requires:
        //      format  ->  internalformat
        //      GL_RGB      GL_SRGB_EXT
        //      GL_RGBA     GL_SRGB_ALPHA_EXT
        switch (webGLInternalFormat.get()) {
        case LOCAL_GL_SRGB:
            format = LOCAL_GL_RGB;
            internalFormat = LOCAL_GL_SRGB;
            break;
        case LOCAL_GL_SRGB_ALPHA:
            format = LOCAL_GL_RGBA;
            internalFormat = LOCAL_GL_SRGB_ALPHA;
            break;
        }
    }

    MOZ_ASSERT(webGLInternalFormat != LOCAL_GL_NONE && internalFormat != LOCAL_GL_NONE,
               "Coding mistake -- bad format/type passed?");

    *out_driverInternalFormat = internalFormat;
    *out_driverFormat = format;
}