Pull in aggressive refactor from tex-format-tables.
draft
Pull in aggressive refactor from tex-format-tables.
new file mode 100644
--- /dev/null
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -0,0 +1,744 @@
+/* -*- 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 "TexUnpackBlob.h"
+
+#include "GLBlitHelper.h"
+#include "GLContext.h"
+#include "GLDefs.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/HTMLCanvasElement.h"
+#include "nsLayoutUtils.h"
+#include "WebGLContext.h"
+#include "WebGLTexelConversions.h"
+#include "WebGLTexture.h"
+
+namespace mozilla {
+namespace webgl {
+
+static GLenum
+DoTexOrSubImage(bool isSubImage, gl::GLContext* gl, TexImageTarget target, GLint level,
+ const DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset,
+ GLsizei width, GLsizei height, GLsizei depth, const void* data)
+{
+ auto internalFormat = dui->internalFormat;
+ auto unpackFormat = dui->unpackFormat;
+ auto unpackType = dui->unpackType;
+
+ if (isSubImage) {
+ return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
+ depth, unpackFormat, unpackType, data);
+ } else {
+ return DoTexImage(gl, target, level, internalFormat, width, height, depth,
+ unpackFormat, unpackType, data);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// TexUnpackBuffer
+
+static bool
+GetPackedSizeForUnpack(uint32_t bytesPerPixel, uint8_t rowByteAlignment,
+ uint32_t maybeStridePixelsPerRow, uint32_t maybeStrideRowsPerImage,
+ uint32_t skipPixelsPerRow, uint32_t skipRowsPerImage,
+ uint32_t skipImages, uint32_t usedPixelsPerRow,
+ uint32_t usedRowsPerImage, uint32_t usedImages,
+ uint32_t* const out_packedBytes)
+{
+ MOZ_RELEASE_ASSERT(rowByteAlignment != 0);
+
+ if (!usedPixelsPerRow || !usedRowsPerImage || !usedImages) {
+ *out_packedBytes = 0;
+ return true;
+ }
+ // Now we know there's at least one image.
+
+ CheckedUint32 pixelsPerRow = CheckedUint32(skipPixelsPerRow) + usedPixelsPerRow;
+ CheckedUint32 rowsPerImage = CheckedUint32(skipRowsPerImage) + usedRowsPerImage;
+ CheckedUint32 images = CheckedUint32(skipImages) + usedImages;
+
+ MOZ_ASSERT_IF(maybeStridePixelsPerRow,
+ (pixelsPerRow.isValid() &&
+ maybeStridePixelsPerRow >= pixelsPerRow.value()));
+
+ MOZ_ASSERT_IF(maybeStrideRowsPerImage,
+ (rowsPerImage.isValid() &&
+ maybeStrideRowsPerImage >= rowsPerImage.value()));
+
+ CheckedUint32 stridePixelsPerRow = maybeStridePixelsPerRow ? maybeStridePixelsPerRow
+ : pixelsPerRow;
+ CheckedUint32 strideRowsPerImage = maybeStrideRowsPerImage ? maybeStrideRowsPerImage
+ : rowsPerImage;
+
+ CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
+ strideBytesPerRow = RoundUpToMultipleOf(strideBytesPerRow, rowByteAlignment);
+
+ CheckedUint32 strideBytesPerImage = strideBytesPerRow * strideRowsPerImage;
+
+ CheckedUint32 lastRowBytes = CheckedUint32(bytesPerPixel) * pixelsPerRow;
+ CheckedUint32 lastImageBytes = strideBytesPerRow * (rowsPerImage - 1) + lastRowBytes;
+
+ CheckedUint32 packedBytes = strideBytesPerImage * (images - 1) + lastImageBytes;
+
+ if (!packedBytes.isValid())
+ return false;
+
+ *out_packedBytes = packedBytes.value();
+ return true;
+}
+
+////////////////////
+
+bool
+TexUnpackBytes::ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
+ const webgl::PackingInfo& pi)
+{
+ if (!mBytes)
+ return true;
+
+ const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+ const auto rowByteAlignment = webgl->mPixelStore_UnpackAlignment;
+ const auto maybeStridePixelsPerRow = webgl->mPixelStore_UnpackRowLength;
+ const auto maybeStrideRowsPerImage = webgl->mPixelStore_UnpackImageHeight;
+ const auto skipPixelsPerRow = webgl->mPixelStore_UnpackSkipPixels;
+ const auto skipRowsPerImage = webgl->mPixelStore_UnpackSkipRows;
+ const auto skipImages = isFunc3D ? webgl->mPixelStore_UnpackSkipImages
+ : 0;
+ const auto usedPixelsPerRow = mWidth;
+ const auto usedRowsPerImage = mHeight;
+ const auto usedImages = mDepth;
+
+ uint32_t bytesNeeded;
+ if (!GetPackedSizeForUnpack(bytesPerPixel, rowByteAlignment,
+ maybeStridePixelsPerRow, maybeStrideRowsPerImage,
+ skipPixelsPerRow, skipRowsPerImage, skipImages,
+ usedPixelsPerRow, usedRowsPerImage, usedImages,
+ &bytesNeeded))
+ {
+ webgl->ErrorInvalidOperation("%s: Overflow while computing the needed buffer"
+ " size.",
+ funcName);
+ return false;
+ }
+
+ if (bytesNeeded > mByteCount) {
+ webgl->ErrorInvalidOperation("%s: Provided buffer is too small. (needs %u, has"
+ " %u)",
+ funcName, bytesNeeded, mByteCount);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+UnpackFormatHasAlpha(GLenum unpackFormat)
+{
+ switch (unpackFormat) {
+ case LOCAL_GL_ALPHA:
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ case LOCAL_GL_RGBA:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static WebGLTexelFormat
+FormatFromPacking(const webgl::PackingInfo& pi)
+{
+ switch (pi.type) {
+ case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+ return WebGLTexelFormat::RGB565;
+
+ case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+ return WebGLTexelFormat::RGBA5551;
+
+ case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+ return WebGLTexelFormat::RGBA4444;
+
+ case LOCAL_GL_UNSIGNED_BYTE:
+ switch (pi.format) {
+ case LOCAL_GL_LUMINANCE: return WebGLTexelFormat::R8;
+ case LOCAL_GL_ALPHA: return WebGLTexelFormat::A8;
+ case LOCAL_GL_LUMINANCE_ALPHA: return WebGLTexelFormat::RA8;
+ case LOCAL_GL_RGB: return WebGLTexelFormat::RGB8;
+ case LOCAL_GL_SRGB: return WebGLTexelFormat::RGB8;
+ case LOCAL_GL_RGBA: return WebGLTexelFormat::RGBA8;
+ case LOCAL_GL_SRGB_ALPHA: return WebGLTexelFormat::RGBA8;
+ }
+
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+ switch (pi.format) {
+ case LOCAL_GL_LUMINANCE: return WebGLTexelFormat::R16F;
+ case LOCAL_GL_ALPHA: return WebGLTexelFormat::A16F;
+ case LOCAL_GL_LUMINANCE_ALPHA: return WebGLTexelFormat::RA16F;
+ case LOCAL_GL_RGB: return WebGLTexelFormat::RGB16F;
+ case LOCAL_GL_RGBA: return WebGLTexelFormat::RGBA16F;
+ }
+
+ case LOCAL_GL_FLOAT:
+ switch (pi.format) {
+ case LOCAL_GL_LUMINANCE: return WebGLTexelFormat::R32F;
+ case LOCAL_GL_ALPHA: return WebGLTexelFormat::A32F;
+ case LOCAL_GL_LUMINANCE_ALPHA: return WebGLTexelFormat::RA32F;
+ case LOCAL_GL_RGB: return WebGLTexelFormat::RGB32F;
+ case LOCAL_GL_RGBA: return WebGLTexelFormat::RGBA32F;
+ }
+ }
+
+ return WebGLTexelFormat::FormatNotSupportingAnyConversion;
+}
+
+void
+TexUnpackBytes::TexOrSubImage(bool isSubImage, const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum* const out_glError)
+{
+ WebGLContext* webgl = tex->mContext;
+ gl::GLContext* gl = webgl->gl;
+
+ const void* uploadBytes = mBytes;
+ UniqueBuffer tempBuffer;
+
+ do {
+ if (!webgl->mPixelStore_FlipY && !webgl->mPixelStore_PremultiplyAlpha)
+ break;
+
+ if (!mBytes || !mWidth || !mHeight || !mDepth)
+ break;
+
+ if (webgl->IsWebGL2())
+ break;
+ MOZ_ASSERT(mDepth == 1);
+
+ // This is literally the worst.
+ webgl->GenerateWarning("%s: Uploading ArrayBuffers with FLIP_Y or"
+ " PREMULTIPLY_ALPHA is slow.",
+ funcName);
+
+ tempBuffer = malloc(mByteCount);
+ if (!tempBuffer) {
+ *out_glError = LOCAL_GL_OUT_OF_MEMORY;
+ return;
+ }
+
+ const webgl::PackingInfo pi = { dui->unpackFormat, dui->unpackType };
+
+ const auto bytesPerPixel = webgl::BytesPerPixel(pi);
+ const auto rowByteAlignment = webgl->mPixelStore_UnpackAlignment;
+
+ const size_t bytesPerRow = bytesPerPixel * mWidth;
+ const size_t rowStride = RoundUpToMultipleOf(bytesPerRow, rowByteAlignment);
+
+ const bool needsYFlip = webgl->mPixelStore_FlipY;
+
+ bool needsAlphaPremult = webgl->mPixelStore_PremultiplyAlpha;
+ if (!UnpackFormatHasAlpha(pi.format))
+ needsAlphaPremult = false;
+
+ if (!needsAlphaPremult) {
+ if (!webgl->mPixelStore_FlipY)
+ break;
+
+ const uint8_t* src = (const uint8_t*)mBytes;
+ const uint8_t* const srcEnd = src + rowStride * mHeight;
+
+ uint8_t* dst = (uint8_t*)tempBuffer.get() + rowStride * (mHeight - 1);
+
+ while (src != srcEnd) {
+ memcpy(dst, src, bytesPerRow);
+ src += rowStride;
+ dst -= rowStride;
+ }
+
+ uploadBytes = tempBuffer.get();
+ break;
+ }
+
+ const auto texelFormat = FormatFromPacking(pi);
+ if (texelFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion) {
+ MOZ_ASSERT(false, "Bad texelFormat from pi.");
+ *out_glError = LOCAL_GL_OUT_OF_MEMORY;
+ return;
+ }
+
+ const auto srcOrigin = gl::OriginPos::BottomLeft;
+ const auto dstOrigin = (needsYFlip ? gl::OriginPos::TopLeft
+ : gl::OriginPos::BottomLeft);
+
+ const bool srcPremultiplied = false;
+ const bool dstPremultiplied = needsAlphaPremult; // Always true here.
+ // And go!:
+ if (!ConvertImage(mWidth, mHeight,
+ mBytes, rowStride, srcOrigin, texelFormat, srcPremultiplied,
+ tempBuffer.get(), rowStride, dstOrigin, texelFormat,
+ dstPremultiplied))
+ {
+ MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
+ *out_glError = LOCAL_GL_OUT_OF_MEMORY;
+ return;
+ }
+
+ uploadBytes = tempBuffer.get();
+ break;
+ } while (false);
+
+ GLenum error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
+ zOffset, mWidth, mHeight, mDepth, uploadBytes);
+ *out_glError = error;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+// TexUnpackDataSurface
+
+static bool
+GuessAlignment(const void* data, size_t width, size_t stride, size_t maxAlignment,
+ size_t* const out_alignment)
+{
+ size_t alignmentGuess = maxAlignment;
+ while (alignmentGuess) {
+ size_t guessStride = RoundUpToMultipleOf(width, alignmentGuess);
+ if (guessStride == stride &&
+ uintptr_t(data) % alignmentGuess == 0)
+ {
+ *out_alignment = alignmentGuess;
+ return true;
+ }
+ alignmentGuess /= 2;
+ }
+ return false;
+}
+
+static bool
+SupportsBGRA(gl::GLContext* gl)
+{
+ if (gl->IsANGLE())
+ return true;
+
+ return false;
+}
+
+/*static*/ void
+TexUnpackSurface::OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
+ gl::OriginPos* const out_dst)
+{
+ // Our surfaces are TopLeft.
+ *out_src = gl::OriginPos::TopLeft;
+
+ // WebGL specs the default as passing DOM elements top-left first.
+ // Thus y-flip would give us bottom-left.
+ *out_dst = webgl->mPixelStore_FlipY ? gl::OriginPos::BottomLeft
+ : gl::OriginPos::TopLeft;
+}
+
+/*static*/ bool
+TexUnpackSurface::UploadDataSurface(bool isSubImage, WebGLContext* webgl,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, gfx::DataSourceSurface* surf,
+ bool isSurfAlphaPremult, GLenum* const out_glError)
+{
+ *out_glError = 0;
+
+ if (isSurfAlphaPremult != webgl->mPixelStore_PremultiplyAlpha)
+ return false;
+
+ gl::OriginPos srcOrigin, dstOrigin;
+ OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
+ if (srcOrigin != dstOrigin)
+ return false;
+
+ gl::GLContext* gl = webgl->gl;
+
+ // This differs from the raw-data upload in that we choose how we do the unpack.
+ // (alignment, etc.)
+
+ // Uploading RGBX as RGBA and blitting to RGB is faster than repacking RGBX into
+ // RGB on the CPU. However, this is optimization is out-of-scope for now.
+
+ static const webgl::DriverUnpackInfo kInfoBGRA = {
+ LOCAL_GL_BGRA,
+ LOCAL_GL_BGRA,
+ LOCAL_GL_UNSIGNED_BYTE,
+ };
+
+ const webgl::DriverUnpackInfo* chosenDUI = nullptr;
+
+ switch (surf->GetFormat()) {
+ case gfx::SurfaceFormat::B8G8R8A8:
+ if (dui->internalFormat == LOCAL_GL_RGBA &&
+ dui->unpackFormat == LOCAL_GL_RGBA &&
+ dui->unpackType == LOCAL_GL_UNSIGNED_BYTE)
+ {
+ if (gl->IsANGLE()) {
+ chosenDUI = &kInfoBGRA;
+ }
+ }
+ break;
+
+ case gfx::SurfaceFormat::R8G8B8A8:
+ if (dui->unpackFormat == LOCAL_GL_RGBA &&
+ dui->unpackType == LOCAL_GL_UNSIGNED_BYTE)
+ {
+ chosenDUI = dui;
+ }
+ break;
+
+ case gfx::SurfaceFormat::R5G6B5_UINT16:
+ if (dui->unpackFormat == LOCAL_GL_RGB &&
+ dui->unpackType == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
+ {
+ chosenDUI = dui;
+ }
+ break;
+ }
+
+ if (!chosenDUI)
+ return false;
+
+ gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::MapType::READ);
+ if (!map.IsMapped())
+ return false;
+
+ const GLint kMaxUnpackAlignment = 8;
+ size_t unpackAlignment;
+ if (!GuessAlignment(map.GetData(), width, map.GetStride(), kMaxUnpackAlignment,
+ &unpackAlignment))
+ {
+ return false;
+ }
+
+ gl->MakeCurrent();
+
+ ScopedUnpackReset scopedReset(webgl);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, unpackAlignment);
+
+ const GLsizei depth = 1;
+ GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, chosenDUI,
+ xOffset, yOffset, zOffset, width, height, depth,
+ map.GetData());
+ if (error) {
+ *out_glError = error;
+ return false;
+ }
+
+ return true;
+}
+
+////////////////////
+
+static bool
+GetFormatForSurf(gfx::SourceSurface* surf, WebGLTexelFormat* const out_texelFormat)
+{
+ gfx::SurfaceFormat surfFormat = surf->GetFormat();
+
+ switch (surfFormat) {
+ case gfx::SurfaceFormat::B8G8R8A8:
+ *out_texelFormat = WebGLTexelFormat::BGRA8;
+ return true;
+
+ case gfx::SurfaceFormat::B8G8R8X8:
+ *out_texelFormat = WebGLTexelFormat::BGRX8;
+ return true;
+
+ case gfx::SurfaceFormat::R8G8B8A8:
+ *out_texelFormat = WebGLTexelFormat::RGBA8;
+ return true;
+
+ case gfx::SurfaceFormat::R8G8B8X8:
+ *out_texelFormat = WebGLTexelFormat::RGBX8;
+ return true;
+
+ case gfx::SurfaceFormat::R5G6B5_UINT16:
+ *out_texelFormat = WebGLTexelFormat::RGB565;
+ return true;
+
+ case gfx::SurfaceFormat::A8:
+ *out_texelFormat = WebGLTexelFormat::A8;
+ return true;
+
+ case gfx::SurfaceFormat::YUV:
+ // Ugh...
+ NS_ERROR("We don't handle uploads from YUV sources yet.");
+ // When we want to, check out gfx/ycbcr/YCbCrUtils.h. (specifically
+ // GetYCbCrToRGBDestFormatAndSize and ConvertYCbCrToRGB)
+ return false;
+ }
+
+ return false;
+}
+
+static bool
+GetFormatForPackingTuple(GLenum packingFormat, GLenum packingType,
+ WebGLTexelFormat* const out_texelFormat)
+{
+ switch (packingType) {
+ case LOCAL_GL_UNSIGNED_BYTE:
+ switch (packingFormat) {
+ case LOCAL_GL_RED:
+ case LOCAL_GL_LUMINANCE:
+ *out_texelFormat = WebGLTexelFormat::R8;
+ return true;
+
+ case LOCAL_GL_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::A8;
+ return true;
+
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::RA8;
+ return true;
+
+ case LOCAL_GL_RGB:
+ *out_texelFormat = WebGLTexelFormat::RGB8;
+ return true;
+
+ case LOCAL_GL_RGBA:
+ *out_texelFormat = WebGLTexelFormat::RGBA8;
+ return true;
+
+ default:
+ break;
+ }
+
+ case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+ switch (packingFormat) {
+ case LOCAL_GL_RGB:
+ *out_texelFormat = WebGLTexelFormat::RGB565;
+ return true;
+
+ default:
+ break;
+ }
+
+ case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+ switch (packingFormat) {
+ case LOCAL_GL_RGBA:
+ *out_texelFormat = WebGLTexelFormat::RGBA5551;
+ return true;
+
+ default:
+ break;
+ }
+
+ case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+ switch (packingFormat) {
+ case LOCAL_GL_RGBA:
+ *out_texelFormat = WebGLTexelFormat::RGBA4444;
+ return true;
+
+ default:
+ break;
+ }
+
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+ switch (packingFormat) {
+ case LOCAL_GL_RED:
+ case LOCAL_GL_LUMINANCE:
+ *out_texelFormat = WebGLTexelFormat::R16F;
+ return true;
+
+ case LOCAL_GL_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::A16F;
+ return true;
+
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::RA16F;
+ return true;
+
+ case LOCAL_GL_RGB:
+ *out_texelFormat = WebGLTexelFormat::RGB16F;
+ return true;
+
+ case LOCAL_GL_RGBA:
+ *out_texelFormat = WebGLTexelFormat::RGBA16F;
+ return true;
+
+ default:
+ break;
+ }
+
+ case LOCAL_GL_FLOAT:
+ switch (packingFormat) {
+ case LOCAL_GL_RED:
+ case LOCAL_GL_LUMINANCE:
+ *out_texelFormat = WebGLTexelFormat::R32F;
+ return true;
+
+ case LOCAL_GL_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::A32F;
+ return true;
+
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ *out_texelFormat = WebGLTexelFormat::RA32F;
+ return true;
+
+ case LOCAL_GL_RGB:
+ *out_texelFormat = WebGLTexelFormat::RGB32F;
+ return true;
+
+ case LOCAL_GL_RGBA:
+ *out_texelFormat = WebGLTexelFormat::RGBA32F;
+ return true;
+
+ default:
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ NS_ERROR("Unsupported EffectiveFormat dest format for DOM element upload.");
+ return false;
+}
+
+/*static*/ bool
+TexUnpackSurface::ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
+ gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
+ UniqueBuffer* const out_convertedBuffer,
+ uint8_t* const out_convertedAlignment,
+ bool* const out_outOfMemory)
+{
+ *out_outOfMemory = false;
+
+ const size_t width = surf->GetSize().width;
+ const size_t height = surf->GetSize().height;
+
+ // Source args:
+
+ gfx::DataSourceSurface::ScopedMap srcMap(surf, gfx::DataSourceSurface::MapType::READ);
+ if (!srcMap.IsMapped())
+ return false;
+
+ const void* const srcBegin = srcMap.GetData();
+ const size_t srcStride = srcMap.GetStride();
+
+ WebGLTexelFormat srcFormat;
+ if (!GetFormatForSurf(surf, &srcFormat))
+ return false;
+
+ const bool srcPremultiplied = isSurfAlphaPremult;
+
+ // Dest args:
+
+ WebGLTexelFormat dstFormat;
+ if (!GetFormatForPackingTuple(dui->unpackFormat, dui->unpackType, &dstFormat))
+ return false;
+
+ const auto bytesPerPixel = webgl::BytesPerPixel({dui->unpackFormat, dui->unpackType});
+ const size_t dstRowBytes = bytesPerPixel * width;
+
+ const size_t dstAlignment = 8; // Just use the max!
+ const size_t dstStride = RoundUpToMultipleOf(dstRowBytes, dstAlignment);
+
+ CheckedUint32 checkedDstSize = dstStride;
+ checkedDstSize *= height;
+ if (!checkedDstSize.isValid()) {
+ *out_outOfMemory = true;
+ return false;
+ }
+
+ const size_t dstSize = checkedDstSize.value();
+
+ UniqueBuffer dstBuffer(malloc(dstSize));
+ if (!dstBuffer) {
+ *out_outOfMemory = true;
+ return false;
+ }
+ void* const dstBegin = dstBuffer.get();
+
+ gl::OriginPos srcOrigin, dstOrigin;
+ OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
+
+ const bool dstPremultiplied = webgl->mPixelStore_PremultiplyAlpha;
+
+ // And go!:
+ if (!ConvertImage(width, height,
+ srcBegin, srcStride, srcOrigin, srcFormat, srcPremultiplied,
+ dstBegin, dstStride, dstOrigin, dstFormat, dstPremultiplied))
+ {
+ MOZ_ASSERT(false, "ConvertImage failed unexpectedly.");
+ NS_ERROR("ConvertImage failed unexpectedly.");
+ *out_outOfMemory = true;
+ return false;
+ }
+
+ *out_convertedBuffer = Move(dstBuffer);
+ *out_convertedAlignment = dstAlignment;
+ return true;
+}
+
+
+////////////////////
+
+TexUnpackSurface::TexUnpackSurface(const RefPtr<gfx::SourceSurface>& surf,
+ bool isAlphaPremult)
+ : TexUnpackBlob(surf->GetSize().width, surf->GetSize().height, 1, true)
+ , mSurf(surf)
+ , mIsAlphaPremult(isAlphaPremult)
+{ }
+
+void
+TexUnpackSurface::TexOrSubImage(bool isSubImage, const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum* const out_glError)
+{
+ *out_glError = 0;
+
+ // TODO: Do blitting of the native SourceSurface.
+
+ RefPtr<gfx::DataSourceSurface> dataSurf = mSurf->GetDataSurface();
+ MOZ_ASSERT(dataSurf);
+
+ WebGLContext* webgl = tex->mContext;
+
+ GLenum error;
+ if (UploadDataSurface(isSubImage, webgl, target, level, dui, xOffset, yOffset,
+ zOffset, mWidth, mHeight, dataSurf, mIsAlphaPremult, &error))
+ {
+ return;
+ }
+
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ *out_glError = LOCAL_GL_OUT_OF_MEMORY;
+ return;
+ }
+
+ // CPU conversion. (++numCopies)
+
+ UniqueBuffer convertedBuffer;
+ uint8_t convertedAlignment;
+ bool outOfMemory;
+
+ if (!ConvertSurface(webgl, dui, dataSurf, mIsAlphaPremult, &convertedBuffer,
+ &convertedAlignment, &outOfMemory))
+ {
+ if (outOfMemory) {
+ *out_glError = LOCAL_GL_OUT_OF_MEMORY;
+ } else {
+ MOZ_CRASH("Failed to convert surface.");
+ }
+ return;
+ }
+
+ ScopedUnpackReset scopedReset(webgl);
+ webgl->gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, convertedAlignment);
+
+ error = DoTexOrSubImage(isSubImage, webgl->gl, target.get(), level, dui, xOffset,
+ yOffset, zOffset, mWidth, mHeight, mDepth,
+ convertedBuffer.get());
+ *out_glError = error;
+}
+
+} // namespace webgl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/canvas/TexUnpackBlob.h
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#ifndef TEX_UNPACK_BLOB_H_
+#define TEX_UNPACK_BLOB_H_
+
+#include "GLContextTypes.h"
+#include "GLDefs.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/gfx/Point.h"
+#include "WebGLStrongTypes.h"
+
+namespace mozilla {
+
+class UniqueBuffer;
+class WebGLContext;
+class WebGLTexture;
+
+namespace dom {
+class Element;
+class HTMLCanvasElement;
+class HTMLVideoElement;
+} // namespace dom
+
+namespace gfx {
+class DataSourceSurface;
+} // namespace gfx
+
+namespace gl {
+class GLContext;
+} // namespace gl
+
+namespace layers {
+class Image;
+class ImageContainer;
+} // namespace layers
+
+namespace webgl {
+
+struct PackingInfo;
+struct DriverUnpackInfo;
+
+class TexUnpackBlob
+{
+public:
+ const GLsizei mWidth;
+ const GLsizei mHeight;
+ const GLsizei mDepth;
+ const bool mHasData;
+
+protected:
+ TexUnpackBlob(GLsizei width, GLsizei height, GLsizei depth, bool hasData)
+ : mWidth(width)
+ , mHeight(height)
+ , mDepth(depth)
+ , mHasData(hasData)
+ { }
+
+public:
+ virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
+ const webgl::PackingInfo& pi) = 0;
+
+ virtual void TexOrSubImage(bool isSubImage, const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset,
+ GLenum* const out_glError) = 0;
+};
+
+class TexUnpackBytes : public TexUnpackBlob
+{
+public:
+ const size_t mByteCount;
+ const void* const mBytes;
+
+ TexUnpackBytes(GLsizei width, GLsizei height, GLsizei depth, size_t byteCount,
+ const void* bytes)
+ : TexUnpackBlob(width, height, depth, bool(bytes))
+ , mByteCount(byteCount)
+ , mBytes(bytes)
+ { }
+
+ virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
+ const webgl::PackingInfo& pi) override;
+
+ virtual void TexOrSubImage(bool isSubImage, const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset,
+ GLenum* const out_glError) override;
+};
+
+class TexUnpackSurface : public TexUnpackBlob
+{
+public:
+ const RefPtr<gfx::SourceSurface> mSurf;
+ const bool mIsAlphaPremult;
+
+ TexUnpackSurface(const RefPtr<gfx::SourceSurface>& surf, bool isAlphaPremult);
+
+ virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
+ const webgl::PackingInfo& pi) override
+ {
+ return true;
+ }
+
+ virtual void TexOrSubImage(bool isSubImage, const char* funcName, WebGLTexture* tex,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset,
+ GLenum* const out_glError) override;
+
+protected:
+ static bool ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
+ gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
+ UniqueBuffer* const out_convertedBuffer,
+ uint8_t* const out_convertedAlignment,
+ bool* const out_outOfMemory);
+ static bool UploadDataSurface(bool isSubImage, WebGLContext* webgl,
+ TexImageTarget target, GLint level,
+ const webgl::DriverUnpackInfo* dui, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, gfx::DataSourceSurface* surf,
+ bool isSurfAlphaPremult, GLenum* const out_glError);
+
+ static void OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
+ gl::OriginPos* const out_dst);
+};
+
+} // namespace webgl
+} // namespace mozilla
+
+#endif // TEX_UNPACK_BLOB_H_
--- a/dom/canvas/WebGL1Context.cpp
+++ b/dom/canvas/WebGL1Context.cpp
@@ -22,19 +22,19 @@ WebGL1Context::WebGL1Context()
{
}
WebGL1Context::~WebGL1Context()
{
}
UniquePtr<webgl::FormatUsageAuthority>
-WebGL1Context::CreateFormatUsage() const
+WebGL1Context::CreateFormatUsage(gl::GLContext* gl) const
{
- return webgl::FormatUsageAuthority::CreateForWebGL1();
+ return webgl::FormatUsageAuthority::CreateForWebGL1(gl);
}
JSObject*
WebGL1Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLRenderingContextBinding::Wrap(cx, this, givenProto);
}
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -13,17 +13,19 @@ namespace mozilla {
class WebGL1Context
: public WebGLContext
{
public:
static WebGL1Context* Create();
private:
WebGL1Context();
- virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
+
+ virtual UniquePtr<webgl::FormatUsageAuthority>
+ CreateFormatUsage(gl::GLContext* gl) const override;
public:
virtual ~WebGL1Context();
virtual bool IsWebGL2() const override {
return false;
}
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -24,19 +24,19 @@ WebGL2Context::WebGL2Context()
}
WebGL2Context::~WebGL2Context()
{
}
UniquePtr<webgl::FormatUsageAuthority>
-WebGL2Context::CreateFormatUsage() const
+WebGL2Context::CreateFormatUsage(gl::GLContext* gl) const
{
- return webgl::FormatUsageAuthority::CreateForWebGL2();
+ return webgl::FormatUsageAuthority::CreateForWebGL2(gl);
}
/*static*/ bool
WebGL2Context::IsSupported()
{
return Preferences::GetBool("webgl.enable-prototype-webgl2", false);
}
@@ -159,26 +159,16 @@ WebGLContext::InitWebGL2()
}
// we initialise WebGL 2 related stuff.
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&mGLMaxTransformFeedbackSeparateAttribs);
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
- if (MinCapabilityMode()) {
- mGLMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
- mGLMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
- } else {
- gl->fGetIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE,
- (GLint*) &mGLMax3DTextureSize);
- gl->fGetIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
- (GLint*) &mGLMaxArrayTextureLayers);
- }
-
mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
return true;
}
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -3,22 +3,16 @@
* 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/. */
#ifndef WEBGL2CONTEXT_H_
#define WEBGL2CONTEXT_H_
#include "WebGLContext.h"
-/*
- * Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4
- */
-#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE 256
-#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS 256
-
namespace mozilla {
class ErrorResult;
class WebGLSampler;
class WebGLSync;
class WebGLTransformFeedback;
class WebGLVertexArrayObject;
namespace dom {
@@ -91,47 +85,57 @@ public:
ErrorResult& rv);
void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
GLsizei width, GLsizei height);
// -------------------------------------------------------------------------
// Texture objects - WebGL2ContextTextures.cpp
- void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
- void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
- GLsizei depth);
- void TexImage3D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format, GLenum type,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
- ErrorResult& rv);
- void TexSubImage3D(GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLenum type, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
- ErrorResult& rv);
- void TexSubImage3D(GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, dom::ImageData* data,
- ErrorResult& rv);
- template<class ElementType>
- void TexSubImage3D(GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, ElementType& elt, ErrorResult& rv)
- {}
+ void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height);
+ void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height, GLsizei depth);
+ void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
+ GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
+ GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels);
+ void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
+ GLenum unpackFormat, GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
+ ErrorResult& out_rv);
+ void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::ImageData* data, ErrorResult& out_rv);
+protected:
+ void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::Element* elem, ErrorResult* const out_rv);
+public:
+ template<class T>
+ inline void
+ TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
+ GLenum unpackFormat, GLenum unpackType, T& elem, ErrorResult& out_rv)
+ {
+ TexSubImage3D(target, level, xOffset, yOffset, zOffset, unpackFormat, unpackType,
+ &elem, &out_rv);
+ }
- void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height);
- void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
+ void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLint x, GLint y, GLsizei width,
+ GLsizei height);
+ void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& data);
- void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& data);
+ GLint border,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& data);
+ void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum sizedUnpackFormat,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& data);
// -------------------------------------------------------------------------
// Programs and shaders - WebGL2ContextPrograms.cpp
GLint GetFragDataLocation(WebGLProgram* program, const nsAString& name);
// -------------------------------------------------------------------------
@@ -378,17 +382,18 @@ public:
already_AddRefed<WebGLVertexArrayObject> CreateVertexArray();
void DeleteVertexArray(WebGLVertexArrayObject* vertexArray);
bool IsVertexArray(WebGLVertexArrayObject* vertexArray);
void BindVertexArray(WebGLVertexArrayObject* vertexArray);
*/
private:
WebGL2Context();
- virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
+ virtual UniquePtr<webgl::FormatUsageAuthority>
+ CreateFormatUsage(gl::GLContext* gl) const override;
virtual bool IsTexParamValid(GLenum pname) const override;
void UpdateBoundQuery(GLenum target, WebGLQuery* query);
// CreateVertexArrayImpl is assumed to be infallible.
virtual WebGLVertexArray* CreateVertexArrayImpl() override;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) override;
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -23,46 +23,68 @@ GetFBInfoForBlit(const WebGLFramebuffer*
auto status = fb->PrecheckFramebufferStatus();
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
webgl->ErrorInvalidOperation("blitFramebuffer: %s is not"
" framebuffer-complete.", fbInfo);
return false;
}
*out_samples = 1; // TODO
+ *out_colorFormat = nullptr;
+ *out_depthFormat = nullptr;
+ *out_stencilFormat = nullptr;
if (fb->ColorAttachment(0).IsDefined()) {
const auto& attachment = fb->ColorAttachment(0);
- *out_colorFormat = attachment.Format().get();
- } else {
- *out_colorFormat = nullptr;
+ *out_colorFormat = attachment.Format()->format;
}
if (fb->DepthStencilAttachment().IsDefined()) {
const auto& attachment = fb->DepthStencilAttachment();
- *out_depthFormat = attachment.Format().get();
+ *out_depthFormat = attachment.Format()->format;
*out_stencilFormat = *out_depthFormat;
} else {
if (fb->DepthAttachment().IsDefined()) {
const auto& attachment = fb->DepthAttachment();
- *out_depthFormat = attachment.Format().get();
- } else {
- *out_depthFormat = nullptr;
+ *out_depthFormat = attachment.Format()->format;
}
if (fb->StencilAttachment().IsDefined()) {
const auto& attachment = fb->StencilAttachment();
- *out_stencilFormat = attachment.Format().get();
- } else {
- *out_stencilFormat = nullptr;
+ *out_stencilFormat = attachment.Format()->format;
}
}
return true;
}
+static void
+GetBackbufferFormats(const WebGLContextOptions& options,
+ const webgl::FormatInfo** const out_color,
+ const webgl::FormatInfo** const out_depth,
+ const webgl::FormatInfo** const out_stencil)
+{
+ const auto effFormat = options.alpha ? webgl::EffectiveFormat::RGBA8
+ : webgl::EffectiveFormat::RGB8;
+ *out_color = webgl::GetFormat(effFormat);
+
+ *out_depth = nullptr;
+ *out_stencil = nullptr;
+ if (options.depth && options.stencil) {
+ *out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH24_STENCIL8);
+ *out_stencil = *out_depth;
+ } else {
+ if (options.depth) {
+ *out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT16);
+ }
+ if (options.stencil) {
+ *out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
+ }
+ }
+}
+
void
WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
LOCAL_GL_DEPTH_BUFFER_BIT |
LOCAL_GL_STENCIL_BUFFER_BIT;
@@ -96,91 +118,80 @@ WebGL2Context::BlitFramebuffer(GLint src
// the underlying buffers are not the same, not the framebuffers
// themselves.
ErrorInvalidOperation("blitFramebuffer: Source and destination must"
" differ.");
return;
}
GLsizei srcSamples;
- const webgl::FormatInfo* srcColorFormat;
- const webgl::FormatInfo* srcDepthFormat;
- const webgl::FormatInfo* srcStencilFormat;
+ const webgl::FormatInfo* srcColorFormat = nullptr;
+ const webgl::FormatInfo* srcDepthFormat = nullptr;
+ const webgl::FormatInfo* srcStencilFormat = nullptr;
if (mBoundReadFramebuffer) {
if (!GetFBInfoForBlit(mBoundReadFramebuffer, this, "READ_FRAMEBUFFER",
&srcSamples, &srcColorFormat, &srcDepthFormat,
&srcStencilFormat))
{
return;
}
} else {
srcSamples = 1; // Always 1.
- // TODO: Don't hardcode these.
- srcColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
-
- if (mOptions.depth && mOptions.stencil) {
- srcDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
- srcStencilFormat = srcDepthFormat;
- } else {
- if (mOptions.depth) {
- srcDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
- }
- if (mOptions.stencil) {
- srcStencilFormat = LOCAL_GL_STENCIL_INDEX8;
- }
- }
+ GetBackbufferFormats(mOptions, &srcColorFormat, &srcDepthFormat,
+ &srcStencilFormat);
}
GLsizei dstSamples;
- GLenum dstColorFormat = 0;
- GLenum dstDepthFormat = 0;
- GLenum dstStencilFormat = 0;
+ const webgl::FormatInfo* dstColorFormat = nullptr;
+ const webgl::FormatInfo* dstDepthFormat = nullptr;
+ const webgl::FormatInfo* dstStencilFormat = nullptr;
if (mBoundDrawFramebuffer) {
if (!GetFBInfoForBlit(mBoundDrawFramebuffer, this, "DRAW_FRAMEBUFFER",
&dstSamples, &dstColorFormat, &dstDepthFormat,
&dstStencilFormat))
{
return;
}
} else {
dstSamples = gl->Screen()->Samples();
- // TODO: Don't hardcode these.
- dstColorFormat = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
-
- if (mOptions.depth && mOptions.stencil) {
- dstDepthFormat = LOCAL_GL_DEPTH24_STENCIL8;
- dstStencilFormat = dstDepthFormat;
- } else {
- if (mOptions.depth) {
- dstDepthFormat = LOCAL_GL_DEPTH_COMPONENT16;
- }
- if (mOptions.stencil) {
- dstStencilFormat = LOCAL_GL_STENCIL_INDEX8;
- }
- }
+ GetBackbufferFormats(mOptions, &dstColorFormat, &dstDepthFormat,
+ &dstStencilFormat);
}
+ if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+ const auto fnSignlessType = [](const webgl::FormatInfo* format) {
+ if (!format)
+ return webgl::ComponentType::None;
- if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
- const GLenum srcColorType = srcColorFormat ? ValueTypeForFormat(srcColorFormat)
- : 0;
- const GLenum dstColorType = dstColorFormat ? ValueTypeForFormat(dstColorFormat)
- : 0;
- if (dstColorType != srcColorType) {
- ErrorInvalidOperation("blitFramebuffer: Color buffer value type"
+ switch (format->componentType) {
+ case webgl::ComponentType::UInt:
+ return webgl::ComponentType::Int;
+
+ case webgl::ComponentType::NormUInt:
+ return webgl::ComponentType::NormInt;
+
+ default:
+ return format->componentType;
+ }
+ };
+
+ const auto srcType = fnSignlessType(srcColorFormat);
+ const auto dstType = fnSignlessType(dstColorFormat);
+
+ if (srcType != dstType) {
+ ErrorInvalidOperation("blitFramebuffer: Color buffer format component type"
" mismatch.");
return;
}
- const bool srcIsInt = srcColorType == LOCAL_GL_INT ||
- srcColorType == LOCAL_GL_UNSIGNED_INT;
+ const bool srcIsInt = (srcType == webgl::ComponentType::Int);
if (srcIsInt && filter != LOCAL_GL_NEAREST) {
ErrorInvalidOperation("blitFramebuffer: Integer read buffers can only"
" be filtered with NEAREST.");
return;
}
}
/* GLES 3.0.4, p199:
@@ -280,24 +291,24 @@ WebGL2Context::FramebufferTextureLayer(G
"texture object.");
}
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
switch (texture->Target().get()) {
case LOCAL_GL_TEXTURE_3D:
- if ((GLuint) layer >= mGLMax3DTextureSize) {
+ if (uint32_t(layer) >= mImplMax3DTextureSize) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_3D_TEXTURE_SIZE");
}
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
- if ((GLuint) layer >= mGLMaxArrayTextureLayers) {
+ if (uint32_t(layer) >= mImplMaxArrayTextureLayers) {
return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
"MAX_ARRAY_TEXTURE_LAYERS");
}
break;
default:
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
@@ -330,17 +341,17 @@ WebGL2Context::FramebufferTextureLayer(G
fb->FramebufferTextureLayer(attachment, texture, level, layer);
}
JS::Value
WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
GLenum target,
GLenum attachment,
GLenum pname,
- ErrorResult& rv)
+ ErrorResult& out_error)
{
if (IsContextLost())
return JS::NullValue();
// OpenGL ES 3.0.4 (August 27, 2014) 6.1. QUERYING GL STATE 240
// "getFramebufferAttachmentParamter returns information about attachments of a bound
// framebuffer object. target must be DRAW_FRAMEBUFFER, READ_FRAMEBUFFER, or
// FRAMEBUFFER."
@@ -354,81 +365,99 @@ WebGL2Context::GetFramebufferAttachmentP
WebGLFramebuffer* boundFB = nullptr;
switch (target) {
case LOCAL_GL_DRAW_FRAMEBUFFER: boundFB = mBoundDrawFramebuffer; break;
case LOCAL_GL_READ_FRAMEBUFFER: boundFB = mBoundReadFramebuffer; break;
}
if (boundFB) {
- return boundFB->GetAttachmentParameter(cx, attachment, pname, rv);
+ return boundFB->GetAttachmentParameter(cx, target, attachment, pname, &out_error);
}
+ ////////////////
// Handle default FB
- const gl::GLFormats& formats = gl->GetGLFormats();
- GLenum internalFormat = LOCAL_GL_NONE;
- /* If the default framebuffer is bound to target, then attachment must be BACK,
- identifying the color buffer; DEPTH, identifying the depth buffer; or STENCIL,
- identifying the stencil buffer. */
+ // If the default framebuffer is bound to target, then attachment must be BACK,
+ // identifying the color buffer; DEPTH, identifying the depth buffer; or STENCIL,
+ // identifying the stencil buffer.
switch (attachment) {
case LOCAL_GL_BACK:
- internalFormat = formats.color_texInternalFormat;
- break;
-
case LOCAL_GL_DEPTH:
- internalFormat = formats.depth;
- break;
-
case LOCAL_GL_STENCIL:
- internalFormat = formats.stencil;
+ case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
break;
default:
ErrorInvalidEnum("getFramebufferAttachmentParameter: Can only query "
"attachment BACK, DEPTH, or STENCIL from default "
"framebuffer");
return JS::NullValue();
}
- const FormatInfo* info = webgl::GetInfoBySizedFormat(internalFormat);
- MOZ_RELEASE_ASSERT(info);
- EffectiveFormat effectiveFormat = info->effectiveFormat;
-
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
+ if (attachment != LOCAL_GL_BACK)
+ return JS::Int32Value(0);
+
+ return JS::Int32Value(8);
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
+ if (attachment != LOCAL_GL_BACK)
+ return JS::Int32Value(0);
+
+ return JS::Int32Value(mOptions.alpha ? 8 : 0);
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
+ if (attachment != LOCAL_GL_DEPTH &&
+ attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+ {
+ return JS::Int32Value(0);
+ }
+
+ return JS::Int32Value(mOptions.depth ? 16 : 0);
+
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
- return JS::Int32Value(webgl::GetComponentSize(effectiveFormat, pname));
+ if (attachment != LOCAL_GL_STENCIL &&
+ attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+ {
+ return JS::Int32Value(0);
+ }
+
+ return JS::Int32Value(mOptions.stencil ? 8 : 0);
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
- if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT &&
- pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)
- {
+ switch (attachment) {
+ case LOCAL_GL_BACK: return JS::Int32Value(LOCAL_GL_UNSIGNED_NORMALIZED);
+ case LOCAL_GL_DEPTH: return JS::Int32Value(LOCAL_GL_UNSIGNED_NORMALIZED);
+ case LOCAL_GL_STENCIL: return JS::Int32Value(LOCAL_GL_UNSIGNED_INT);
+
+ case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
ErrorInvalidOperation("getFramebufferAttachmentParameter: Querying "
"FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE against "
"DEPTH_STENCIL_ATTACHMENT is an error.");
return JS::NullValue();
}
-
- return JS::Int32Value(webgl::GetComponentType(effectiveFormat));
+ MOZ_CRASH("unreachable");
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
- return JS::Int32Value(webgl::GetColorEncoding(effectiveFormat));
+ if (attachment != LOCAL_GL_BACK)
+ return JS::Int32Value(0);
+
+ return JS::Int32Value(LOCAL_GL_LINEAR);
}
- /* Any combinations of framebuffer type and pname not described above will generate an
- INVALID_ENUM error. */
- ErrorInvalidEnum("getFramebufferAttachmentParameter: Invalid combination of ");
+ // Any combinations of framebuffer type and pname not described above will generate an
+ // INVALID_ENUM error.
+ ErrorInvalidEnum("getFramebufferAttachmentParameter: Invalid combination of params.");
return JS::NullValue();
}
// Map attachments intended for the default buffer, to attachments for a non-
// default buffer.
static bool
TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
{
--- a/dom/canvas/WebGL2ContextState.cpp
+++ b/dom/canvas/WebGL2ContextState.cpp
@@ -54,18 +54,16 @@ WebGL2Context::GetParameter(JSContext* c
return JS::Int32Value(LOCAL_GL_BACK);
}
case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
/* fall through */
/* GLint */
- case LOCAL_GL_MAX_3D_TEXTURE_SIZE:
- case LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS:
case LOCAL_GL_MAX_COMBINED_UNIFORM_BLOCKS:
case LOCAL_GL_MAX_ELEMENTS_INDICES:
case LOCAL_GL_MAX_ELEMENTS_VERTICES:
case LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS:
case LOCAL_GL_MAX_FRAGMENT_UNIFORM_BLOCKS:
case LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
case LOCAL_GL_MAX_PROGRAM_TEXEL_OFFSET:
case LOCAL_GL_MAX_SAMPLES:
@@ -84,16 +82,22 @@ WebGL2Context::GetParameter(JSContext* c
case LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT:
case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
case LOCAL_GL_UNPACK_ROW_LENGTH: {
GLint val;
gl->fGetIntegerv(pname, &val);
return JS::Int32Value(val);
}
+ case LOCAL_GL_MAX_3D_TEXTURE_SIZE:
+ return JS::Int32Value(mImplMax3DTextureSize);
+
+ case LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS:
+ return JS::Int32Value(mImplMaxArrayTextureLayers);
+
case LOCAL_GL_MAX_VARYING_COMPONENTS: {
// On OS X Core Profile this is buggy. The spec says that the
// value is 4 * GL_MAX_VARYING_VECTORS
GLint val;
gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &val);
return JS::Int32Value(4*val);
}
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -5,112 +5,236 @@
#include "GLContext.h"
#include "WebGL2Context.h"
#include "WebGLContextUtils.h"
#include "WebGLTexture.h"
namespace mozilla {
+static bool
+ValidateTargetMatchesFuncDims(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
+ GLenum rawTexTarget)
+{
+ uint8_t targetDims = 0;
+ switch (rawTexTarget) {
+ case LOCAL_GL_TEXTURE_2D:
+ case LOCAL_GL_TEXTURE_CUBE_MAP:
+ targetDims = 2;
+ break;
+
+ case LOCAL_GL_TEXTURE_3D:
+ targetDims = 3;
+ break;
+ }
+
+ if (targetDims != funcDims) {
+ webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName);
+ return false;
+ }
+
+ return true;
+}
+
void
-WebGL2Context::TexStorage2D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height)
+WebGL2Context::TexStorage2D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat,
+ GLsizei width, GLsizei height)
{
const char funcName[] = "TexStorage2D";
- TexTarget texTarget;
- WebGLTexture* tex;
- if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
+ const uint8_t funcDims = 2;
+
+ if (!ValidateTargetMatchesFuncDims(this, funcName, funcDims, rawTexTarget))
return;
- tex->TexStorage2D(texTarget, levels, internalFormat, width, height);
+ TexTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexTarget(this, funcName, rawTexTarget, &target, &tex))
+ return;
+
+ const GLsizei depth = 1;
+ tex->TexStorage(funcName, target, levels, internalFormat, width, height, depth);
}
void
WebGL2Context::TexStorage3D(GLenum rawTexTarget, GLsizei levels, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth)
{
const char funcName[] = "texStorage3D";
- TexTarget texTarget;
- WebGLTexture* tex;
- if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
+ const uint8_t funcDims = 3;
+
+ if (!ValidateTargetMatchesFuncDims(this, funcName, funcDims, rawTexTarget))
return;
- tex->TexStorage3D(texTarget, levels, internalFormat, width, height, depth);
+ TexTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexTarget(this, funcName, rawTexTarget, &target, &tex))
+ return;
+
+ tex->TexStorage(funcName, target, levels, internalFormat, width, height, depth);
}
void
WebGL2Context::TexImage3D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv)
+ GLsizei width, GLsizei height, GLsizei depth, GLint border,
+ GLenum unpackFormat, GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
{
const char funcName[] = "texImage3D";
- TexImageTarget texImageTarget;
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ const bool isSubImage = false;
+ const GLint xOffset = 0;
+ const GLint yOffset = 0;
+ const GLint zOffset = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, width, height, depth, border, unpackFormat,
+ unpackType, maybeView);
+}
+
+void
+WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum unpackFormat, GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
+ ErrorResult& /*out_rv*/)
+{
+ const char funcName[] = "texSubImage3D";
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ const GLint border = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, width, height, depth, border, unpackFormat,
+ unpackType, maybeView);
+}
+
+void
+WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum unpackFormat,
+ GLenum unpackType, dom::ImageData* imageData,
+ ErrorResult& /*out_rv*/)
+{
+ const char funcName[] = "texSubImage3D";
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
{
return;
}
- tex->TexImage3D(texImageTarget, level, internalFormat, width, height, depth, border,
- unpackFormat, unpackType, maybeView, &out_rv);
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, imageData);
}
void
-WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level,
- GLint xOffset, GLint yOffset, GLint zOffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv)
+WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum unpackFormat,
+ GLenum unpackType, dom::Element* elem,
+ ErrorResult* const out_rv)
{
const char funcName[] = "texSubImage3D";
- TexImageTarget texImageTarget;
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, funcName, &texImageTarget, &tex))
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
{
return;
}
- tex->TexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, width, height,
- depth, unpackFormat, unpackType, maybeView, &out_rv);
-
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, elem, out_rv);
}
void
-WebGL2Context::TexSubImage3D(GLenum target, GLint level,
- GLint xOffset, GLint yOffset, GLint zOffset,
- GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult& out_rv)
+WebGL2Context::CompressedTexImage3D(GLenum rawTexImageTarget, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
- GenerateWarning("texSubImage3D: Not implemented.");
+ const char funcName[] = "compressedTexImage3D";
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ tex->CompressedTexImage(funcName, target, level, internalFormat, width, height, depth,
+ border, view);
}
void
-WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
- GLint xOffset, GLint yOffset, GLint zOffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
+WebGL2Context::CompressedTexSubImage3D(GLenum rawTexImageTarget, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum sizedUnpackFormat,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
- GenerateWarning("copyTexSubImage3D: Not implemented.");
+ const char funcName[] = "compressedTexSubImage3D";
+ const uint8_t funcDims = 3;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ tex->CompressedTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width,
+ height, depth, sizedUnpackFormat, view);
}
void
-WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+WebGL2Context::CopyTexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLint x, GLint y,
+ GLsizei width, GLsizei height)
{
- GenerateWarning("compressedTexImage3D: Not implemented.");
-}
+ const char funcName[] = "copyTexSubImage3D";
+ const uint8_t funcDims = 3;
-void
-WebGL2Context::CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
-{
- GenerateWarning("compressedTexSubImage3D: Not implemented.");
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ tex->CopyTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, x, y, width,
+ height);
}
bool
WebGL2Context::IsTexParamValid(GLenum pname) const
{
switch (pname) {
case LOCAL_GL_TEXTURE_BASE_LEVEL:
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -50,17 +50,17 @@ public:
size_t updateSizeInBytes);
bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
uint32_t* const out_upperBound);
bool IsElementArrayUsedWithMultipleTypes() const;
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
const GLenum mGLName;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -106,19 +106,16 @@ WebGLContext::WebGLContext()
mGeneration = 0;
mInvalidated = false;
mCapturedFrameInvalidated = false;
mShouldPresent = true;
mResetLayer = true;
mOptionsFrozen = false;
mActiveTexture = 0;
- mPixelStoreFlipY = false;
- mPixelStorePremultiplyAlpha = false;
- mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
mVertexAttrib0Vector[0] = 0;
mVertexAttrib0Vector[1] = 0;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
mFakeVertexAttrib0BufferObjectVector[0] = 0;
mFakeVertexAttrib0BufferObjectVector[1] = 0;
mFakeVertexAttrib0BufferObjectVector[2] = 0;
@@ -135,41 +132,16 @@ WebGLContext::WebGLContext()
mViewportHeight = 0;
mDitherEnabled = 1;
mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
mScissorTestEnabled = 0;
mDepthTestEnabled = 0;
mStencilTestEnabled = 0;
- // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
- // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
- mGLMaxVertexAttribs = 0;
- mGLMaxTextureUnits = 0;
- mGLMaxTextureSize = 0;
- mGLMaxTextureSizeLog2 = 0;
- mGLMaxCubeMapTextureSize = 0;
- mGLMaxCubeMapTextureSizeLog2 = 0;
- mGLMaxRenderbufferSize = 0;
- mGLMaxTextureImageUnits = 0;
- mGLMaxVertexTextureImageUnits = 0;
- mGLMaxVaryingVectors = 0;
- mGLMaxFragmentUniformVectors = 0;
- mGLMaxVertexUniformVectors = 0;
- mGLMaxColorAttachments = 1;
- mGLMaxDrawBuffers = 1;
- mGLMaxTransformFeedbackSeparateAttribs = 0;
- mGLMaxUniformBufferBindings = 0;
- mGLMax3DTextureSize = 0;
- mGLMaxArrayTextureLayers = 0;
-
- // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
- mPixelStorePackAlignment = 4;
- mPixelStoreUnpackAlignment = 4;
-
if (NS_IsMainThread()) {
// XXX mtseng: bug 709490, not thread safe
WebGLMemoryTracker::AddWebGLContext(this);
}
mAllowContextRestore = true;
mLastLossWasSimulated = false;
mContextLossHandler = new WebGLContextLossHandler(this);
@@ -1816,36 +1788,42 @@ WebGLContext::DidRefresh()
if (gl) {
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
size_t
RoundUpToMultipleOf(size_t value, size_t multiple)
{
- size_t overshoot = value + multiple - 1;
- return overshoot - (overshoot % multiple);
+ return ((value + multiple - 1) / multiple) * multiple;
}
CheckedUint32
-RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y)
+RoundedToNextMultipleOf(CheckedUint32 value, CheckedUint32 multiple)
{
- return ((x + y - 1) / y) * y;
+ return ((value + multiple - 1) / multiple) * multiple;
}
bool
WebGLContext::ValidateCurFBForRead(const char* funcName,
- TexInternalFormat* const out_format,
+ const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height)
{
if (!mBoundReadFramebuffer) {
ClearBackbufferIfNeeded();
- // FIXME - here we're assuming that the default framebuffer is backed by UNSIGNED_BYTE
- // that might not always be true, say if we had a 16bpp default framebuffer.
- *out_format = mOptions.alpha ? LOCAL_GL_RGBA8 : LOCAL_GL_RGB8;
+
+ // FIXME - here we're assuming that the default framebuffer is backed by
+ // UNSIGNED_BYTE that might not always be true, say if we had a 16bpp default
+ // framebuffer.
+ auto effFormat = mOptions.alpha ? webgl::EffectiveFormat::RGBA8
+ : webgl::EffectiveFormat::RGB8;
+
+ *out_format = mFormatUsage->GetUsage(effFormat);
+ MOZ_ASSERT(*out_format);
+
*out_width = mWidth;
*out_height = mHeight;
return true;
}
return mBoundReadFramebuffer->ValidateForRead(funcName, out_format, out_width,
out_height);
}
@@ -1883,16 +1861,203 @@ WebGLContext::ScopedMaskWorkaround::~Sco
if (mFakeNoDepth) {
mWebGL.gl->fEnable(LOCAL_GL_DEPTH_TEST);
}
if (mFakeNoStencil) {
mWebGL.gl->fEnable(LOCAL_GL_STENCIL_TEST);
}
}
+////////////////////
+
+ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
+ : ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
+ , mWebGL(webgl)
+{
+ gl::GLContext* gl = mWebGL->gl;
+
+ if (mWebGL->mPixelStore_UnpackAlignment != 4) gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT , 4);
+
+ if (mWebGL->IsWebGL2()) {
+ if (mWebGL->mPixelStore_UnpackRowLength != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , 0);
+ if (mWebGL->mPixelStore_UnpackImageHeight != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0);
+ if (mWebGL->mPixelStore_UnpackSkipPixels != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , 0);
+ if (mWebGL->mPixelStore_UnpackSkipRows != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS , 0);
+ if (mWebGL->mPixelStore_UnpackSkipImages != 0) gl->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , 0);
+
+ if (mWebGL->mBoundPixelUnpackBuffer) gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+}
+
+void
+ScopedUnpackReset::UnwrapImpl()
+{
+ // Check that we're not falling out of scope after the current context changed.
+ MOZ_ASSERT(mGL->IsCurrent());
+
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mWebGL->mPixelStore_UnpackAlignment);
+
+ if (mWebGL->IsWebGL2()) {
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , mWebGL->mPixelStore_UnpackRowLength );
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mWebGL->mPixelStore_UnpackImageHeight);
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , mWebGL->mPixelStore_UnpackSkipPixels );
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS , mWebGL->mPixelStore_UnpackSkipRows );
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , mWebGL->mPixelStore_UnpackSkipImages );
+
+ GLuint pbo = 0;
+ if (mWebGL->mBoundPixelUnpackBuffer) {
+ pbo = mWebGL->mBoundPixelUnpackBuffer->mGLName;
+ }
+
+ mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, pbo);
+ }
+}
+
+////////////////////////////////////////
+
+bool
+GuessAlignmentFromStride(size_t width, size_t stride, size_t maxAlignment,
+ size_t* const out_alignment)
+{
+ size_t alignmentGuess = maxAlignment;
+ while (alignmentGuess) {
+ size_t guessStride = RoundUpToMultipleOf(width, alignmentGuess);
+ if (guessStride == stride) {
+ *out_alignment = alignmentGuess;
+ return true;
+ }
+ alignmentGuess /= 2;
+ }
+ return false;
+}
+
+void
+Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
+ uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
+ uint32_t* const out_intSize)
+{
+ // Only >0 if dstStartInSrc is >0:
+ // 0 3 // src coords
+ // | [========] // dst box
+ // ^--^
+ *out_intStartInSrc = std::max<int32_t>(0, dstStartInSrc);
+
+ // Only >0 if dstStartInSrc is <0:
+ //-6 0 // src coords
+ // [=====|==] // dst box
+ // ^-----^
+ *out_intStartInDst = std::max<int32_t>(0, 0 - dstStartInSrc);
+
+ int32_t intEndInSrc = std::min<int32_t>(srcSize, dstStartInSrc + dstSize);
+ *out_intSize = std::max<int32_t>(0, intEndInSrc - *out_intStartInSrc);
+}
+
+bool
+ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture,
+ TexImageTarget target, uint32_t level,
+ const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
+ uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth)
+{
+ // This has two usecases:
+ // 1. Lazy zeroing of uninitialized textures:
+ // a. Before draw, when FakeBlack isn't viable. (TexStorage + Draw*)
+ // b. Before partial upload. (TexStorage + TexSubImage)
+ // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
+
+ // We have no sympathy for any of these cases.
+
+ // "Doctor, it hurts when I do this!" "Well don't do that!"
+ webgl->GenerateWarning("%s: This operation requires zeroing texture data. This is"
+ " slow.",
+ funcName);
+
+ gl::GLContext* gl = webgl->GL();
+ gl->MakeCurrent();
+
+ ScopedUnpackReset scopedReset(webgl);
+ gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well.
+
+ auto compression = usage->format->compression;
+ if (compression) {
+ MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
+ MOZ_RELEASE_ASSERT(!respecifyTexture);
+
+ auto sizedFormat = usage->format->sizedFormat;
+ MOZ_RELEASE_ASSERT(sizedFormat);
+
+ const auto fnSizeInBlocks = [](CheckedUint32 pixels, uint8_t pixelsPerBlock) {
+ return RoundUpToMultipleOf(pixels, pixelsPerBlock) / pixelsPerBlock;
+ };
+
+ const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth);
+ const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight);
+
+ CheckedUint32 checkedByteCount = compression->bytesPerBlock;
+ checkedByteCount *= widthBlocks;
+ checkedByteCount *= heightBlocks;
+ checkedByteCount *= depth;
+
+ if (!checkedByteCount.isValid())
+ return false;
+
+ const size_t byteCount = checkedByteCount.value();
+
+ UniqueBuffer zeros(calloc(1, byteCount));
+ if (!zeros)
+ return false;
+
+ GLenum error = DoCompressedTexSubImage(gl, target.get(), level, xOffset, yOffset,
+ zOffset, width, height, depth, sizedFormat,
+ byteCount, zeros.get());
+ if (error)
+ return false;
+
+ return true;
+ }
+
+ const auto driverUnpackInfo = usage->idealUnpack;
+ MOZ_RELEASE_ASSERT(driverUnpackInfo);
+
+ const auto unpackFormat = driverUnpackInfo->unpackFormat;
+ const auto unpackType = driverUnpackInfo->unpackType;
+ const webgl::PackingInfo packing = { unpackFormat, unpackType };
+
+ const auto bytesPerPixel = webgl::BytesPerPixel(packing);
+
+ CheckedUint32 checkedByteCount = bytesPerPixel;
+ checkedByteCount *= width;
+ checkedByteCount *= height;
+ checkedByteCount *= depth;
+
+ if (!checkedByteCount.isValid())
+ return false;
+
+ const size_t byteCount = checkedByteCount.value();
+
+ UniqueBuffer zeros(calloc(1, byteCount));
+ if (!zeros)
+ return false;
+
+ GLenum error;
+ if (respecifyTexture) {
+ MOZ_RELEASE_ASSERT(!xOffset && !yOffset && !zOffset);
+
+ const auto internalFormat = driverUnpackInfo->internalFormat;
+ error = DoTexImage(gl, target, level, internalFormat, width, height, depth,
+ unpackFormat, unpackType, zeros.get());
+ } else {
+ error = DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
+ depth, unpackFormat, unpackType, zeros.get());
+ }
+ if (error)
+ return false;
+
+ return true;
+}
+
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mCanvasElement,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -21,26 +21,29 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "nsCycleCollectionNoteChild.h"
#include "nsICanvasRenderingContextInternal.h"
#include "nsLayoutUtils.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "SurfaceTypes.h"
+#include "ScopedGLHelpers.h"
+#include "TexUnpackBlob.h"
#ifdef XP_MACOSX
#include "ForceDiscreteGPUHelperCGL.h"
#endif
// Local
#include "WebGLContextUnchecked.h"
#include "WebGLFormats.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
+#include "WebGLTexture.h"
// Generated
#include "nsIDOMEventListener.h"
#include "nsIDOMWebGLRenderingContext.h"
#include "nsICanvasRenderingContextInternal.h"
#include "nsIObserver.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsWrapperCache.h"
@@ -63,27 +66,34 @@ class nsIDocShell;
#define MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS 128 // Page 164
#define MINVALUE_GL_MAX_VARYING_VECTORS 8 // Page 164
#define MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS 8 // Page 164
#define MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0 // Page 164
#define MINVALUE_GL_MAX_RENDERBUFFER_SIZE 1024 // Different from the spec, which sets it to 1 on page 164
#define MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 8 // Page 164
/*
+ * Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4
+ */
+#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE 256
+#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS 256
+
+/*
* WebGL-only GLenums
*/
#define LOCAL_GL_BROWSER_DEFAULT_WEBGL 0x9244
#define LOCAL_GL_CONTEXT_LOST_WEBGL 0x9242
#define LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL 0x9247
#define LOCAL_GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243
#define LOCAL_GL_UNPACK_FLIP_Y_WEBGL 0x9240
#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
namespace mozilla {
+class ScopedUnpackReset;
class WebGLActiveInfo;
class WebGLContextLossHandler;
class WebGLBuffer;
class WebGLExtensionBase;
class WebGLFramebuffer;
class WebGLProgram;
class WebGLQuery;
class WebGLRenderbuffer;
@@ -106,16 +116,19 @@ template<typename> struct Nullable;
namespace gfx {
class SourceSurface;
} // namespace gfx
namespace webgl {
struct LinkedProgramInfo;
class ShaderValidator;
+class TexUnpackBuffer;
+class TexUnpackImage;
+class TexUnpackSrcSurface;
} // namespace webgl
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
struct WebGLContextOptions
{
@@ -518,16 +531,21 @@ public:
bool IsProgram(WebGLProgram* prog);
bool IsRenderbuffer(WebGLRenderbuffer* rb);
bool IsShader(WebGLShader* shader);
bool IsVertexArray(WebGLVertexArray* vao);
void LineWidth(GLfloat width);
void LinkProgram(WebGLProgram* prog);
void PixelStorei(GLenum pname, GLint param);
void PolygonOffset(GLfloat factor, GLfloat units);
+protected:
+ bool DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum destFormat, GLenum destType, void* destBytes,
+ GLenum auxReadFormat, GLenum auxReadType);
+public:
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type,
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
ErrorResult& rv);
void RenderbufferStorage(GLenum target, GLenum internalFormat,
GLsizei width, GLsizei height);
protected:
void RenderbufferStorage_base(const char* funcName, GLenum target,
@@ -880,56 +898,72 @@ public:
void CopyTexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLint x, GLint y, GLsizei width,
GLsizei height);
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
GLenum unpackType,
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv);
+ ErrorResult&);
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult& out_rv);
+ ErrorResult&);
void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
- ErrorResult* const out_rv);
-
+ ErrorResult* const out_error);
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
GLsizei width, GLsizei height, GLenum unpackFormat,
GLenum unpackType,
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv);
+ ErrorResult&);
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult& out_rv);
+ ErrorResult&);
void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
- ErrorResult* const out_rv);
+ ErrorResult* const out_error);
// Allow whatever element unpackTypes the bindings are willing to pass
// us in Tex(Sub)Image2D
- template<typename ElementT>
- void TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
- GLenum unpackFormat, GLenum unpackType, ElementT& elem,
- ErrorResult& out_rv)
+ template<typename T>
+ inline void
+ TexImage2D(GLenum texImageTarget, GLint level, GLenum internalFormat,
+ GLenum unpackFormat, GLenum unpackType, T& elem, ErrorResult& out_error)
{
TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType, &elem,
- &out_rv);
+ &out_error);
}
- template<typename ElementT>
- void TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
- GLenum unpackFormat, GLenum unpackType, ElementT& elem,
- ErrorResult& out_rv)
+
+ template<typename T>
+ inline void
+ TexSubImage2D(GLenum texImageTarget, GLint level, GLint xOffset, GLint yOffset,
+ GLenum unpackFormat, GLenum unpackType, T& elem, ErrorResult& out_error)
{
TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
- &elem, &out_rv);
+ &elem, &out_error);
}
+ // WebGLTextureUpload.cpp
+ bool ValidateTexImageSpecification(const char* funcName, uint8_t funcDims,
+ GLenum texImageTarget, GLint level,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border,
+ TexImageTarget* const out_target,
+ WebGLTexture** const out_texture,
+ WebGLTexture::ImageInfo** const out_imageInfo);
+ bool ValidateTexImageSelection(const char* funcName, uint8_t funcDims,
+ GLenum texImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth,
+ TexImageTarget* const out_target,
+ WebGLTexture** const out_texture,
+ WebGLTexture::ImageInfo** const out_imageInfo);
+
// -----------------------------------------------------------------------------
// Vertices Feature (WebGLContextVertices.cpp)
public:
void DrawArrays(GLenum mode, GLint first, GLsizei count);
void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
GLsizei primcount);
void DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset);
@@ -1023,20 +1057,16 @@ private:
// -----------------------------------------------------------------------------
// PROTECTED
protected:
WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
bool DoFakeVertexAttrib0(GLuint vertexCount);
void UndoFakeVertexAttrib0();
- static CheckedUint32 GetImageSize(GLsizei height, GLsizei width,
- GLsizei depth, uint32_t pixelSize,
- uint32_t alignment);
-
inline void InvalidateBufferFetching()
{
mBufferFetchingIsVerified = false;
mBufferFetchingHasPerVertex = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
}
@@ -1071,44 +1101,44 @@ protected:
bool mBypassShaderValidation;
webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
// some GL constants
int32_t mGLMaxVertexAttribs;
int32_t mGLMaxTextureUnits;
- int32_t mGLMaxTextureSize;
- int32_t mGLMaxTextureSizeLog2;
- int32_t mGLMaxCubeMapTextureSize;
- int32_t mGLMaxCubeMapTextureSizeLog2;
- int32_t mGLMaxRenderbufferSize;
int32_t mGLMaxTextureImageUnits;
int32_t mGLMaxVertexTextureImageUnits;
int32_t mGLMaxVaryingVectors;
int32_t mGLMaxFragmentUniformVectors;
int32_t mGLMaxVertexUniformVectors;
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
GLuint mGLMaxUniformBufferBindings;
GLsizei mGLMaxSamples;
- GLuint mGLMax3DTextureSize;
- GLuint mGLMaxArrayTextureLayers;
+
+ // Texture sizes are often not actually the GL values. Let's be explicit that these
+ // are implementation limits.
+ uint32_t mImplMaxTextureSize;
+ uint32_t mImplMaxCubeMapTextureSize;
+ uint32_t mImplMax3DTextureSize;
+ uint32_t mImplMaxArrayTextureLayers;
+ uint32_t mImplMaxRenderbufferSize;
public:
GLuint MaxVertexAttribs() const {
return mGLMaxVertexAttribs;
}
GLuint GLMaxTextureUnits() const {
return mGLMaxTextureUnits;
}
-
bool IsFormatValidForFB(TexInternalFormat format) const;
protected:
// Represents current status of the context with respect to context loss.
// That is, whether the context is lost, and what part of the context loss
// process we currently are at.
// This is used to support the WebGL spec's asyncronous nature in handling
// context loss.
@@ -1238,57 +1268,55 @@ protected:
uint32_t byteLength,
WebGLTexImageFunc func,
WebGLTexDimensions dims);
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
WebGLProgram* program,
const char* funcName);
- bool ValidateCurFBForRead(const char* funcName, TexInternalFormat* const out_format,
+ bool ValidateCurFBForRead(const char* funcName,
+ const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
void Invalidate();
void DestroyResourcesAndContext();
void MakeContextCurrent() const;
// helpers
bool ConvertImage(size_t width, size_t height, size_t srcStride,
size_t dstStride, const uint8_t* src, uint8_t* dst,
WebGLTexelFormat srcFormat, bool srcPremultiplied,
WebGLTexelFormat dstFormat, bool dstPremultiplied,
size_t dstTexelSize);
- template<class ElementType>
+public:
nsLayoutUtils::SurfaceFromElementResult
- SurfaceFromElement(ElementType* element) {
- MOZ_ASSERT(element);
+ SurfaceFromElement(dom::Element* elem)
+ {
+ uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
- uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE;
- if (mPixelStoreColorspaceConversion == LOCAL_GL_NONE)
+ if (mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
- if (!mPixelStorePremultiplyAlpha)
+
+ if (!mPixelStore_PremultiplyAlpha)
flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
- return nsLayoutUtils::SurfaceFromElement(element, flags);
- }
-
- template<class ElementType>
- nsLayoutUtils::SurfaceFromElementResult
- SurfaceFromElement(ElementType& element) {
- return SurfaceFromElement(&element);
+ gfx::DrawTarget* idealDrawTarget = nullptr; // Don't care for now.
+ return nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
}
nsresult
- SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
- RefPtr<gfx::DataSourceSurface>& imageOut,
- WebGLTexelFormat* format);
+ SurfaceFromElementResultToImageSurface(const nsLayoutUtils::SurfaceFromElementResult& res,
+ RefPtr<gfx::DataSourceSurface>* const out_image,
+ WebGLTexelFormat* const out_format);
+protected:
// Returns false if `object` is null or not valid.
template<class ObjectType>
bool ValidateObject(const char* info, ObjectType* object);
// Returns false if `object` is not valid. Considers null to be valid.
template<class ObjectType>
bool ValidateObjectAllowNull(const char* info, ObjectType* object);
@@ -1317,35 +1345,26 @@ private:
virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info);
virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0;
virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
protected:
- int32_t MaxTextureSizeForTarget(TexTarget target) const {
- return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize
- : mGLMaxCubeMapTextureSize;
- }
-
- int32_t
- MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const {
- const TexTarget target = TexImageTargetToTexTarget(texImageTarget);
- return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSizeLog2
- : mGLMaxCubeMapTextureSizeLog2;
- }
-
/** Like glBufferData, but if the call may change the buffer size, checks
* any GL error generated by this glBufferData call and returns it.
*/
GLenum CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
GLenum usage);
+public:
void ForceLoseContext(bool simulateLoss = false);
+
+protected:
void ForceRestoreContext();
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
nsTArray<WebGLRefPtr<WebGLSampler> > mBoundSamplers;
void ResolveTexturesForDraw() const;
@@ -1377,24 +1396,37 @@ protected:
// TODO(djg): Does this need a rethink? Should it be WebGL2Context?
LinkedList<WebGLSampler> mSamplers;
LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
WebGLRefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
// PixelStore parameters
- uint32_t mPixelStorePackAlignment;
- uint32_t mPixelStoreUnpackAlignment;
- uint32_t mPixelStoreColorspaceConversion;
- bool mPixelStoreFlipY;
- bool mPixelStorePremultiplyAlpha;
+ uint32_t mPixelStore_UnpackImageHeight;
+ uint32_t mPixelStore_UnpackSkipImages;
+ uint32_t mPixelStore_UnpackRowLength;
+ uint32_t mPixelStore_UnpackSkipRows;
+ uint32_t mPixelStore_UnpackSkipPixels;
+ uint32_t mPixelStore_UnpackAlignment;
+ uint32_t mPixelStore_PackRowLength;
+ uint32_t mPixelStore_PackSkipRows;
+ uint32_t mPixelStore_PackSkipPixels;
+ uint32_t mPixelStore_PackAlignment;
+ CheckedUint32 GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
+ CheckedUint32* const out_startOffset,
+ CheckedUint32* const out_rowStride);
+
+ GLenum mPixelStore_ColorspaceConversion;
+ bool mPixelStore_FlipY;
+ bool mPixelStore_PremultiplyAlpha;
+
+public:
// Fake-black
-public:
class FakeBlackTexture {
gl::GLContext* const mGL;
GLuint mGLName;
public:
FakeBlackTexture(gl::GLContext* gl, TexTarget target, GLenum format);
~FakeBlackTexture();
GLuint GLName() const { return mGLName; }
@@ -1405,17 +1437,17 @@ public:
protected:
bool mCanSkipFakeBlack;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Opaque;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Alpha;
UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_Opaque;
UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_Alpha;
- void BindFakeBlackTextures();
+ bool BindFakeBlackTextures(const char* funcName);
void UnbindFakeBlackTextures();
// Generic Vertex Attributes
UniquePtr<GLenum[]> mVertexAttribType;
GLfloat mVertexAttrib0Vector[4];
GLfloat mFakeVertexAttrib0BufferObjectVector[4];
size_t mFakeVertexAttrib0BufferObjectSize;
GLuint mFakeVertexAttrib0BufferObject;
@@ -1522,19 +1554,24 @@ protected:
public:
// console logging helpers
void GenerateWarning(const char* fmt, ...);
void GenerateWarning(const char* fmt, va_list ap);
public:
UniquePtr<webgl::FormatUsageAuthority> mFormatUsage;
- virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const = 0;
+
+ virtual UniquePtr<webgl::FormatUsageAuthority>
+ CreateFormatUsage(gl::GLContext* gl) const = 0;
// Friend list
+ friend class ScopedUnpackReset;
+ friend class webgl::TexUnpackBytes;
+ friend class webgl::TexUnpackSurface;
friend class WebGLTexture;
friend class WebGLFramebuffer;
friend class WebGLRenderbuffer;
friend class WebGLProgram;
friend class WebGLQuery;
friend class WebGLBuffer;
friend class WebGLSampler;
friend class WebGLShader;
@@ -1619,29 +1656,103 @@ WebGLContext::ValidateObject(const char*
if (!object) {
ErrorInvalidValue("%s: null object passed as argument", info);
return false;
}
return ValidateObjectAssumeNonNull(info, object);
}
-size_t RoundUpToMultipleOf(size_t value, size_t multiple);
+// Returns `value` rounded to the next highest multiple of `multiple`.
+// AKA PadToAlignment, StrideForAlignment.
+template<typename V, typename M>
+V
+RoundUpToMultipleOf(const V& value, const M& multiple)
+{
+ return ((value + multiple - 1) / multiple) * multiple;
+}
bool
-ValidateTexTarget(WebGLContext* webgl, GLenum rawTexTarget, const char* funcName,
+ValidateTexTarget(WebGLContext* webgl, const char* funcName, GLenum rawTexTarget,
TexTarget* const out_texTarget, WebGLTexture** const out_tex);
bool
-ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
- const char* funcName, TexImageTarget* const out_texImageTarget,
+ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
+ GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget,
WebGLTexture** const out_tex);
-// Returns x rounded to the next highest multiple of y.
-CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y);
+
+bool
+GuessAlignmentFromStride(size_t width, size_t stride, size_t maxAlignment,
+ size_t* const out_alignment);
+
+class UniqueBuffer
+{
+ void* mBuffer;
+
+public:
+ UniqueBuffer()
+ : mBuffer(nullptr)
+ { }
+
+ explicit UniqueBuffer(void* buffer)
+ : mBuffer(buffer)
+ { }
+
+ explicit UniqueBuffer(UniqueBuffer&& other) {
+ this->mBuffer = other.mBuffer;
+ other.mBuffer = nullptr;
+ }
+
+ UniqueBuffer& operator =(UniqueBuffer&& other) {
+ free(this->mBuffer);
+ this->mBuffer = other.mBuffer;
+ other.mBuffer = nullptr;
+ return *this;
+ }
+
+ UniqueBuffer& operator =(void* newBuffer) {
+ free(this->mBuffer);
+ this->mBuffer = newBuffer;
+ return *this;
+ }
+
+ explicit operator bool() const { return bool(mBuffer); }
+
+ void* get() const { return mBuffer; }
+
+ UniqueBuffer(const UniqueBuffer& other) = delete; // construct using Move()!
+ void operator =(const UniqueBuffer& other) = delete; // assign using Move()!
+};
+
+class ScopedUnpackReset
+ : public gl::ScopedGLWrapper<ScopedUnpackReset>
+{
+ friend struct gl::ScopedGLWrapper<ScopedUnpackReset>;
+
+protected:
+ WebGLContext* const mWebGL;
+
+public:
+ explicit ScopedUnpackReset(WebGLContext* webgl);
+
+protected:
+ void UnwrapImpl();
+};
void
ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
void** const out_data, size_t* const out_length,
js::Scalar::Type* const out_type);
+void
+Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
+ uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
+ uint32_t* const out_intSize);
+
+bool
+ZeroTextureData(WebGLContext* webgl, const char* funcName, bool respecifyTexture,
+ TexImageTarget target, uint32_t level,
+ const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
+ uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
+
} // namespace mozilla
#endif
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -110,17 +110,18 @@ WebGLContext::DrawArrays_check(GLint fir
if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
- BindFakeBlackTextures();
+ if (!BindFakeBlackTextures(info))
+ return false;
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
{
if (IsContextLost())
@@ -291,17 +292,18 @@ WebGLContext::DrawElements_check(GLsizei
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
- BindFakeBlackTextures();
+ if (!BindFakeBlackTextures(info))
+ return false;
return true;
}
void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset)
{
@@ -653,59 +655,59 @@ WebGLContext::UndoFakeVertexAttrib0()
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
}
static bool
-BindFakeBlackHelper(gl::GLContext* gl, TexTarget target,
+BindFakeBlackHelper(const char* funcName, gl::GLContext* gl, TexTarget target,
const nsTArray<WebGLRefPtr<WebGLTexture>>& texArray,
WebGLContext::FakeBlackTexture* opaqueTex,
- WebGLContext::FakeBlackTexture* alphaTex)
+ WebGLContext::FakeBlackTexture* alphaTex, bool* const out_wasNeeded)
{
MOZ_ASSERT(opaqueTex && alphaTex);
- bool wasNeeded = false;
+ *out_wasNeeded = false;
int32_t len = texArray.Length();
for (int32_t i = 0; i < len; i++) {
WebGLTexture* tex = texArray[i];
if (!tex)
continue;
WebGLTextureFakeBlackStatus status;
- if (!tex->ResolveFakeBlackStatus(&status))
- return true; // Technically this should propagate up as a critical failure.
- // I believe this is currently harmless.
+ if (!tex->ResolveFakeBlackStatus(funcName, &status))
+ return false; // World is currently exploding...
+
MOZ_ASSERT(status != WebGLTextureFakeBlackStatus::Unknown);
if (MOZ_LIKELY(status == WebGLTextureFakeBlackStatus::NotNeeded))
continue;
// Ok, needs fake-black.
- wasNeeded = true;
+ *out_wasNeeded = true;
// Default to (0, 0, 0, 1) for incomplete textures, as well as uninit'd alpha-less
// formats.
WebGLContext::FakeBlackTexture* fakeTex = opaqueTex;
if (status == WebGLTextureFakeBlackStatus::UninitializedImageData) {
const auto& imageInfo = tex->BaseImageInfo();
- if (FormatHasAlpha(imageInfo.mFormat)) {
+ if (imageInfo.mFormat->format->hasAlpha) {
fakeTex = alphaTex;
}
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(target.get(), fakeTex->GLName());
}
- return wasNeeded;
+ return true;
}
static bool
UnbindFakeBlackHelper(gl::GLContext* gl, TexTarget target,
const nsTArray<WebGLRefPtr<WebGLTexture>>& texArray)
{
bool changedActiveTex = false;
@@ -724,44 +726,59 @@ UnbindFakeBlackHelper(gl::GLContext* gl,
changedActiveTex = true;
gl->fBindTexture(target.get(), tex->mGLName);
}
return changedActiveTex;
}
-void
-WebGLContext::BindFakeBlackTextures()
+bool
+WebGLContext::BindFakeBlackTextures(const char* funcName)
{
if (mCanSkipFakeBlack)
- return;
+ return true;
if (!mFakeBlack_2D_Opaque) {
typedef FakeBlackTexture T;
mFakeBlack_2D_Opaque = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_2D, LOCAL_GL_RGB);
mFakeBlack_2D_Alpha = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_2D, LOCAL_GL_RGBA);
mFakeBlack_CubeMap_Opaque = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_CUBE_MAP,
LOCAL_GL_RGB);
mFakeBlack_CubeMap_Alpha = MakeUnique<T>(gl, LOCAL_GL_TEXTURE_CUBE_MAP,
LOCAL_GL_RGBA);
}
- bool wasNeeded = false;
+ bool wasEverNeeded = false;
+ bool wasNeeded;
+
+ if (!BindFakeBlackHelper(funcName, gl, LOCAL_GL_TEXTURE_2D, mBound2DTextures,
+ mFakeBlack_2D_Opaque.get(), mFakeBlack_2D_Alpha.get(),
+ &wasNeeded))
+ {
+ goto FAIL;
+ }
+ wasEverNeeded |= wasNeeded;
- wasNeeded |= BindFakeBlackHelper(gl, LOCAL_GL_TEXTURE_2D, mBound2DTextures,
- mFakeBlack_2D_Opaque.get(),
- mFakeBlack_2D_Alpha.get());
- wasNeeded |= BindFakeBlackHelper(gl, LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures,
- mFakeBlack_CubeMap_Opaque.get(),
- mFakeBlack_CubeMap_Alpha.get());
+ if (!BindFakeBlackHelper(funcName, gl, LOCAL_GL_TEXTURE_CUBE_MAP,
+ mBoundCubeMapTextures, mFakeBlack_CubeMap_Opaque.get(),
+ mFakeBlack_CubeMap_Alpha.get(), &wasNeeded))
+ {
+ goto FAIL;
+ }
+ wasEverNeeded |= wasNeeded;
- mCanSkipFakeBlack = !wasNeeded;
+ mCanSkipFakeBlack = !wasEverNeeded;
+ return true;
+
+FAIL:
+ ErrorOutOfMemory("%s: Failed to bind fake-black textures.");
+ return false;
}
void
WebGLContext::UnbindFakeBlackTextures()
{
if (mCanSkipFakeBlack)
return;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -681,16 +681,30 @@ WebGLContext::GetBufferParameter(GLenum
default:
ErrorInvalidEnumInfo("getBufferParameter: parameter", pname);
}
return JS::NullValue();
}
+static JS::Value
+MissingAttachmentCausesInvalidOp(WebGLContext* webgl)
+{
+ webgl->ErrorInvalidOperation("getFramebufferAttachmentParameter: Valid pname, but"
+ " missing attachment.");
+ return JS::NullValue();
+}
+
+static JS::Value
+JSUint32Value(uint32_t val)
+{
+ return JS::NumberValue(val);
+}
+
JS::Value
WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
GLenum target,
GLenum attachment,
GLenum pname,
ErrorResult& rv)
{
if (IsContextLost())
@@ -710,16 +724,17 @@ WebGLContext::GetFramebufferAttachmentPa
fb = mBoundReadFramebuffer;
break;
default:
MOZ_CRASH("Bad target.");
}
if (!fb) {
+ // This isn't actually true. GLES 3.0.4, p240: "If the default framebuffer[...]".
ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query"
" framebuffer 0.");
return JS::NullValue();
}
if (!ValidateFramebufferAttachment(fb, attachment,
"getFramebufferAttachmentParameter"))
{
@@ -732,176 +747,131 @@ WebGLContext::GetFramebufferAttachmentPa
{
fb->EnsureColorAttachPoints(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
}
MakeContextCurrent();
const WebGLFBAttachPoint& fba = fb->GetAttachPoint(attachment);
- if (fba.Renderbuffer()) {
- switch (pname) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
- if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
- const GLenum internalFormat = fba.Renderbuffer()->InternalFormat();
- return (internalFormat == LOCAL_GL_SRGB_EXT ||
- internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
- internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT) ?
- JS::NumberValue(uint32_t(LOCAL_GL_SRGB_EXT)) :
- JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
- }
- break;
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER));
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
- if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
- !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
- {
- break;
- }
-
- if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
- " type of a depth-stencil attachment.");
- return JS::NullValue();
- }
-
- if (!fba.IsComplete())
- return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
-
- uint32_t ret = LOCAL_GL_NONE;
- switch (fba.Renderbuffer()->InternalFormat()) {
- case LOCAL_GL_RGBA4:
- case LOCAL_GL_RGB5_A1:
- case LOCAL_GL_RGB565:
- case LOCAL_GL_SRGB8_ALPHA8:
- ret = LOCAL_GL_UNSIGNED_NORMALIZED;
- break;
- case LOCAL_GL_RGB16F:
- case LOCAL_GL_RGBA16F:
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_RGBA32F:
- ret = LOCAL_GL_FLOAT;
- break;
- case LOCAL_GL_DEPTH_COMPONENT16:
- case LOCAL_GL_STENCIL_INDEX8:
- ret = LOCAL_GL_UNSIGNED_INT;
- break;
- default:
- MOZ_ASSERT(false, "Unhandled RB component type.");
- break;
- }
- return JS::NumberValue(uint32_t(ret));
- }
- }
-
- ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
+ switch (pname) {
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ if (fba.Renderbuffer())
+ return JSUint32Value(LOCAL_GL_RENDERBUFFER);
+
+ if (fba.Texture())
+ return JSUint32Value(LOCAL_GL_TEXTURE);
+
+ return JSUint32Value(LOCAL_GL_NONE);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ if (fba.Renderbuffer())
+ return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
+
+ if (fba.Texture())
+ return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
+
return JS::NullValue();
- } else if (fba.Texture()) {
- switch (pname) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
- if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
- const TexInternalFormat effectiveInternalFormat =
- fba.Texture()->BaseImageInfo().mFormat;
-
- if (effectiveInternalFormat == LOCAL_GL_NONE) {
- ErrorInvalidOperation("getFramebufferAttachmentParameter: "
- "texture contains no data");
- return JS::NullValue();
- }
-
- TexInternalFormat unsizedinternalformat = LOCAL_GL_NONE;
- TexType type = LOCAL_GL_NONE;
- UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(
- effectiveInternalFormat, &unsizedinternalformat, &type);
- MOZ_ASSERT(unsizedinternalformat != LOCAL_GL_NONE);
- const bool srgb = unsizedinternalformat == LOCAL_GL_SRGB ||
- unsizedinternalformat == LOCAL_GL_SRGB_ALPHA;
- return srgb ? JS::NumberValue(uint32_t(LOCAL_GL_SRGB))
- : JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
- }
- break;
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
- return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
- return JS::Int32Value(fba.MipLevel());
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
- GLenum face = fba.ImageTarget().get();
- if (face == LOCAL_GL_TEXTURE_2D)
- face = 0;
- return JS::Int32Value(face);
- }
-
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
- if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
- !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
- {
- break;
- }
-
- if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
- ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
- " type of depth-stencil attachments.");
- return JS::NullValue();
- }
-
- if (!fba.IsComplete())
- return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
-
- TexInternalFormat effectiveInternalFormat =
- fba.Texture()->ImageInfoAt(fba.ImageTarget(), fba.MipLevel()).mFormat;
- TexType type = TypeFromInternalFormat(effectiveInternalFormat);
- GLenum ret = LOCAL_GL_NONE;
- switch (type.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:
- ret = LOCAL_GL_UNSIGNED_NORMALIZED;
- break;
- case LOCAL_GL_FLOAT:
- case LOCAL_GL_HALF_FLOAT:
- ret = LOCAL_GL_FLOAT;
- break;
- case LOCAL_GL_UNSIGNED_SHORT:
- case LOCAL_GL_UNSIGNED_INT:
- ret = LOCAL_GL_UNSIGNED_INT;
- break;
- default:
- MOZ_ASSERT(false, "Unhandled RB component type.");
- break;
- }
- return JS::NumberValue(uint32_t(ret));
- }
+ }
+
+
+ const bool hasAttachments = (fba.Renderbuffer() || fba.Texture());
+
+ switch (pname) {
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
+ if (!hasAttachments)
+ return MissingAttachmentCausesInvalidOp(this);
+
+ if (!IsWebGL2() && !IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
+ break;
+
+ if (!fba.IsDefined())
+ return JSUint32Value(LOCAL_GL_LINEAR);
+
+ if (fba.IsDefined()) {
+ if (fba.Format()->format->isSRGB)
+ return JSUint32Value(LOCAL_GL_SRGB_EXT);
+ }
+
+ return JSUint32Value(LOCAL_GL_LINEAR);
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
+ if (!hasAttachments)
+ return MissingAttachmentCausesInvalidOp(this);
+
+ if (!IsWebGL2() &&
+ !IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
+ !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
+ {
+ break;
+ }
+
+ if (!fba.IsDefined())
+ return JSUint32Value(LOCAL_GL_LINEAR);
+
+ if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+ ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
+ " type of a depth-stencil attachment.");
+ return JS::NullValue();
}
- ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
- return JS::NullValue();
- } else {
- switch (pname) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
- return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
-
- default:
- ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
- return JS::NullValue();
+ switch (fba.Format()->format->componentType) {
+ case webgl::ComponentType::Int:
+ return JSUint32Value(LOCAL_GL_INT);
+
+ case webgl::ComponentType::UInt:
+ return JSUint32Value(LOCAL_GL_UNSIGNED_INT);
+
+ case webgl::ComponentType::NormInt:
+ return JSUint32Value(LOCAL_GL_SIGNED_NORMALIZED);
+
+ case webgl::ComponentType::NormUInt:
+ return JSUint32Value(LOCAL_GL_UNSIGNED_NORMALIZED);
+
+ case webgl::ComponentType::Float:
+ return JSUint32Value(LOCAL_GL_FLOAT);
+
+ case webgl::ComponentType::None:
+ return JSUint32Value(LOCAL_GL_NONE);
}
+ // Exhaustive switch means nothing's left.
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ if (!hasAttachments)
+ return MissingAttachmentCausesInvalidOp(this);
+
+ if (!fba.Texture())
+ break;
+
+ return JSUint32Value(fba.MipLevel());
+
+ case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ if (!hasAttachments)
+ return MissingAttachmentCausesInvalidOp(this);
+
+ if (!fba.Texture())
+ break;
+
+ switch (fba.ImageTarget().get()) {
+ case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ return JSUint32Value(fba.ImageTarget().get());
+ }
+
+ return JSUint32Value(0);
+
+ default:
+ break;
}
+ ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
return JS::NullValue();
}
JS::Value
WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
{
if (IsContextLost())
return JS::NullValue();
@@ -929,17 +899,17 @@ WebGLContext::GetRenderbufferParameter(G
case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
{
// RB emulation means we have to ask the RB itself.
GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
return JS::Int32Value(i);
}
case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
{
- return JS::NumberValue(mBoundRenderbuffer->InternalFormat());
+ return JS::NumberValue(mBoundRenderbuffer->GetInternalFormat());
}
default:
ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname);
}
return JS::NullValue();
}
@@ -1182,147 +1152,248 @@ WebGLContext::LinkProgram(WebGLProgram*
}
void
WebGLContext::PixelStorei(GLenum pname, GLint param)
{
if (IsContextLost())
return;
- switch (pname) {
- case UNPACK_FLIP_Y_WEBGL:
- mPixelStoreFlipY = (param != 0);
+ if (IsWebGL2()) {
+ uint32_t* pValueSlot = nullptr;
+ switch (pname) {
+ case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
+ pValueSlot = &mPixelStore_UnpackImageHeight;
break;
- case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
- mPixelStorePremultiplyAlpha = (param != 0);
+
+ case LOCAL_GL_UNPACK_SKIP_IMAGES:
+ pValueSlot = &mPixelStore_UnpackSkipImages;
+ break;
+
+ case LOCAL_GL_UNPACK_ROW_LENGTH:
+ pValueSlot = &mPixelStore_UnpackRowLength;
+ break;
+
+ case LOCAL_GL_UNPACK_SKIP_ROWS:
+ pValueSlot = &mPixelStore_UnpackSkipRows;
break;
- case UNPACK_COLORSPACE_CONVERSION_WEBGL:
- if (param == LOCAL_GL_NONE || param == BROWSER_DEFAULT_WEBGL)
- mPixelStoreColorspaceConversion = param;
- else
- return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param);
+
+ case LOCAL_GL_UNPACK_SKIP_PIXELS:
+ pValueSlot = &mPixelStore_UnpackSkipPixels;
+ break;
+
+ case LOCAL_GL_PACK_ROW_LENGTH:
+ pValueSlot = &mPixelStore_PackRowLength;
+ break;
+
+ case LOCAL_GL_PACK_SKIP_ROWS:
+ pValueSlot = &mPixelStore_PackSkipRows;
break;
- case LOCAL_GL_PACK_ALIGNMENT:
- case LOCAL_GL_UNPACK_ALIGNMENT:
- if (param != 1 &&
- param != 2 &&
- param != 4 &&
- param != 8)
- return ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
- if (pname == LOCAL_GL_PACK_ALIGNMENT)
- mPixelStorePackAlignment = param;
- else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
- mPixelStoreUnpackAlignment = param;
+
+ case LOCAL_GL_PACK_SKIP_PIXELS:
+ pValueSlot = &mPixelStore_PackSkipPixels;
+ break;
+ }
+
+ if (pValueSlot) {
+ if (param < 0) {
+ ErrorInvalidValue("pixelStorei: param must be >= 0.");
+ return;
+ }
+
MakeContextCurrent();
gl->fPixelStorei(pname, param);
- break;
+ *pValueSlot = param;
+ return;
+ }
+ }
+
+ switch (pname) {
+ case UNPACK_FLIP_Y_WEBGL:
+ mPixelStore_FlipY = bool(param);
+ return;
+
+ case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+ mPixelStore_PremultiplyAlpha = bool(param);
+ return;
+
+ case UNPACK_COLORSPACE_CONVERSION_WEBGL:
+ switch (param) {
+ case LOCAL_GL_NONE:
+ case BROWSER_DEFAULT_WEBGL:
+ mPixelStore_ColorspaceConversion = param;
+ return;
+
default:
- return ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
+ ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter",
+ param);
+ return;
+ }
+
+ case LOCAL_GL_PACK_ALIGNMENT:
+ case LOCAL_GL_UNPACK_ALIGNMENT:
+ switch (param) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ if (pname == LOCAL_GL_PACK_ALIGNMENT)
+ mPixelStore_PackAlignment = param;
+ else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
+ mPixelStore_UnpackAlignment = param;
+
+ MakeContextCurrent();
+ gl->fPixelStorei(pname, param);
+ return;
+
+ default:
+ ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
+ return;
+ }
+
+
+
+ default:
+ break;
}
+
+ ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
}
// `width` in pixels.
// `stride` in bytes.
-static bool
-SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
- size_t height, size_t stride)
+static void
+SetFullAlpha(void* data, GLenum format, GLenum type, size_t width, size_t height,
+ size_t stride)
{
if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
// Just memset the rows.
uint8_t* row = static_cast<uint8_t*>(data);
for (size_t j = 0; j < height; ++j) {
memset(row, 0xff, width);
row += stride;
}
- return true;
+ return;
}
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
for (size_t j = 0; j < height; ++j) {
uint8_t* row = static_cast<uint8_t*>(data) + j*stride;
uint8_t* pAlpha = row + 3;
uint8_t* pAlphaEnd = pAlpha + 4*width;
while (pAlpha != pAlphaEnd) {
*pAlpha = 0xff;
pAlpha += 4;
}
}
- return true;
+ return;
}
if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
for (size_t j = 0; j < height; ++j) {
uint8_t* rowBytes = static_cast<uint8_t*>(data) + j*stride;
float* row = reinterpret_cast<float*>(rowBytes);
float* pAlpha = row + 3;
float* pAlphaEnd = pAlpha + 4*width;
while (pAlpha != pAlphaEnd) {
*pAlpha = 1.0f;
pAlpha += 4;
}
}
- return true;
- }
-
- MOZ_ASSERT(false, "Unhandled case, how'd we get here?");
- return false;
-}
-
-static void
-ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment,
- GLenum destFormat, GLenum destType, void* destBytes)
-{
- if (readFormat == destFormat && readType == destType) {
- gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
return;
}
- if (readFormat == LOCAL_GL_RGBA &&
- readType == LOCAL_GL_HALF_FLOAT &&
- destFormat == LOCAL_GL_RGBA &&
- destType == LOCAL_GL_FLOAT)
+ MOZ_CRASH("Unhandled case, how'd we get here?");
+}
+
+bool
+WebGLContext::DoReadPixelsAndConvert(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum destFormat, GLenum destType, void* destBytes,
+ GLenum auxReadFormat, GLenum auxReadType)
+{
+ GLenum readFormat = destFormat;
+ GLenum readType = destType;
+
+ if (gl->WorkAroundDriverBugs() &&
+ gl->IsANGLE() &&
+ readType == LOCAL_GL_FLOAT &&
+ auxReadFormat == destFormat &&
+ auxReadType == LOCAL_GL_HALF_FLOAT)
{
- size_t readBytesPerPixel = sizeof(uint16_t) * 4;
- size_t destBytesPerPixel = sizeof(float) * 4;
-
- size_t readBytesPerRow = readBytesPerPixel * width;
-
- size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment);
- size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width,
- pixelStorePackAlignment);
-
- size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow;
- UniquePtr<uint8_t[]> readBuffer(new uint8_t[bytesNeeded]);
+ readType = auxReadType;
+
+ const auto readBytesPerPixel = webgl::BytesPerPixel({readFormat, readType});
+ const auto destBytesPerPixel = webgl::BytesPerPixel({destFormat, destType});
+
+ CheckedUint32 readOffset;
+ CheckedUint32 readStride;
+ const CheckedUint32 readSize = GetPackSize(width, height, readBytesPerPixel,
+ &readOffset, &readStride);
+
+ CheckedUint32 destOffset;
+ CheckedUint32 destStride;
+ const CheckedUint32 destSize = GetPackSize(width, height, destBytesPerPixel,
+ &destOffset, &destStride);
+ if (!readSize.isValid() || !destSize.isValid()) {
+ ErrorOutOfMemory("readPixels: Overflow calculating sizes for conversion.");
+ return false;
+ }
+
+ UniqueBuffer readBuffer(malloc(readSize.value()));
+ if (!readBuffer) {
+ ErrorOutOfMemory("readPixels: Failed to alloc temp buffer for conversion.");
+ return false;
+ }
+
+ gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
- size_t channelsPerRow = width * 4;
+ const GLenum error = errorScope.GetError();
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ ErrorOutOfMemory("readPixels: Driver ran out of memory.");
+ return false;
+ }
+
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "Unexpected driver error.");
+ return false;
+ }
+
+ size_t channelsPerRow = std::min(readStride.value() / sizeof(uint16_t),
+ destStride.value() / sizeof(float));
+
+ const uint8_t* srcRow = (uint8_t*)(readBuffer.get()) + readOffset.value();
+ uint8_t* dstRow = (uint8_t*)(destBytes) + destOffset.value();
+
for (size_t j = 0; j < (size_t)height; j++) {
- uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride;
- float* dst = (float*)(destBytes) + j*destStride;
-
- uint16_t* srcEnd = src + channelsPerRow;
+ auto src = (const uint16_t*)srcRow;
+ auto dst = (float*)dstRow;
+
+ const auto srcEnd = src + channelsPerRow;
while (src != srcEnd) {
*dst = unpackFromFloat16(*src);
-
++src;
++dst;
}
+
+ srcRow += readStride.value();
+ dstRow += destStride.value();
}
- return;
+ return true;
}
- MOZ_CRASH("bad format/type");
+ gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
+ return true;
}
static bool
IsFormatAndTypeUnpackable(GLenum format, GLenum type)
{
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
case LOCAL_GL_FLOAT:
@@ -1344,53 +1415,86 @@ IsFormatAndTypeUnpackable(GLenum format,
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
return format == LOCAL_GL_RGB;
default:
return false;
}
}
+CheckedUint32
+WebGLContext::GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
+ CheckedUint32* const out_startOffset,
+ CheckedUint32* const out_rowStride)
+{
+ if (!width || !height) {
+ *out_startOffset = 0;
+ *out_rowStride = 0;
+ return 0;
+ }
+
+ const CheckedUint32 pixelsPerRow = (mPixelStore_PackRowLength ? mPixelStore_PackRowLength
+ : width);
+ const CheckedUint32 skipPixels = mPixelStore_PackSkipPixels;
+ const CheckedUint32 skipRows = mPixelStore_PackSkipRows;
+ const CheckedUint32 alignment = mPixelStore_PackAlignment;
+
+ // GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
+ const auto totalBytesPerRow = bytesPerPixel * pixelsPerRow;
+ const auto rowStride = RoundUpToMultipleOf(totalBytesPerRow, alignment);
+
+ const auto startOffset = rowStride * skipRows + bytesPerPixel * skipPixels;
+ const auto usedBytesPerRow = bytesPerPixel * width;
+
+ const auto bytesNeeded = startOffset + rowStride * (height - 1) + usedBytesPerRow;
+
+ *out_startOffset = startOffset;
+ *out_rowStride = rowStride;
+ return bytesNeeded;
+}
+
// This function is temporary, and will be removed once https://bugzilla.mozilla.org/show_bug.cgi?id=1176214 lands, which will
// collapse the SharedArrayBufferView and ArrayBufferView into one.
void
ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
void** const out_data, size_t* const out_length,
js::Scalar::Type* const out_type)
{
if (view.IsArrayBufferView()) {
- const dom::ArrayBufferView& pixbuf = view.GetAsArrayBufferView();
- pixbuf.ComputeLengthAndData();
- *out_length = pixbuf.Length();
- *out_data = pixbuf.Data();
- *out_type = JS_GetArrayBufferViewType(pixbuf.Obj());
+ const auto& view2 = view.GetAsArrayBufferView();
+ view2.ComputeLengthAndData();
+
+ *out_length = view2.Length();
+ *out_data = view2.Data();
+ *out_type = JS_GetArrayBufferViewType(view2.Obj());
} else {
- const dom::SharedArrayBufferView& pixbuf = view.GetAsSharedArrayBufferView();
- pixbuf.ComputeLengthAndData();
- *out_length = pixbuf.Length();
- *out_data = pixbuf.Data();
- *out_type = JS_GetSharedArrayBufferViewType(pixbuf.Obj());
+ const auto& view2 = view.GetAsSharedArrayBufferView();
+ view2.ComputeLengthAndData();
+ *out_length = view2.Length();
+ *out_data = view2.Data();
+ *out_type = JS_GetSharedArrayBufferViewType(view2.Obj());
}
}
void
-WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
- GLsizei height, GLenum format,
- GLenum type, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
- ErrorResult& rv)
+WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+ GLenum type,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& pixels,
+ ErrorResult& out_error)
{
if (IsContextLost())
return;
if (mCanvasElement &&
mCanvasElement->IsWriteOnly() &&
!nsContentUtils::IsCallerChrome())
{
GenerateWarning("readPixels: Not allowed");
- return rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ out_error.Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
}
if (width < 0 || height < 0)
return ErrorInvalidValue("readPixels: negative size passed");
if (pixels.IsNull())
return ErrorInvalidValue("readPixels: null destination buffer");
@@ -1441,59 +1545,59 @@ WebGLContext::ReadPixels(GLint x, GLint
bytesPerPixel = 2*channels;
requiredDataType = js::Scalar::Uint16;
break;
default:
MOZ_CRASH("bad `type`");
}
- const dom::ArrayBufferViewOrSharedArrayBufferView &view = pixels.Value();
+ const auto& view = pixels.Value();
// Compute length and data. Don't reenter after this point, lest the
// precomputed go out of sync with the instant length/data.
- size_t dataByteLen;
void* data;
+ size_t bytesAvailable;
js::Scalar::Type dataType;
- ComputeLengthAndData(view, &data, &dataByteLen, &dataType);
+ ComputeLengthAndData(view, &data, &bytesAvailable, &dataType);
// Check the pixels param type
if (dataType != requiredDataType)
return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
- // Check the pixels param size
- CheckedUint32 checked_neededByteLength =
- GetImageSize(height, width, 1, bytesPerPixel, mPixelStorePackAlignment);
-
- CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
-
- CheckedUint32 checked_alignedRowSize =
- RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
-
- if (checked_neededByteLength.value() > dataByteLen)
- return ErrorInvalidOperation("readPixels: buffer too small");
+ CheckedUint32 startOffset;
+ CheckedUint32 rowStride;
+ const auto bytesNeeded = GetPackSize(width, height, bytesPerPixel, &startOffset,
+ &rowStride);
+ if (!bytesNeeded.isValid()) {
+ ErrorInvalidOperation("readPixels: Integer overflow computing the needed buffer"
+ " size.");
+ return;
+ }
+
+ if (bytesNeeded.value() > bytesAvailable) {
+ ErrorInvalidOperation("readPixels: buffer too small");
+ return;
+ }
if (!data) {
ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
- return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+ out_error.Throw(NS_ERROR_OUT_OF_MEMORY);
+ return;
}
MakeContextCurrent();
- TexInternalFormat srcFormat;
+ const webgl::FormatUsageInfo* srcFormat;
uint32_t srcWidth;
uint32_t srcHeight;
if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
return;
- const TexType srcType = TypeFromInternalFormat(srcFormat);
- const bool isSrcTypeFloat = (srcType == LOCAL_GL_FLOAT ||
- srcType == LOCAL_GL_HALF_FLOAT);
+ auto srcType = srcFormat->format->componentType;
+ const bool isSrcTypeFloat = (srcType == webgl::ComponentType::Float);
// Check the format and type params to assure they are an acceptable pair (as per spec)
const GLenum mainReadFormat = LOCAL_GL_RGBA;
const GLenum mainReadType = isSrcTypeFloat ? LOCAL_GL_FLOAT
: LOCAL_GL_UNSIGNED_BYTE;
GLenum auxReadFormat = mainReadFormat;
@@ -1509,103 +1613,99 @@ WebGLContext::ReadPixels(GLint x, GLint
}
const bool mainMatches = (format == mainReadFormat && type == mainReadType);
const bool auxMatches = (format == auxReadFormat && type == auxReadType);
const bool isValid = mainMatches || auxMatches;
if (!isValid)
return ErrorInvalidOperation("readPixels: Invalid format/type pair");
- GLenum readType = type;
- if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
- if (type == LOCAL_GL_FLOAT &&
- auxReadFormat == format &&
- auxReadType == LOCAL_GL_HALF_FLOAT)
- {
- readType = auxReadType;
- }
+ // Now that the errors are out of the way, on to actually reading!
+
+ uint32_t readX, readY;
+ uint32_t writeX, writeY;
+ uint32_t rwWidth, rwHeight;
+ Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+ Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
+
+ if (rwWidth == width && rwHeight == height) {
+ DoReadPixelsAndConvert(x, y, width, height, format, type, data, auxReadFormat,
+ auxReadType);
+ return;
}
- // Now that the errors are out of the way, on to actually reading
-
- // If we won't be reading any pixels anyways, just skip the actual reading
- if (width == 0 || height == 0)
- return DummyFramebufferOperation("readPixels");
-
- if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, srcWidth, srcHeight)) {
- // the easy case: we're not reading out-of-range pixels
-
- // Effectively: gl->fReadPixels(x, y, width, height, format, type, dest);
- ReadPixelsAndConvert(gl, x, y, width, height, format, readType,
- mPixelStorePackAlignment, format, type, data);
- } else {
- // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
- // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
- // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
- // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
- // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
- // to accomodate the potentially different strides (widths).
-
- // Zero the whole pixel dest area in the destination buffer.
- memset(data, 0, checked_neededByteLength.value());
-
- if ( x >= int32_t(srcWidth)
- || x+width <= 0
- || y >= int32_t(srcHeight)
- || y+height <= 0)
- {
- // we are completely outside of range, can exit now with buffer filled with zeros
- return DummyFramebufferOperation("readPixels");
+ // Read request contains out-of-bounds pixels. Unfortunately:
+ // GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer":
+ // "If any of these pixels lies outside of the window allocated to the current GL
+ // context, or outside of the image attached to the currently bound framebuffer
+ // object, then the values obtained for those pixels are undefined."
+
+ // This is a slow-path, so warn people away!
+ GenerateWarning("readPixels: Out-of-bounds reads with readPixels are deprecated, and"
+ " may be slow.");
+
+ // Currently, the spec dictates that we need to zero the out-of-bounds pixels.
+
+ // Ideally we could just ReadPixels into the buffer, then zero the undefined parts.
+ // However, we can't do this for *shared* ArrayBuffers, as they can have racey
+ // accesses from Workers.
+
+ // We can use a couple tricks to do this faster, but we shouldn't encourage this
+ // anyway. Why not just do it the really safe, dead-simple way, even if it is
+ // hilariously slow?
+
+ ////////////////////////////////////
+ // Clear the targetted pixels to zero.
+
+ if (mPixelStore_PackRowLength ||
+ mPixelStore_PackSkipPixels ||
+ mPixelStore_PackSkipRows)
+ {
+ // Targetted bytes might not be contiguous, so do it row-by-row.
+ uint8_t* row = (uint8_t*)data + startOffset.value();
+ const auto bytesPerRow = bytesPerPixel * width;
+ for (uint32_t j = 0; j < uint32_t(height); j++) {
+ std::memset(row, 0, bytesPerRow);
+ row += rowStride.value();
}
-
- // compute the parameters of the subrect we're actually going to call glReadPixels on
- GLint subrect_x = std::max(x, 0);
- GLint subrect_end_x = std::min(x+width, int32_t(srcWidth));
- GLsizei subrect_width = subrect_end_x - subrect_x;
-
- GLint subrect_y = std::max(y, 0);
- GLint subrect_end_y = std::min(y+height, int32_t(srcHeight));
- GLsizei subrect_height = subrect_end_y - subrect_y;
-
- if (subrect_width < 0 || subrect_height < 0 ||
- subrect_width > width || subrect_height > height)
- {
- return ErrorInvalidOperation("readPixels: integer overflow computing clipped rect size");
+ } else {
+ std::memset(data, 0, bytesNeeded.value());
+ }
+
+ ////////////////////////////////////
+ // Read only the in-bounds pixels.
+
+ if (!rwWidth || !rwHeight) {
+ // There aren't any, so we're 'done'.
+ DummyFramebufferOperation("readPixels");
+ return;
+ }
+
+ if (IsWebGL2()) {
+ if (!mPixelStore_PackRowLength) {
+ gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, width);
}
-
- // now we know that subrect_width is in the [0..width] interval, and same for heights.
-
- // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
- // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
- uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel;
- // There are checks above to ensure that this doesn't overflow.
- uint32_t subrect_alignedRowSize =
- RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
- uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
-
- // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
- auto subrect_data = MakeUniqueFallible<GLubyte[]>(subrect_byteLength);
- if (!subrect_data)
- return ErrorOutOfMemory("readPixels: subrect_data");
-
- // Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
- // subrect_height, format, type, subrect_data.get());
- ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height,
- format, readType, mPixelStorePackAlignment, format, type,
- subrect_data.get());
-
- // notice that this for loop terminates because we already checked that subrect_height is at most height
- for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
- GLint subrect_x_in_dest_buffer = subrect_x - x;
- GLint subrect_y_in_dest_buffer = subrect_y - y;
- memcpy(static_cast<GLubyte*>(data)
- + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
- + bytesPerPixel * subrect_x_in_dest_buffer, // destination
- subrect_data.get() + subrect_alignedRowSize * y_inside_subrect, // source
- subrect_plainRowSize); // size
+ gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels + writeX);
+ gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows + writeY);
+
+ DoReadPixelsAndConvert(readX, readY, rwWidth, rwHeight, format, type, data,
+ auxReadFormat, auxReadType);
+
+ gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength);
+ gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels);
+ gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows);
+ } else {
+ // I *did* say "hilariously slow".
+
+ uint8_t* row = (uint8_t*)data + startOffset.value() + writeX * bytesPerPixel;
+ row += writeY * rowStride.value();
+ for (uint32_t j = 0; j < rwHeight; j++) {
+ DoReadPixelsAndConvert(readX, readY+j, rwWidth, 1, format, type, row,
+ auxReadFormat, auxReadType);
+ row += rowStride.value();
}
}
// if we're reading alpha, we may need to do fixup. Note that we don't allow
// GL_ALPHA to readpixels currently, but we had the code written for it already.
const bool formatHasAlpha = format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA;
if (!formatHasAlpha)
@@ -1616,20 +1716,17 @@ WebGLContext::ReadPixels(GLint x, GLint
needAlphaFilled = !mBoundReadFramebuffer->ColorAttachment(0).HasAlpha();
} else {
needAlphaFilled = !mOptions.alpha;
}
if (!needAlphaFilled)
return;
- size_t stride = checked_alignedRowSize.value(); // In bytes!
- if (!SetFullAlpha(data, format, type, width, height, stride)) {
- return rv.Throw(NS_ERROR_FAILURE);
- }
+ SetFullAlpha(data, format, type, width, height, rowStride.value());
}
void
WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
{
@@ -1651,101 +1748,42 @@ WebGLContext::RenderbufferStorage_base(c
return;
}
if (width < 0 || height < 0) {
ErrorInvalidValue("%s: Width and height must be >= 0.", funcName);
return;
}
- if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize) {
+ if (uint32_t(width) > mImplMaxRenderbufferSize ||
+ uint32_t(height) > mImplMaxRenderbufferSize)
+ {
ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
" size.", funcName);
return;
}
- // Convert DEPTH_STENCIL to sized type for testing
- GLenum sizedInternalFormat = internalFormat;
- if (sizedInternalFormat == LOCAL_GL_DEPTH_STENCIL)
- sizedInternalFormat = LOCAL_GL_DEPTH24_STENCIL8;
-
- bool isFormatValid = false;
- const webgl::FormatInfo* info = webgl::GetInfoBySizedFormat(sizedInternalFormat);
- if (info) {
- const webgl::FormatUsageInfo* usage = mFormatUsage->GetUsage(info);
- isFormatValid = usage && usage->asRenderbuffer;
- }
-
- if (!isFormatValid) {
+ const auto usage = mFormatUsage->GetRBUsage(internalFormat);
+ if (!usage) {
ErrorInvalidEnumInfo("`internalFormat`", funcName, internalFormat);
return;
}
- // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
- GLenum internalFormatForGL = internalFormat;
-
- switch (internalFormat) {
- case LOCAL_GL_RGBA4:
- case LOCAL_GL_RGB5_A1:
- // 16-bit RGBA formats are not supported on desktop GL
- if (!gl->IsGLES())
- internalFormatForGL = LOCAL_GL_RGBA8;
- break;
-
- case LOCAL_GL_RGB565:
- // the RGB565 format is not supported on desktop GL
- if (!gl->IsGLES())
- internalFormatForGL = LOCAL_GL_RGB8;
- break;
-
- case LOCAL_GL_DEPTH_COMPONENT16:
- if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
- internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
- else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
- internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
- break;
-
- case LOCAL_GL_DEPTH_STENCIL:
- // We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
- internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
- break;
-
- default:
- break;
- }
-
// Validation complete.
MakeContextCurrent();
- bool willRealloc = samples != mBoundRenderbuffer->Samples() ||
- internalFormat != mBoundRenderbuffer->InternalFormat() ||
- width != mBoundRenderbuffer->Width() ||
- height != mBoundRenderbuffer->Height();
-
- if (willRealloc) {
- GetAndFlushUnderlyingGLErrors();
- mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
- width, height);
- GLenum error = GetAndFlushUnderlyingGLErrors();
- if (error) {
- GenerateWarning("%s generated error %s", funcName,
- ErrorName(error));
- return;
- }
- } else {
- mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
- width, height);
+ GetAndFlushUnderlyingGLErrors();
+ mBoundRenderbuffer->RenderbufferStorage(samples, usage, width, height);
+ GLenum error = GetAndFlushUnderlyingGLErrors();
+ if (error) {
+ GenerateWarning("%s generated error %s", funcName,
+ ErrorName(error));
+ return;
}
-
- mBoundRenderbuffer->SetSamples(samples);
- mBoundRenderbuffer->SetInternalFormat(internalFormat);
- mBoundRenderbuffer->SetInternalFormatForGL(internalFormatForGL);
- mBoundRenderbuffer->setDimensions(width, height);
- mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
}
void
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
{
RenderbufferStorage_base("renderbufferStorage", target, 0,
internalFormat, width, height);
}
@@ -1839,24 +1877,25 @@ WebGLContext::StencilOpSeparate(GLenum f
!ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
return;
MakeContextCurrent();
gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
}
nsresult
-WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
- RefPtr<DataSourceSurface>& imageOut,
- WebGLTexelFormat* format)
+WebGLContext::SurfaceFromElementResultToImageSurface(const nsLayoutUtils::SurfaceFromElementResult& res,
+ RefPtr<DataSourceSurface>* const out_image,
+ WebGLTexelFormat* const out_format)
{
- *format = WebGLTexelFormat::None;
+ *out_format = WebGLTexelFormat::None;
if (!res.mSourceSurface)
return NS_OK;
+
RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
if (!data) {
// SurfaceFromElement lied!
return NS_OK;
}
// We disallow loading cross-domain images and videos that have not been validated
// with CORS as WebGL textures. The reason for doing that is that timing
@@ -1890,34 +1929,33 @@ WebGLContext::SurfaceFromElementResultTo
}
// End of security checks, now we should be safe regarding cross-domain images
// Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
// texture sources in the first place.
switch (data->GetFormat()) {
case SurfaceFormat::B8G8R8A8:
- *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
+ *out_format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
break;
case SurfaceFormat::B8G8R8X8:
- *format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
+ *out_format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
break;
case SurfaceFormat::A8:
- *format = WebGLTexelFormat::A8;
+ *out_format = WebGLTexelFormat::A8;
break;
case SurfaceFormat::R5G6B5_UINT16:
- *format = WebGLTexelFormat::RGB565;
+ *out_format = WebGLTexelFormat::RGB565;
break;
default:
NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
return NS_ERROR_NOT_IMPLEMENTED;
}
- imageOut = data;
-
+ *out_image = data;
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// Uniform setters.
void
WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -375,23 +375,23 @@ WebGLContext::GetParameter(JSContext* cx
case LOCAL_GL_ALPHA_BITS: {
GLint i = 0;
if (!mNeedsFakeNoAlpha) {
gl->fGetIntegerv(pname, &i);
}
return JS::Int32Value(i);
}
case LOCAL_GL_MAX_TEXTURE_SIZE:
- return JS::Int32Value(mGLMaxTextureSize);
+ return JS::Int32Value(mImplMaxTextureSize);
case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
- return JS::Int32Value(mGLMaxCubeMapTextureSize);
+ return JS::Int32Value(mImplMaxCubeMapTextureSize);
case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
- return JS::Int32Value(mGLMaxRenderbufferSize);
+ return JS::Int32Value(mImplMaxRenderbufferSize);
case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
return JS::Int32Value(mGLMaxVertexUniformVectors);
case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
return JS::Int32Value(mGLMaxFragmentUniformVectors);
case LOCAL_GL_MAX_VARYING_VECTORS:
@@ -444,23 +444,23 @@ WebGLContext::GetParameter(JSContext* cx
case LOCAL_GL_DEPTH_WRITEMASK: {
realGLboolean b = 0;
gl->fGetBooleanv(pname, &b);
return JS::BooleanValue(bool(b));
}
// bool, WebGL-specific
case UNPACK_FLIP_Y_WEBGL:
- return JS::BooleanValue(mPixelStoreFlipY);
+ return JS::BooleanValue(mPixelStore_FlipY);
case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
- return JS::BooleanValue(mPixelStorePremultiplyAlpha);
+ return JS::BooleanValue(mPixelStore_PremultiplyAlpha);
// uint, WebGL-specific
case UNPACK_COLORSPACE_CONVERSION_WEBGL:
- return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion));
+ return JS::NumberValue(uint32_t(mPixelStore_ColorspaceConversion));
////////////////////////////////
// Complex values
// 2 floats
case LOCAL_GL_DEPTH_RANGE:
case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
--- a/dom/canvas/WebGLContextTextures.cpp
+++ b/dom/canvas/WebGLContextTextures.cpp
@@ -47,17 +47,18 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/Endian.h"
namespace mozilla {
static bool
-IsValidTexTarget(WebGLContext* webgl, GLenum rawTexTarget, TexTarget* const out)
+IsValidTexTarget(WebGLContext* webgl, GLenum rawTexTarget,
+ TexTarget* const out)
{
switch (rawTexTarget) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP:
break;
case LOCAL_GL_TEXTURE_3D:
if (!webgl->IsWebGL2())
@@ -69,45 +70,52 @@ IsValidTexTarget(WebGLContext* webgl, GL
return false;
}
*out = rawTexTarget;
return true;
}
static bool
-IsValidTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
+IsValidTexImageTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexImageTarget,
TexImageTarget* const out)
{
+ uint8_t targetDims;
+
switch (rawTexImageTarget) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ targetDims = 2;
break;
case LOCAL_GL_TEXTURE_3D:
if (!webgl->IsWebGL2())
return false;
+ targetDims = 3;
break;
default:
return false;
}
+ if (targetDims != funcDims)
+ return false;
+
*out = rawTexImageTarget;
return true;
}
bool
-ValidateTexTarget(WebGLContext* webgl, GLenum rawTexTarget, const char* funcName,
+ValidateTexTarget(WebGLContext* webgl, const char* funcName, GLenum rawTexTarget,
TexTarget* const out_texTarget, WebGLTexture** const out_tex)
{
if (webgl->IsContextLost())
return false;
TexTarget texTarget;
if (!IsValidTexTarget(webgl, rawTexTarget, &texTarget)) {
webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName);
@@ -121,25 +129,25 @@ ValidateTexTarget(WebGLContext* webgl, G
}
*out_texTarget = texTarget;
*out_tex = tex;
return true;
}
bool
-ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
- const char* funcName, TexImageTarget* const out_texImageTarget,
+ValidateTexImageTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
+ GLenum rawTexImageTarget, TexImageTarget* const out_texImageTarget,
WebGLTexture** const out_tex)
{
if (webgl->IsContextLost())
return false;
TexImageTarget texImageTarget;
- if (!IsValidTexImageTarget(webgl, rawTexImageTarget, &texImageTarget)) {
+ if (!IsValidTexImageTarget(webgl, funcDims, rawTexImageTarget, &texImageTarget)) {
webgl->ErrorInvalidEnum("%s: Invalid texImageTarget.", funcName);
return false;
}
WebGLTexture* tex = webgl->ActiveBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
webgl->ErrorInvalidOperation("%s: No texture is bound to this target.", funcName);
return false;
@@ -214,30 +222,34 @@ WebGLContext::BindTexture(GLenum rawTarg
}
*currentTexPtr = newTex;
}
void
WebGLContext::GenerateMipmap(GLenum rawTexTarget)
{
+ const char funcName[] = "generateMipmap";
+
TexTarget texTarget;
WebGLTexture* tex;
- if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
+ if (!ValidateTexTarget(this, funcName, rawTexTarget, &texTarget, &tex))
return;
tex->GenerateMipmap(texTarget);
}
JS::Value
WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname)
{
+ const char funcName[] = "getTexParameter";
+
TexTarget texTarget;
WebGLTexture* tex;
- if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
+ if (!ValidateTexTarget(this, funcName, rawTexTarget, &texTarget, &tex))
return JS::NullValue();
if (!IsTexParamValid(pname)) {
ErrorInvalidEnumInfo("getTexParameter: pname", pname);
return JS::NullValue();
}
return tex->GetTexParameter(texTarget, pname);
@@ -256,214 +268,274 @@ WebGLContext::IsTexture(WebGLTexture* te
}
void
WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, GLint* maybeIntParam,
GLfloat* maybeFloatParam)
{
MOZ_ASSERT(maybeIntParam || maybeFloatParam);
+ const char funcName[] = "texParameter";
+
TexTarget texTarget;
WebGLTexture* tex;
- if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
+ if (!ValidateTexTarget(this, funcName, rawTexTarget, &texTarget, &tex))
return;
tex->TexParameter(texTarget, pname, maybeIntParam, maybeFloatParam);
}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// Uploads
-//////////////////////////////////////////////////////////////////////////////////////////
+////////////////////
// TexImage
void
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
- GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
- ErrorResult* const out_rv)
-{
- TexImageTarget texImageTarget;
- WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
- &tex))
- {
- return;
- }
-
- tex->TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType, elem,
- out_rv);
-}
-
-void
-WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
GLenum unpackType,
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv)
+ ErrorResult&)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "texImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
- tex->TexImage2D(texImageTarget, level, internalFormat, width, height, border,
- unpackFormat, unpackType, maybeView, &out_rv);
+ const bool isSubImage = false;
+ const GLint xOffset = 0;
+ const GLint yOffset = 0;
+ const GLint zOffset = 0;
+ const GLsizei depth = 1;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, width, height, depth, border, unpackFormat,
+ unpackType, maybeView);
}
void
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
GLenum unpackFormat, GLenum unpackType,
- dom::ImageData* imageData, ErrorResult& out_rv)
+ dom::ImageData* imageData, ErrorResult&)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "texImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texImage2D", &texImageTarget,
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
- tex->TexImage2D(texImageTarget, level, internalFormat, unpackFormat, unpackType,
- imageData, &out_rv);
+ const bool isSubImage = false;
+ const GLint xOffset = 0;
+ const GLint yOffset = 0;
+ const GLint zOffset = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, imageData);
}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// TexSubImage
-
+void
+WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
+ GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
+ ErrorResult* const out_error)
+{
+ const char funcName[] = "texImage2D";
+ const uint8_t funcDims = 2;
-void
-WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLenum unpackFormat, GLenum unpackType,
- dom::Element* elem, ErrorResult* const out_rv)
-{
- TexImageTarget texImageTarget;
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
- tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
- elem, out_rv);
+ const bool isSubImage = false;
+ const GLint xOffset = 0;
+ const GLint yOffset = 0;
+ const GLint zOffset = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, elem, out_error);
}
+////////////////////////////////////////
+// TexSubImage
+
void
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLsizei width, GLsizei height,
GLenum unpackFormat, GLenum unpackType,
const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult& out_rv)
+ ErrorResult&)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "texSubImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ const GLint zOffset = 0;
+ const GLsizei depth = 1;
+ const GLint border = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, width, height, depth, border, unpackFormat,
+ unpackType, maybeView);
+}
+
+void
+WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::ImageData* imageData, ErrorResult&)
+{
+ const char funcName[] = "texSubImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
- tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
- unpackFormat, unpackType, maybeView, &out_rv);
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ const GLint zOffset = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, imageData);
}
void
-WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset, GLint yOffset,
- GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult& out_rv)
+WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
+ GLint yOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::Element* elem, ErrorResult* const out_error)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "texSubImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "texSubImage2D", &texImageTarget,
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
- tex->TexSubImage2D(texImageTarget, level, xOffset, yOffset, unpackFormat, unpackType,
- imageData, &out_rv);
+ const bool isSubImage = true;
+ const GLenum internalFormat = 0;
+ const GLint zOffset = 0;
+ tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
+ yOffset, zOffset, unpackFormat, unpackType, elem, out_error);
}
+////////////////////////////////////////
+// CompressedTex(Sub)Image
-//////////////////////////////////////////////////////////////////////////////////////////
+void
+WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height,
+ GLint border,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+{
+ const char funcName[] = "compressedTexImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ const GLsizei depth = 1;
+
+ tex->CompressedTexImage(funcName, target, level, internalFormat, width, height, depth,
+ border, view);
+}
+
+void
+WebGLContext::CompressedTexSubImage2D(GLenum rawTexImageTarget, GLint level,
+ GLint xOffset, GLint yOffset, GLsizei width,
+ GLsizei height, GLenum sizedUnpackFormat,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
+{
+ const char funcName[] = "compressedTexSubImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
+ WebGLTexture* tex;
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
+ {
+ return;
+ }
+
+ const GLint zOffset = 0;
+ const GLsizei depth = 1;
+
+ tex->CompressedTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, width,
+ height, depth, sizedUnpackFormat, view);
+}
+
+////////////////////////////////////////
// CopyTex(Sub)Image
-
void
WebGLContext::CopyTexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
GLint x, GLint y, GLsizei width, GLsizei height,
GLint border)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "copyTexImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "copyTexImage2D",
- &texImageTarget, &tex))
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
{
return;
}
- tex->CopyTexImage2D(texImageTarget, level, internalFormat, x, y, width, height,
- border);
+ tex->CopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
}
void
WebGLContext::CopyTexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLint x, GLint y, GLsizei width,
GLsizei height)
{
- TexImageTarget texImageTarget;
+ const char funcName[] = "copyTexSubImage2D";
+ const uint8_t funcDims = 2;
+
+ TexImageTarget target;
WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "copyTexSubImage2D",
- &texImageTarget, &tex))
+ if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
+ &tex))
{
return;
}
- tex->CopyTexSubImage2D(texImageTarget, level, xOffset, yOffset, x, y, width, height);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// CompressedTex(Sub)Image
-
-
-void
-WebGLContext::CompressedTexImage2D(GLenum rawTexImageTarget, GLint level,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLint border, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
-{
- TexImageTarget texImageTarget;
- WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "compressedTexImage2D",
- &texImageTarget, &tex))
- {
- return;
- }
+ const GLint zOffset = 0;
- tex->CompressedTexImage2D(texImageTarget, level, internalFormat, width, height,
- border, view);
-}
-
-void
-WebGLContext::CompressedTexSubImage2D(GLenum rawTexImageTarget, GLint level,
- GLint xOffset, GLint yOffset, GLsizei width,
- GLsizei height, GLenum unpackFormat,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view)
-{
- TexImageTarget texImageTarget;
- WebGLTexture* tex;
- if (!ValidateTexImageTarget(this, rawTexImageTarget, "compressedTexSubImage2D",
- &texImageTarget, &tex))
- {
- return;
- }
-
- tex->CompressedTexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
- unpackFormat, view);
+ tex->CopyTexSubImage(funcName, target, level, xOffset, yOffset, zOffset, x, y, width,
+ height);
}
} // namespace mozilla
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -22,49 +22,16 @@
#include "WebGLFramebuffer.h"
#include "WebGLProgram.h"
#include "WebGLTexture.h"
#include "WebGLVertexArray.h"
#include "WebGLContextUtils.h"
namespace mozilla {
-bool
-IsGLDepthFormat(TexInternalFormat internalformat)
-{
- TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
- return unsizedformat == LOCAL_GL_DEPTH_COMPONENT;
-}
-
-bool
-IsGLDepthStencilFormat(TexInternalFormat internalformat)
-{
- TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
- return unsizedformat == LOCAL_GL_DEPTH_STENCIL;
-}
-
-bool
-FormatHasAlpha(TexInternalFormat internalformat)
-{
- TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
- return unsizedformat == LOCAL_GL_RGBA ||
- unsizedformat == LOCAL_GL_LUMINANCE_ALPHA ||
- unsizedformat == LOCAL_GL_ALPHA ||
- unsizedformat == LOCAL_GL_SRGB_ALPHA ||
- unsizedformat == LOCAL_GL_RGBA_INTEGER;
-}
-
-bool
-FormatHasDepth(TexInternalFormat format)
-{
- TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(format);
- return unsizedformat == LOCAL_GL_DEPTH_COMPONENT ||
- unsizedformat == LOCAL_GL_DEPTH_STENCIL;
-}
-
TexTarget
TexImageTargetToTexTarget(TexImageTarget texImageTarget)
{
switch (texImageTarget.get()) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_3D:
return texImageTarget.get();
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
@@ -88,467 +55,16 @@ StringValue(JSContext* cx, const char* c
if (!str) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return JS::NullValue();
}
return JS::StringValue(str);
}
-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;
- }
-}
-
-bool
-GLComponents::IsSubsetOf(const GLComponents& other) const
-{
- return (mComponents | other.mComponents) == other.mComponents;
-}
-
-void
-CopyTexImageIntermediateFormatAndType(TexInternalFormat effectiveFormat,
- TexFormat* const out_format,
- TexType* const out_type)
-{
- // GLES 3.0.4, p140, table 3.15 "ReadPixels `format` and `type` used during CopyTex*."
- switch (effectiveFormat.get()) {
- // Normalized fixed-point
- case LOCAL_GL_R8:
- case LOCAL_GL_RG8:
- case LOCAL_GL_RGB8:
- case LOCAL_GL_RGBA8:
- case LOCAL_GL_ALPHA8:
- case LOCAL_GL_LUMINANCE8:
- case LOCAL_GL_LUMINANCE8_ALPHA8:
-
- case LOCAL_GL_RGB565:
- case LOCAL_GL_RGBA4:
- case LOCAL_GL_RGB5_A1:
-
- case LOCAL_GL_SRGB8:
- case LOCAL_GL_SRGB8_ALPHA8:
- *out_format = LOCAL_GL_RGBA;
- *out_type = LOCAL_GL_UNSIGNED_BYTE;
- return;
-
- // 10-bit normalized fixed-point
- case LOCAL_GL_RGB10_A2:
- *out_format = LOCAL_GL_RGBA;
- *out_type = LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV;
- return;
-
- // Signed integer.
- case LOCAL_GL_R8I:
- case LOCAL_GL_RG8I:
- case LOCAL_GL_RGB8I:
- case LOCAL_GL_RGBA8I:
-
- case LOCAL_GL_R16I:
- case LOCAL_GL_RG16I:
- case LOCAL_GL_RGB16I:
- case LOCAL_GL_RGBA16I:
-
- case LOCAL_GL_R32I:
- case LOCAL_GL_RG32I:
- case LOCAL_GL_RGB32I:
- case LOCAL_GL_RGBA32I:
- *out_format = LOCAL_GL_RGBA;
- *out_type = LOCAL_GL_INT;
- return;
-
- // Unsigned integer.
- case LOCAL_GL_R8UI:
- case LOCAL_GL_RG8UI:
- case LOCAL_GL_RGB8UI:
- case LOCAL_GL_RGBA8UI:
-
- case LOCAL_GL_R16UI:
- case LOCAL_GL_RG16UI:
- case LOCAL_GL_RGB16UI:
- case LOCAL_GL_RGBA16UI:
-
- case LOCAL_GL_R32UI:
- case LOCAL_GL_RG32UI:
- case LOCAL_GL_RGB32UI:
- case LOCAL_GL_RGBA32UI:
-
- case LOCAL_GL_RGB10_A2UI:
- *out_format = LOCAL_GL_RGBA;
- *out_type = LOCAL_GL_UNSIGNED_INT;
- return;
-
- // Float and half-float are added by EXT_color_buffer_float.
- case LOCAL_GL_R16F:
- case LOCAL_GL_RG16F:
- case LOCAL_GL_RGB16F:
- case LOCAL_GL_RGBA16F:
- case LOCAL_GL_ALPHA16F_EXT:
- case LOCAL_GL_LUMINANCE16F_EXT:
- case LOCAL_GL_LUMINANCE_ALPHA16F_EXT:
-
- case LOCAL_GL_R32F:
- case LOCAL_GL_RG32F:
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_RGBA32F:
- case LOCAL_GL_ALPHA32F_EXT:
- case LOCAL_GL_LUMINANCE32F_EXT:
- case LOCAL_GL_LUMINANCE_ALPHA32F_EXT:
- *out_format = LOCAL_GL_RGBA;
- *out_type = LOCAL_GL_FLOAT;
- return;
-
- // Non-color-renderable
- case LOCAL_GL_R8_SNORM:
- case LOCAL_GL_RG8_SNORM:
- case LOCAL_GL_RGB8_SNORM:
- case LOCAL_GL_RGBA8_SNORM:
- case LOCAL_GL_R11F_G11F_B10F:
- case LOCAL_GL_RGB9_E5:
-
- // Unsupported
- case LOCAL_GL_DEPTH_COMPONENT16:
- case LOCAL_GL_DEPTH_COMPONENT24:
- case LOCAL_GL_DEPTH24_STENCIL8:
- case LOCAL_GL_DEPTH_COMPONENT32F:
- case LOCAL_GL_DEPTH32F_STENCIL8:
- default:
- MOZ_CRASH("Bad `effectiveFormat`.");
- }
-}
-
-TexType
-TypeFromInternalFormat(TexInternalFormat internalformat)
-{
-#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
- if (internalformat == table_effectiveinternalformat) { \
- return table_type; \
- }
-
-#include "WebGLInternalFormatsTable.h"
-
- // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
- return LOCAL_GL_NONE; // no size, no type
-}
-
-TexInternalFormat
-UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat)
-{
-#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
- if (internalformat == table_effectiveinternalformat) { \
- return table_internalformat; \
- }
-
-#include "WebGLInternalFormatsTable.h"
-
- // if we're here, then internalformat is not an effective internalformat i.e. is an unsized internalformat.
- // so we can just return it.
- return internalformat;
-}
-
-/*
- * Note that the following two functions are inverse of each other:
- * EffectiveInternalFormatFromInternalFormatAndType and
- * InternalFormatAndTypeFromEffectiveInternalFormat both implement OpenGL ES 3.0.3 Table 3.2
- * but in opposite directions.
- */
-TexInternalFormat
-EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
- TexType type)
-{
- MOZ_ASSERT(TypeFromInternalFormat(internalformat) == LOCAL_GL_NONE);
-
-#define HANDLE_WEBGL_INTERNAL_FORMAT(table_effectiveinternalformat, table_internalformat, table_type) \
- if (internalformat == table_internalformat && type == table_type) { \
- return table_effectiveinternalformat; \
- }
-
-#include "WebGLInternalFormatsTable.h"
-
- // If we're here, that means that type was incompatible with the given internalformat.
- return LOCAL_GL_NONE;
-}
-
-void
-UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
- TexInternalFormat* const out_internalformat,
- TexType* const 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;
-}
-
-TexInternalFormat
-EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
- TexType type)
-{
- TexType typeOfInternalFormat = TypeFromInternalFormat(internalformat);
- if (typeOfInternalFormat == LOCAL_GL_NONE)
- return EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, type);
-
- if (typeOfInternalFormat == type)
- return internalformat;
-
- return LOCAL_GL_NONE;
-}
-
-/**
- * Convert effective internalformat into GL function parameters
- * valid for underlying driver.
- */
-void
-DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
- TexInternalFormat effectiveinternalformat,
- GLenum* const out_driverInternalFormat,
- GLenum* const out_driverFormat,
- GLenum* const 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->IsCompatibilityProfile()) {
- // 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();
- }
- }
-
- // OpenGL core profile removed texture formats ALPHA, LUMINANCE and LUMINANCE_ALPHA
- if (gl->IsCoreProfile()) {
- switch (driverFormat) {
- case LOCAL_GL_ALPHA:
- case LOCAL_GL_LUMINANCE:
- driverInternalFormat = driverFormat = LOCAL_GL_RED;
- break;
-
- case LOCAL_GL_LUMINANCE_ALPHA:
- driverInternalFormat = driverFormat = LOCAL_GL_RG;
- break;
- }
- }
-
- *out_driverInternalFormat = driverInternalFormat;
- *out_driverFormat = driverFormat;
- *out_driverType = driverType;
-}
-
-/**
- * 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;
- }
-}
-
void
WebGLContext::GenerateWarning(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
GenerateWarning(fmt, ap);
@@ -593,37 +109,16 @@ bool
WebGLContext::ShouldGenerateWarnings() const
{
if (mMaxWarnings == -1)
return true;
return mAlreadyGeneratedWarnings < mMaxWarnings;
}
-CheckedUint32
-WebGLContext::GetImageSize(GLsizei height, GLsizei width, GLsizei depth,
- uint32_t pixelSize, uint32_t packOrUnpackAlignment)
-{
- CheckedUint32 checked_plainRowSize = CheckedUint32(width) * pixelSize;
-
- // alignedRowSize = row size rounded up to next multiple of packAlignment
- CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
-
- // if height is 0, we don't need any memory to store this; without this check, we'll get an overflow
- CheckedUint32 checked_2dImageSize = 0;
- if (height >= 1) {
- checked_2dImageSize = (height-1) * checked_alignedRowSize +
- checked_plainRowSize;
- }
-
- // FIXME - we should honor UNPACK_IMAGE_HEIGHT
- CheckedUint32 checked_imageSize = checked_2dImageSize * depth;
- return checked_imageSize;
-}
-
void
WebGLContext::SynthesizeGLError(GLenum err)
{
/* ES2 section 2.5 "GL Errors" states that implementations can have
* multiple 'flags', as errors might be caught in different parts of
* a distributed implementation.
* We're signing up as a distributed implementation here, with
* separate flags for WebGL and the underlying GLContext.
@@ -1307,18 +802,29 @@ WebGLContext::AssertCachedState()
// Viewport
GLint int4[4] = {0, 0, 0, 0};
gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4);
MOZ_ASSERT(int4[0] == mViewportX &&
int4[1] == mViewportY &&
int4[2] == mViewportWidth &&
int4[3] == mViewportHeight);
- AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStorePackAlignment);
- AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStoreUnpackAlignment);
+ AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment);
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);
+
+ if (IsWebGL2()) {
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT, mPixelStore_UnpackImageHeight);
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES , mPixelStore_UnpackSkipImages);
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH , mPixelStore_UnpackRowLength);
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS , mPixelStore_UnpackSkipRows);
+ AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS , mPixelStore_UnpackSkipPixels);
+ AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH , mPixelStore_PackRowLength);
+ AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS , mPixelStore_PackSkipRows);
+ AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS , mPixelStore_PackSkipPixels);
+ }
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
#endif
}
const char*
InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
{
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -10,48 +10,16 @@
#include "mozilla/Assertions.h"
#include "mozilla/dom/BindingUtils.h"
#include "WebGLStrongTypes.h"
namespace mozilla {
-bool IsGLDepthFormat(TexInternalFormat format);
-bool IsGLDepthStencilFormat(TexInternalFormat format);
-bool FormatHasAlpha(TexInternalFormat format);
-bool FormatHasDepth(TexInternalFormat format);
-
-void
-DriverFormatsFromEffectiveInternalFormat(gl::GLContext* gl,
- TexInternalFormat internalformat,
- GLenum* const out_driverInternalFormat,
- GLenum* const out_driverFormat,
- GLenum* const out_driverType);
-TexInternalFormat
-EffectiveInternalFormatFromInternalFormatAndType(TexInternalFormat internalformat,
- TexType type);
-TexInternalFormat
-EffectiveInternalFormatFromUnsizedInternalFormatAndType(TexInternalFormat internalformat,
- TexType type);
-void
-UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(TexInternalFormat effectiveinternalformat,
- TexInternalFormat* const out_internalformat,
- TexType* const out_type);
-TexType TypeFromInternalFormat(TexInternalFormat internalformat);
-
-TexInternalFormat
-UnsizedInternalFormatFromInternalFormat(TexInternalFormat internalformat);
-
-void CopyTexImageIntermediateFormatAndType(TexInternalFormat effectiveFormat,
- TexFormat* const out_format,
- TexType* const out_type);
-
-size_t GetBitsPerTexel(TexInternalFormat effectiveinternalformat);
-
// For use with the different texture calls, i.e.
// TexImage2D, CopyTex[Sub]Image2D, ...
// that take a "target" parameter. This parameter is not always the same as
// the texture binding location, like GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
// For example, cube maps would pass GL_TEXTURE_CUBE_MAP_[POS|NEG]_[X|Y|Z]
// instead of just GL_TEXTURE_CUBE_MAP.
//
// This function converts the texture image target to the texture target a.k.a.
@@ -59,19 +27,16 @@ size_t GetBitsPerTexel(TexInternalFormat
// the currently bound texture is appropriate for this texImageTarget.
//
// Returns GL_NONE if passed an invalid texture image target
TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
// Helper function to create a JS::Value from a C string
JS::Value StringValue(JSContext* cx, const char* str, ErrorResult& rv);
-bool IsCompressedTextureFormat(GLenum format);
-bool IsTextureFormatCompressed(TexInternalFormat format);
-
struct GLComponents
{
unsigned char mComponents;
enum Components {
Red = (1 << 0),
Green = (1 << 1),
Blue = (1 << 2),
@@ -94,17 +59,17 @@ struct GLComponents
template <typename WebGLObjectType>
JS::Value
WebGLContext::WebGLObjectAsJSValue(JSContext* cx, const WebGLObjectType* object,
ErrorResult& rv) const
{
if (!object)
return JS::NullValue();
- MOZ_ASSERT(this == object->Context());
+ MOZ_ASSERT(this == object->mContext);
JS::Rooted<JS::Value> v(cx);
JS::Rooted<JSObject*> wrapper(cx, GetWrapper());
JSAutoCompartment ac(cx, wrapper);
if (!dom::GetOrCreateDOMReflector(cx, const_cast<WebGLObjectType*>(object), &v)) {
rv.Throw(NS_ERROR_FAILURE);
return JS::NullValue();
}
return v;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -516,918 +516,16 @@ WebGLContext::ValidateSamplerParameterPa
}
default:
ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
return false;
}
}
-
-/**
- * Return true if format is a valid texture image format for source,
- * taking into account enabled WebGL extensions.
- */
-bool
-WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- /* Core WebGL texture formats */
- if (format == LOCAL_GL_ALPHA ||
- format == LOCAL_GL_RGB ||
- format == LOCAL_GL_RGBA ||
- format == LOCAL_GL_LUMINANCE ||
- format == LOCAL_GL_LUMINANCE_ALPHA)
- {
- return true;
- }
-
- /* WebGL2 new formats */
- if (format == LOCAL_GL_RED ||
- format == LOCAL_GL_RG ||
- format == LOCAL_GL_RED_INTEGER ||
- format == LOCAL_GL_RG_INTEGER ||
- format == LOCAL_GL_RGB_INTEGER ||
- format == LOCAL_GL_RGBA_INTEGER)
- {
- if (IsWebGL2())
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires WebGL version 2.0 or"
- " newer.", InfoFrom(func, dims), EnumName(format));
- return false;
- }
-
- /* WEBGL_depth_texture added formats */
- if (format == LOCAL_GL_DEPTH_COMPONENT ||
- format == LOCAL_GL_DEPTH_STENCIL)
- {
- if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
- ErrorInvalidEnum("%s: Invalid format %s: Requires that"
- " WEBGL_depth_texture is enabled.",
- InfoFrom(func, dims), EnumName(format));
- return false;
- }
-
- // If WEBGL_depth_texture is enabled, then it is not allowed to be used
- // with the copyTexImage, or copyTexSubImage methods, and it is not
- // allowed with texSubImage in WebGL1.
- if ((func == WebGLTexImageFunc::TexSubImage && !IsWebGL2()) ||
- func == WebGLTexImageFunc::CopyTexImage ||
- func == WebGLTexImageFunc::CopyTexSubImage)
- {
- ErrorInvalidOperation("%s: format %s is not supported",
- InfoFrom(func, dims), EnumName(format));
- return false;
- }
-
- return true;
- }
-
- // Needs to be below the depth_texture check because an invalid operation
- // error needs to be generated instead of invalid enum.
- // Only core formats are valid for CopyTex[Sub]Image.
- // TODO: Revisit this once color_buffer_[half_]float lands.
- if (IsCopyFunc(func)) {
- ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
- return false;
- }
-
- // EXT_sRGB added formats
- if (format == LOCAL_GL_SRGB ||
- format == LOCAL_GL_SRGB_ALPHA)
- {
- if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires that EXT_sRGB is"
- " enabled.", InfoFrom(func, dims),
- WebGLContext::EnumName(format));
- return false;
- }
-
- ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
- return false;
-}
-
-/**
- * Return true if type is a valid texture image type for source,
- * taking into account enabled WebGL extensions.
- */
-bool
-WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- /* Core WebGL texture types */
- if (type == LOCAL_GL_UNSIGNED_BYTE ||
- type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
- type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
- type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
- {
- return true;
- }
-
- /* WebGL2 new types */
- if (type == LOCAL_GL_BYTE ||
- type == LOCAL_GL_SHORT ||
- type == LOCAL_GL_INT ||
- type == LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV ||
- type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV ||
- type == LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV ||
- type == LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV)
- {
- if (IsWebGL2())
- return true;
-
- ErrorInvalidEnum("%s: Invalid type %s: Requires WebGL version 2.0 or"
- " newer.", InfoFrom(func, dims),
- WebGLContext::EnumName(type));
- return false;
- }
-
- /* OES_texture_float added types */
- if (type == LOCAL_GL_FLOAT) {
- if (IsExtensionEnabled(WebGLExtensionID::OES_texture_float))
- return true;
-
- ErrorInvalidEnum("%s: Invalid type %s: Requires that OES_texture_float"
- " is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(type));
- return false;
- }
-
- /* OES_texture_half_float add types */
- if (type == LOCAL_GL_HALF_FLOAT) {
- if (IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float))
- return true;
-
- ErrorInvalidEnum("%s: Invalid type %s: Requires that"
- " OES_texture_half_float is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(type));
- return false;
- }
-
- /* WEBGL_depth_texture added types */
- if (type == LOCAL_GL_UNSIGNED_SHORT ||
- type == LOCAL_GL_UNSIGNED_INT ||
- type == LOCAL_GL_UNSIGNED_INT_24_8)
- {
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture))
- return true;
-
- ErrorInvalidEnum("%s: Invalid type %s: Requires that"
- " WEBGL_depth_texture is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(type));
- return false;
- }
-
- ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
- return false;
-}
-
-/**
- * Validate texture image sizing extra constraints for
- * CompressedTex(Sub)?Image.
- */
-// TODO: WebGL 2
-bool
-WebGLContext::ValidateCompTexImageSize(GLint level, GLenum format,
- GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLsizei levelWidth, GLsizei levelHeight,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- // Negative parameters must already have been handled above
- MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
- width >= 0 && height >= 0);
-
- if (xoffset + width > (GLint) levelWidth) {
- ErrorInvalidValue("%s: xoffset + width must be <= levelWidth.",
- InfoFrom(func, dims));
- return false;
- }
-
- if (yoffset + height > (GLint) levelHeight) {
- ErrorInvalidValue("%s: yoffset + height must be <= levelHeight.",
- InfoFrom(func, dims));
- return false;
- }
-
- GLint blockWidth = 1;
- GLint blockHeight = 1;
- BlockSizeFor(format, &blockWidth, &blockHeight);
-
- // If blockWidth || blockHeight != 1, then the compressed format had
- // block-based constraints to be checked. (For example, PVRTC is compressed
- // but isn't a block-based format)
- if (blockWidth != 1 || blockHeight != 1) {
- // Offsets must be multiple of block size.
- if (xoffset % blockWidth != 0) {
- ErrorInvalidOperation("%s: xoffset must be multiple of %d.",
- InfoFrom(func, dims), blockWidth);
- return false;
- }
-
- if (yoffset % blockHeight != 0) {
- ErrorInvalidOperation("%s: yoffset must be multiple of %d.",
- InfoFrom(func, dims), blockHeight);
- return false;
- }
-
- /* The size must be a multiple of blockWidth and blockHeight, or must be
- * using offset+size that exactly hits the edge. Important for small
- * mipmap levels.
- *
- * From the WEBGL_compressed_texture_s3tc spec:
- * When level equals zero width and height must be a multiple of 4.
- * When level is greater than 0 width and height must be 0, 1, 2 or
- * a multiple of 4. If they are not an INVALID_OPERATION error is
- * generated."
- */
- if (level == 0) {
- if (width % blockWidth != 0) {
- ErrorInvalidOperation("%s: Width of level 0 must be a multiple"
- " of %d.", InfoFrom(func, dims),
- blockWidth);
- return false;
- }
-
- if (height % blockHeight != 0) {
- ErrorInvalidOperation("%s: Height of level 0 must be a multiple"
- " of %d.", InfoFrom(func, dims),
- blockHeight);
- return false;
- }
- } else if (level > 0) {
- if (width % blockWidth != 0 && width > 2) {
- ErrorInvalidOperation("%s: Width of level %d must be a multiple"
- " of %d, or be 0, 1, or 2.",
- InfoFrom(func, dims), level, blockWidth);
- return false;
- }
-
- if (height % blockHeight != 0 && height > 2) {
- ErrorInvalidOperation("%s: Height of level %d must be a"
- " multiple of %d, or be 0, 1, or 2.",
- InfoFrom(func, dims), level, blockHeight);
- return false;
- }
- }
-
- if (IsSubFunc(func)) {
- if ((xoffset % blockWidth) != 0) {
- ErrorInvalidOperation("%s: xoffset must be a multiple of %d.",
- InfoFrom(func, dims), blockWidth);
- return false;
- }
-
- if (yoffset % blockHeight != 0) {
- ErrorInvalidOperation("%s: yoffset must be a multiple of %d.",
- InfoFrom(func, dims), blockHeight);
- return false;
- }
- }
- }
-
- switch (format) {
- 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:
- if (!IsPowerOfTwo(width) ||
- !IsPowerOfTwo(height))
- {
- ErrorInvalidValue("%s: Width and height must be powers of two.",
- InfoFrom(func, dims));
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * Return true if the enough data is present to satisfy compressed
- * texture format constraints.
- */
-bool
-WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
- GLsizei width, GLsizei height,
- uint32_t byteLength,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- // negative width and height must already have been handled above
- MOZ_ASSERT(width >= 0 && height >= 0);
-
- CheckedUint32 required_byteLength = 0;
-
- switch (format) {
- case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- case LOCAL_GL_ATC_RGB:
- case LOCAL_GL_ETC1_RGB8_OES:
- required_byteLength = ((CheckedUint32(width) + 3) / 4) *
- ((CheckedUint32(height) + 3) / 4) * 8;
- break;
-
- 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:
- required_byteLength = ((CheckedUint32(width) + 3) / 4) *
- ((CheckedUint32(height) + 3) / 4) * 16;
- break;
-
- case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
- case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
- required_byteLength = CheckedUint32(std::max(width, 8)) *
- CheckedUint32(std::max(height, 8)) / 2;
- break;
-
- case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
- case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
- required_byteLength = CheckedUint32(std::max(width, 16)) *
- CheckedUint32(std::max(height, 8)) / 4;
- break;
- }
-
- if (!required_byteLength.isValid() ||
- required_byteLength.value() != byteLength)
- {
- ErrorInvalidValue("%s: Data size does not match dimensions.",
- InfoFrom(func, dims));
- return false;
- }
-
- return true;
-}
-
-/**
- * Validate the width, height, and depth of a texture image, \return
- * true is valid, false otherwise.
- * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
- * Target and level must have been validated before calling.
- */
-bool
-WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
- GLint width, GLint height, GLint depth,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- MOZ_ASSERT(level >= 0, "level should already be validated");
-
- /* Bug 966630: maxTextureSize >> level runs into "undefined"
- * behaviour depending on ISA. For example, on Intel shifts
- * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
- * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
- * what would be expected. Make the required behaviour explicit by
- * clamping to a shift of 31 bits if level is greater than that
- * ammount. This will give 0 that if (!maxAllowedSize) is
- * expecting.
- */
-
- if (level > 31)
- level = 31;
-
- auto texTarget = TexImageTargetToTexTarget(texImageTarget);
- const GLuint maxTexImageSize = MaxTextureSizeForTarget(texTarget) >> level;
-
- const bool isCubemapTarget = IsTexImageCubemapTarget(texImageTarget.get());
- const bool isSub = IsSubFunc(func);
-
- if (!isSub && isCubemapTarget && (width != height)) {
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "When the target parameter to TexImage2D is one of the
- * six cube map two-dimensional image targets, the error
- * INVALID_VALUE is generated if the width and height
- * parameters are not equal."
- */
- ErrorInvalidValue("%s: For cube maps, width must equal height.",
- InfoFrom(func, dims));
- return false;
- }
-
- if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget) {
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "If wt and ht are the specified image width and height,
- * and if either wt or ht are less than zero, then the error
- * INVALID_VALUE is generated."
- */
- if (width < 0) {
- ErrorInvalidValue("%s: Width must be >= 0.", InfoFrom(func, dims));
- return false;
- }
-
- if (height < 0) {
- ErrorInvalidValue("%s: Height must be >= 0.", InfoFrom(func, dims));
- return false;
- }
-
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "The maximum allowable width and height of a
- * two-dimensional texture image must be at least 2**(k−lod)
- * for image arrays of level zero through k, where k is the
- * log base 2 of MAX_TEXTURE_SIZE. and lod is the
- * level-of-detail of the image array. It may be zero for
- * image arrays of any level-of-detail greater than k. The
- * error INVALID_VALUE is generated if the specified image
- * is too large to be stored under any conditions.
- */
- if (width > (int) maxTexImageSize) {
- ErrorInvalidValue("%s: The maximum width for level %d is %u.",
- InfoFrom(func, dims), level, maxTexImageSize);
- return false;
- }
-
- if (height > (int) maxTexImageSize) {
- ErrorInvalidValue("%s: The maximum height for level %d is %u.",
- InfoFrom(func, dims), level, maxTexImageSize);
- return false;
- }
-
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "If level is greater than zero, and either width or
- * height is not a power-of-two, the error INVALID_VALUE is
- * generated."
- *
- * This restriction does not apply to GL ES Version 3.0+.
- */
- if (!IsWebGL2() && level > 0) {
- if (!IsPowerOfTwo(width)) {
- ErrorInvalidValue("%s: For level > 0, width of %d must be a"
- " power of two.", InfoFrom(func, dims),
- width);
- return false;
- }
-
- if (!IsPowerOfTwo(height)) {
- ErrorInvalidValue("%s: For level > 0, height of %d must be a"
- " power of two.", InfoFrom(func, dims),
- height);
- return false;
- }
- }
- }
-
- // TODO: WebGL 2
- if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
- if (depth < 0) {
- ErrorInvalidValue("%s: Depth must be >= 0.", InfoFrom(func, dims));
- return false;
- }
-
- if (!IsWebGL2() && !IsPowerOfTwo(depth)) {
- ErrorInvalidValue("%s: Depth of %d must be a power of two.",
- InfoFrom(func, dims), depth);
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * Validate texture image sizing for Tex(Sub)?Image variants.
- */
-// TODO: WebGL 2. Update this to handle 3D textures.
-bool
-WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset,
- GLint /*zoffset*/, GLsizei width,
- GLsizei height, GLsizei /*depth*/,
- GLsizei baseWidth, GLsizei baseHeight,
- GLsizei /*baseDepth*/,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
- * "Taking wt and ht to be the specified width and height of the
- * texture array, and taking x, y, w, and h to be the xoffset,
- * yoffset, width, and height argument values, any of the
- * following relationships generates the error INVALID_VALUE:
- * x < 0
- * x + w > wt
- * y < 0
- * y + h > ht"
- */
-
- if (xoffset < 0) {
- ErrorInvalidValue("%s: xoffset must be >= 0.", InfoFrom(func, dims));
- return false;
- }
-
- if (yoffset < 0) {
- ErrorInvalidValue("%s: yoffset must be >= 0.", InfoFrom(func, dims));
- return false;
- }
-
- if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height,
- baseWidth, baseHeight))
- {
- ErrorInvalidValue("%s: Subtexture rectangle out-of-bounds.",
- InfoFrom(func, dims));
- return false;
- }
-
- return true;
-}
-
-/**
- * Perform validation of format/type combinations for TexImage variants.
- * Returns true if the format/type is a valid combination, false otherwise.
- */
-bool
-WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- if (type == LOCAL_GL_HALF_FLOAT_OES) {
- type = LOCAL_GL_HALF_FLOAT;
- }
-
- if (IsCompressedFunc(func) || IsCopyFunc(func)) {
- MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
- return true;
- }
-
- if (!ValidateTexImageFormat(format, func, dims) ||
- !ValidateTexImageType(type, func, dims))
- {
- return false;
- }
-
- // Here we're reinterpreting format as an unsized internalformat;
- // these are the same in practice and there's no point in having the
- // same code implemented twice.
- TexInternalFormat effective =
- EffectiveInternalFormatFromInternalFormatAndType(format, type);
-
- if (effective != LOCAL_GL_NONE)
- return true;
-
- ErrorInvalidOperation("%s: Invalid combination of format %s and type %s.",
- InfoFrom(func, dims), WebGLContext::EnumName(format),
- WebGLContext::EnumName(type));
- return false;
-}
-
-bool
-WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- if (!IsCompressedTextureFormat(format)) {
- ErrorInvalidEnum("%s: Invalid compressed texture format: %s",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
- return false;
- }
-
- /* WEBGL_compressed_texture_atc added formats */
- if (format == LOCAL_GL_ATC_RGB ||
- format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
- format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
- {
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc))
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires that"
- " WEBGL_compressed_texture_atc is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
- return false;
- }
-
- // WEBGL_compressed_texture_etc1
- if (format == LOCAL_GL_ETC1_RGB8_OES) {
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1))
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires that"
- " WEBGL_compressed_texture_etc1 is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
- return false;
- }
-
-
- if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
- format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
- format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
- format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
- {
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc))
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires that"
- " WEBGL_compressed_texture_pvrtc is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
- return false;
- }
-
-
- if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
- format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
- format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
- format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
- {
- if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc))
- return true;
-
- ErrorInvalidEnum("%s: Invalid format %s: Requires that"
- " WEBGL_compressed_texture_s3tc is enabled.",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
- return false;
- }
-
- MOZ_ASSERT(false);
- return false;
-}
-
-bool
-WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- switch (format) {
- case LOCAL_GL_RGBA:
- case LOCAL_GL_RGB:
- case LOCAL_GL_LUMINANCE_ALPHA:
- case LOCAL_GL_LUMINANCE:
- case LOCAL_GL_ALPHA:
- return true;
- }
- // In CopyTexImage, internalFormat is a function parameter,
- // so a bad value is an INVALID_ENUM error.
- // In CopyTexSubImage, internalFormat is part of existing state,
- // so this is an INVALID_OPERATION error.
- GenerateWarning("%s: Invalid texture internal format: %s",
- InfoFrom(func, dims), WebGLContext::EnumName(format));
-
- GLenum error;
- if (func == WebGLTexImageFunc::CopyTexImage)
- error = LOCAL_GL_INVALID_ENUM;
- else
- error = LOCAL_GL_INVALID_OPERATION;
-
- SynthesizeGLError(error);
- return false;
-}
-/**
- * Return true if format, type and jsArrayType are a valid combination.
- * Also returns the size for texel of format and type (in bytes) via
- * \a texelSize.
- *
- * It is assumed that type has previously been validated.
- */
-bool
-WebGLContext::ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- // We're using js::Scalar::MaxTypedArrayViewType as dummy value for when
- // the tex source wasn't a typed array.
- if (jsArrayType == js::Scalar::MaxTypedArrayViewType)
- return true;
-
- const char invalidTypedArray[] = "%s: Invalid typed array type for given"
- " texture data type.";
-
- bool validInput = false;
- switch (type) {
- case LOCAL_GL_UNSIGNED_BYTE:
- validInput = jsArrayType == js::Scalar::Uint8;
- break;
-
- case LOCAL_GL_BYTE:
- validInput = jsArrayType == js::Scalar::Int8;
- break;
-
- case LOCAL_GL_HALF_FLOAT:
- case LOCAL_GL_UNSIGNED_SHORT:
- 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:
- validInput = jsArrayType == js::Scalar::Uint16;
- break;
-
- case LOCAL_GL_SHORT:
- validInput = jsArrayType == js::Scalar::Int16;
- break;
-
- case LOCAL_GL_UNSIGNED_INT:
- case LOCAL_GL_UNSIGNED_INT_24_8:
- case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
- case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
- case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
- validInput = jsArrayType == js::Scalar::Uint32;
- break;
-
- case LOCAL_GL_INT:
- validInput = jsArrayType == js::Scalar::Int32;
- break;
-
- case LOCAL_GL_FLOAT:
- validInput = jsArrayType == js::Scalar::Float32;
- break;
-
- default:
- break;
- }
-
- if (!validInput)
- ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
-
- return validInput;
-}
-
-/**
- * Checks specific for the CopyTex[Sub]Image2D functions.
- * Verifies:
- * - Framebuffer is complete and has valid read planes
- * - Copy format is a subset of framebuffer format (i.e. all required components
- * are available)
- */
-bool
-WebGLContext::ValidateCopyTexImage(TexInternalFormat srcFormat,
- TexInternalFormat dstformat, WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- MOZ_ASSERT(IsCopyFunc(func));
-/*
- // Default framebuffer format
- GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
-
- if (mBoundReadFramebuffer) {
- TexInternalFormat srcFormat;
- if (!mBoundReadFramebuffer->ValidateForRead(InfoFrom(func, dims), &srcFormat))
- return false;
-
- fboFormat = srcFormat.get();
- }
-*/
- // Make sure the format of the framebuffer (srcFormat) is a superset of the format
- // requested by the CopyTex[Sub]Image2D functions (dstFormat).
- const GLComponents srcComps = GLComponents(srcFormat);
- const GLComponents dstComps = GLComponents(dstformat);
- if (!dstComps.IsSubsetOf(srcComps)) {
- ErrorInvalidOperation("%s: Format %s is not a subset of the current"
- " framebuffer format, which is %s.",
- InfoFrom(func, dims), EnumName(dstformat.get()),
- EnumName(srcFormat.get()));
- return false;
- }
-
- return true;
-}
-
-/**
- * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
- * Verifies each of the parameters against the WebGL standard and enabled
- * extensions.
- */
-// TODO: Texture dims is here for future expansion in WebGL 2.0
-bool
-WebGLContext::ValidateTexImage(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLint xoffset,
- GLint yoffset, GLint zoffset, GLint width,
- GLint height, GLint depth, GLint border,
- GLenum format, GLenum type,
- WebGLTexImageFunc func,
- WebGLTexDimensions dims)
-{
- const char* info = InfoFrom(func, dims);
-
- // Check level
- if (level < 0) {
- ErrorInvalidValue("%s: `level` must be >= 0.", info);
- return false;
- }
-
- // Check border
- if (border != 0) {
- ErrorInvalidValue("%s: `border` must be 0.", info);
- return false;
- }
-
- // Check incoming image format and type
- if (!ValidateTexImageFormatAndType(format, type, func, dims))
- return false;
-
- if (!TexInternalFormat::IsValueLegal(internalFormat)) {
- ErrorInvalidEnum("%s: Invalid `internalformat` enum %s.", info,
- EnumName(internalFormat));
- return false;
- }
- TexInternalFormat unsizedInternalFormat =
- UnsizedInternalFormatFromInternalFormat(internalFormat);
-
- if (IsCompressedFunc(func)) {
- if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims))
- return false;
-
- } else if (IsCopyFunc(func)) {
- if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(),
- func, dims))
- {
- return false;
- }
- } else if (format != unsizedInternalFormat) {
- if (IsWebGL2()) {
- // In WebGL2, it's OK to have `internalFormat != format` if
- // internalFormat is the sized internal format corresponding to the
- // (format, type) pair according to Table 3.2 in the OpenGL ES 3.0.3
- // spec.
- auto effectiveFormat = EffectiveInternalFormatFromInternalFormatAndType(format,
- type);
- if (internalFormat != effectiveFormat) {
- bool exceptionallyAllowed = false;
- if (internalFormat == LOCAL_GL_SRGB8_ALPHA8 &&
- format == LOCAL_GL_RGBA &&
- type == LOCAL_GL_UNSIGNED_BYTE)
- {
- exceptionallyAllowed = true;
- }
- else if (internalFormat == LOCAL_GL_SRGB8 &&
- format == LOCAL_GL_RGB &&
- type == LOCAL_GL_UNSIGNED_BYTE)
- {
- exceptionallyAllowed = true;
- }
- if (!exceptionallyAllowed) {
- ErrorInvalidOperation("%s: `internalformat` does not match"
- " `format` and `type`.", info);
- return false;
- }
- }
- } else {
- // In WebGL 1, format must be equal to internalformat.
- ErrorInvalidOperation("%s: `internalformat` does not match"
- " `format`.", info);
- return false;
- }
- }
-
- // Check texture image size
- if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func,
- dims))
- {
- return false;
- }
-
- /* 5.14.8 Texture objects - WebGL Spec.
- * "If an attempt is made to call these functions with no
- * WebGLTexture bound (see above), an INVALID_OPERATION error
- * is generated."
- */
- WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
- if (!tex) {
- ErrorInvalidOperation("%s: No texture is bound to target %s.", info,
- WebGLContext::EnumName(texImageTarget.get()));
- return false;
- }
-
- if (IsSubFunc(func)) {
- const auto& imageInfo = tex->ImageInfoAt(texImageTarget, level);
- if (!imageInfo.IsDefined()) {
- ErrorInvalidOperation("%s: No texture image previously defined for"
- " target %s at level %d.", info,
- WebGLContext::EnumName(texImageTarget.get()),
- level);
- return false;
- }
-
- if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset, width, height,
- depth, imageInfo.mWidth,
- imageInfo.mHeight, 0, func, dims))
- {
- return false;
- }
- }
-
- // Additional checks for depth textures
- if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
- (format == LOCAL_GL_DEPTH_COMPONENT ||
- format == LOCAL_GL_DEPTH_STENCIL))
- {
- ErrorInvalidOperation("%s: With format of %s, target must be"
- " TEXTURE_2D.", info,
- WebGLContext::EnumName(format));
- return false;
- }
-
- // Additional checks for compressed textures
- if (!IsAllowedFromSource(internalFormat, func)) {
- ErrorInvalidOperation("%s: Invalid format %s for this operation.",
- info, WebGLContext::EnumName(format));
- return false;
- }
-
- // Parameters are OK
- return true;
-}
-
bool
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
{
/* GLES 2.0.25, p38:
* If the value of location is -1, the Uniform* commands will silently
* ignore the data passed in, and the current uniform values will not be
* changed.
*/
@@ -1653,17 +751,17 @@ bool
WebGLContext::InitAndValidateGL()
{
if (!gl)
return false;
// Unconditionally create a new format usage authority. This is
// important when restoring contexts and extensions need to add
// formats back into the authority.
- mFormatUsage = CreateFormatUsage();
+ mFormatUsage = CreateFormatUsage(gl);
GLenum error = gl->fGetError();
if (error != LOCAL_GL_NO_ERROR) {
GenerateWarning("GL error 0x%x occurred during OpenGL context"
" initialization, before WebGL initialization!", error);
return false;
}
@@ -1768,49 +866,64 @@ WebGLContext::InitAndValidateGL()
return false;
}
mBound2DTextures.SetLength(mGLMaxTextureUnits);
mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
mBound3DTextures.SetLength(mGLMaxTextureUnits);
mBoundSamplers.SetLength(mGLMaxTextureUnits);
+ ////////////////
+
if (MinCapabilityMode()) {
- mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
- mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
- mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
+ mImplMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
+ mImplMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
+ mImplMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
+
+ mImplMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
+ mImplMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
+
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
+
mGLMaxSamples = 1;
} else {
- gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
- gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
- gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
+ gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mImplMaxTextureSize);
+ gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mImplMaxCubeMapTextureSize);
+ gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, (GLint*)&mImplMaxRenderbufferSize);
+
+ if (!gl->GetPotentialInteger(LOCAL_GL_MAX_3D_TEXTURE_SIZE, (GLint*)&mImplMax3DTextureSize))
+ mImplMax3DTextureSize = 0;
+ if (!gl->GetPotentialInteger(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, (GLint*)&mImplMaxArrayTextureLayers))
+ mImplMaxArrayTextureLayers = 0;
+
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
mGLMaxSamples = 1;
}
- // Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize
- mGLMaxTextureSizeLog2 = 0;
- int32_t tempSize = mGLMaxTextureSize;
- while (tempSize >>= 1) {
- ++mGLMaxTextureSizeLog2;
- }
+ const auto fnFloor = [](uint32_t& val) {
+ if (val) {
+ val = FloorPOT(val);
+ }
+ };
- mGLMaxCubeMapTextureSizeLog2 = 0;
- tempSize = mGLMaxCubeMapTextureSize;
- while (tempSize >>= 1) {
- ++mGLMaxCubeMapTextureSizeLog2;
- }
+ fnFloor(mImplMaxTextureSize);
+ fnFloor(mImplMaxCubeMapTextureSize);
+ fnFloor(mImplMaxRenderbufferSize);
- mGLMaxTextureSize = FloorPOT(mGLMaxTextureSize);
- mGLMaxRenderbufferSize = FloorPOT(mGLMaxRenderbufferSize);
+ fnFloor(mImplMax3DTextureSize);
+ fnFloor(mImplMaxArrayTextureLayers);
+
+ ////////////////
+
+ mGLMaxColorAttachments = 1;
+ mGLMaxDrawBuffers = 1;
if (MinCapabilityMode()) {
mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
} else {
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
@@ -1931,16 +1044,32 @@ WebGLContext::InitAndValidateGL()
// vertex array object (the name zero) is also deprecated. [...]"
if (gl->IsCoreProfile()) {
MakeContextCurrent();
mDefaultVertexArray->GenVertexArray();
mDefaultVertexArray->BindVertexArray();
}
+ mPixelStore_FlipY = false;
+ mPixelStore_PremultiplyAlpha = false;
+ mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL;
+
+ // GLES 3.0.4, p259:
+ mPixelStore_UnpackImageHeight = 0;
+ mPixelStore_UnpackSkipImages = 0;
+ mPixelStore_UnpackRowLength = 0;
+ mPixelStore_UnpackSkipRows = 0;
+ mPixelStore_UnpackSkipPixels = 0;
+ mPixelStore_UnpackAlignment = 4;
+ mPixelStore_PackRowLength = 0;
+ mPixelStore_PackSkipRows = 0;
+ mPixelStore_PackSkipPixels = 0;
+ mPixelStore_PackAlignment = 4;
+
return true;
}
bool
WebGLContext::ValidateFramebufferTarget(GLenum target,
const char* const info)
{
bool isValid = true;
--- a/dom/canvas/WebGLExtensionColorBufferFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferFloat.cpp
@@ -4,42 +4,42 @@
#include "WebGLExtensions.h"
#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
-namespace mozilla {
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
-using mozilla::webgl::EffectiveFormat;
+namespace mozilla {
WebGLExtensionColorBufferFloat::WebGLExtensionColorBufferFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
- auto updateUsage = [authority](EffectiveFormat effectiveFormat) {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->asRenderbuffer = usage->isRenderable = true;
+ auto fnUpdateUsage = [&fua](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto usage = fua->EditUsage(effFormat);
+ usage->isRenderable = true;
+
+ fua->AddRBFormat(sizedFormat, usage);
};
- // Ensure require formats are initialized.
- WebGLExtensionTextureFloat::InitWebGLFormats(authority);
+#define FOO(x) fnUpdateUsage(LOCAL_GL_ ## x, webgl::EffectiveFormat::x)
- // Update usage to allow asRenderbuffer and isRenderable
- updateUsage(EffectiveFormat::RGBA32F);
- updateUsage(EffectiveFormat::RGB32F);
- updateUsage(EffectiveFormat::Luminance32FAlpha32F);
- updateUsage(EffectiveFormat::Luminance32F);
- updateUsage(EffectiveFormat::Alpha32F);
+ FOO(RGBA32F);
+ FOO(RGB32F);
+
+#undef FOO
}
WebGLExtensionColorBufferFloat::~WebGLExtensionColorBufferFloat()
{
}
bool
WebGLExtensionColorBufferFloat::IsSupported(const WebGLContext* webgl)
--- a/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionColorBufferHalfFloat.cpp
@@ -4,42 +4,42 @@
#include "WebGLExtensions.h"
#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
-namespace mozilla {
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
-using mozilla::webgl::EffectiveFormat;
+namespace mozilla {
WebGLExtensionColorBufferHalfFloat::WebGLExtensionColorBufferHalfFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
- auto updateUsage = [authority](EffectiveFormat effectiveFormat) {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->asRenderbuffer = usage->isRenderable = true;
+ auto fnUpdateUsage = [&fua](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto usage = fua->EditUsage(effFormat);
+ usage->isRenderable = true;
+
+ fua->AddRBFormat(sizedFormat, usage);
};
- // Ensure require formats are initialized.
- WebGLExtensionTextureHalfFloat::InitWebGLFormats(authority);
+#define FOO(x) fnUpdateUsage(LOCAL_GL_ ## x, webgl::EffectiveFormat::x)
- // Update usage to allow asRenderbuffer and isRenderable
- updateUsage(EffectiveFormat::RGBA16F);
- updateUsage(EffectiveFormat::RGB16F);
- updateUsage(EffectiveFormat::Luminance16FAlpha16F);
- updateUsage(EffectiveFormat::Luminance16F);
- updateUsage(EffectiveFormat::Alpha16F);
+ FOO(RGBA16F);
+ FOO(RGB16F);
+
+#undef FOO
}
WebGLExtensionColorBufferHalfFloat::~WebGLExtensionColorBufferHalfFloat()
{
}
bool
WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
--- a/dom/canvas/WebGLExtensionCompressedTextureATC.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTextureATC.cpp
@@ -2,24 +2,41 @@
* 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 "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
namespace mozilla {
WebGLExtensionCompressedTextureATC::WebGLExtensionCompressedTextureATC(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGB);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA);
+ const auto fnAdd = [webgl](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto& fua = webgl->mFormatUsage;
+
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddSizedTexFormat(sizedFormat, usage);
+
+ webgl->mCompressedTextureFormats.AppendElement(sizedFormat);
+ };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+ fnAdd(FOO(ATC_RGB_AMD));
+ fnAdd(FOO(ATC_RGBA_EXPLICIT_ALPHA_AMD));
+ fnAdd(FOO(ATC_RGBA_INTERPOLATED_ALPHA_AMD));
+
+#undef FOO
}
WebGLExtensionCompressedTextureATC::~WebGLExtensionCompressedTextureATC()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureATC, WEBGL_compressed_texture_atc)
--- a/dom/canvas/WebGLExtensionCompressedTextureETC1.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTextureETC1.cpp
@@ -2,22 +2,39 @@
* 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 "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
namespace mozilla {
WebGLExtensionCompressedTextureETC1::WebGLExtensionCompressedTextureETC1(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_ETC1_RGB8_OES);
+ const auto fnAdd = [webgl](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto& fua = webgl->mFormatUsage;
+
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddSizedTexFormat(sizedFormat, usage);
+
+ webgl->mCompressedTextureFormats.AppendElement(sizedFormat);
+ };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+ fnAdd(FOO(ETC1_RGB8_OES));
+
+#undef FOO
}
WebGLExtensionCompressedTextureETC1::~WebGLExtensionCompressedTextureETC1()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureETC1, WEBGL_compressed_texture_etc1)
--- a/dom/canvas/WebGLExtensionCompressedTexturePVRTC.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTexturePVRTC.cpp
@@ -2,25 +2,42 @@
* 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 "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
namespace mozilla {
WebGLExtensionCompressedTexturePVRTC::WebGLExtensionCompressedTexturePVRTC(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1);
+ const auto fnAdd = [webgl](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto& fua = webgl->mFormatUsage;
+
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddSizedTexFormat(sizedFormat, usage);
+
+ webgl->mCompressedTextureFormats.AppendElement(sizedFormat);
+ };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+ fnAdd(FOO(COMPRESSED_RGB_PVRTC_4BPPV1));
+ fnAdd(FOO(COMPRESSED_RGB_PVRTC_2BPPV1));
+ fnAdd(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1));
+ fnAdd(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1));
+
+#undef FOO
}
WebGLExtensionCompressedTexturePVRTC::~WebGLExtensionCompressedTexturePVRTC()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTexturePVRTC, WEBGL_compressed_texture_pvrtc)
--- a/dom/canvas/WebGLExtensionCompressedTextureS3TC.cpp
+++ b/dom/canvas/WebGLExtensionCompressedTextureS3TC.cpp
@@ -2,25 +2,42 @@
* 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 "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
namespace mozilla {
WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
- webgl->mCompressedTextureFormats.AppendElement(LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
+ const auto fnAdd = [webgl](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
+ auto& fua = webgl->mFormatUsage;
+
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddSizedTexFormat(sizedFormat, usage);
+
+ webgl->mCompressedTextureFormats.AppendElement(sizedFormat);
+ };
+
+#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
+
+ fnAdd(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT));
+ fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT));
+ fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT));
+ fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT));
+
+#undef FOO
}
WebGLExtensionCompressedTextureS3TC::~WebGLExtensionCompressedTextureS3TC()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureS3TC, WEBGL_compressed_texture_s3tc)
--- a/dom/canvas/WebGLExtensionDepthTexture.cpp
+++ b/dom/canvas/WebGLExtensionDepthTexture.cpp
@@ -8,16 +8,37 @@
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
namespace mozilla {
WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
+ auto& fua = webgl->mFormatUsage;
+
+ const auto fnAdd = [&fua](webgl::EffectiveFormat effFormat, GLenum unpackFormat,
+ GLenum unpackType)
+ {
+ auto usage = fua->EditUsage(effFormat);
+ const webgl::PackingInfo pi = {unpackFormat, unpackType};
+ const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
+
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ };
+
+ fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT16, LOCAL_GL_DEPTH_COMPONENT,
+ LOCAL_GL_UNSIGNED_SHORT);
+
+ fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT24, LOCAL_GL_DEPTH_COMPONENT,
+ LOCAL_GL_UNSIGNED_INT);
+
+ fnAdd(webgl::EffectiveFormat::DEPTH24_STENCIL8, LOCAL_GL_DEPTH_STENCIL,
+ LOCAL_GL_UNSIGNED_INT_24_8);
}
WebGLExtensionDepthTexture::~WebGLExtensionDepthTexture()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDepthTexture, WEBGL_depth_texture)
--- a/dom/canvas/WebGLExtensionSRGB.cpp
+++ b/dom/canvas/WebGLExtensionSRGB.cpp
@@ -7,46 +7,52 @@
#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
namespace mozilla {
-using mozilla::webgl::EffectiveFormat;
-
-
WebGLExtensionSRGB::WebGLExtensionSRGB(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
gl::GLContext* gl = webgl->GL();
if (!gl->IsGLES()) {
// Desktop OpenGL requires the following to be enabled in order to
// support sRGB operations on framebuffers.
gl->MakeCurrent();
gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
}
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
+
+ webgl::FormatUsageInfo* usage;
+ webgl::PackingInfo pi;
+ webgl::DriverUnpackInfo dui;
- auto addFormatIfMissing = [authority](EffectiveFormat effectiveFormat,
- GLenum unpackFormat, GLenum unpackType,
- bool asRenderbuffer)
- {
- if (!authority->GetUsage(effectiveFormat)) {
- authority->AddFormat(effectiveFormat, asRenderbuffer, asRenderbuffer, true, true);
- authority->AddUnpackOption(unpackFormat, unpackType, effectiveFormat);
- }
- };
+ usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8);
+ usage->isRenderable = false;
+ usage->isFilterable = true;
+ pi = {LOCAL_GL_SRGB, LOCAL_GL_UNSIGNED_BYTE};
+ dui = {LOCAL_GL_SRGB, LOCAL_GL_SRGB, LOCAL_GL_UNSIGNED_BYTE};
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
- addFormatIfMissing(EffectiveFormat::SRGB8 , LOCAL_GL_SRGB , LOCAL_GL_UNSIGNED_BYTE, false);
- addFormatIfMissing(EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE, true);
+ usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
+ usage->isRenderable = true;
+ usage->isFilterable = true;
+ pi = {LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ dui = {LOCAL_GL_SRGB_ALPHA, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+
+ fua->AddRBFormat(LOCAL_GL_SRGB_ALPHA, usage);
}
WebGLExtensionSRGB::~WebGLExtensionSRGB()
{
}
bool
WebGLExtensionSRGB::IsSupported(const WebGLContext* webgl)
--- a/dom/canvas/WebGLExtensionTextureFloat.cpp
+++ b/dom/canvas/WebGLExtensionTextureFloat.cpp
@@ -1,65 +1,59 @@
/* 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 "WebGLExtensions.h"
+#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
namespace mozilla {
-using mozilla::webgl::EffectiveFormat;
-
-void
-WebGLExtensionTextureFloat::InitWebGLFormats(webgl::FormatUsageAuthority* authority)
-{
- MOZ_ASSERT(authority);
-
- auto addFormatIfMissing = [authority](EffectiveFormat effectiveFormat)
- {
- if (!authority->GetUsage(effectiveFormat)) {
- authority->AddFormat(effectiveFormat, false, false, false, false);
- }
- };
-
- // Populate authority with any missing effective formats.
- addFormatIfMissing(EffectiveFormat::RGBA32F);
- addFormatIfMissing(EffectiveFormat::RGB32F);
- addFormatIfMissing(EffectiveFormat::Luminance32FAlpha32F);
- addFormatIfMissing(EffectiveFormat::Luminance32F);
- addFormatIfMissing(EffectiveFormat::Alpha32F);
-}
-
WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
+
+ webgl::PackingInfo pi;
+ webgl::DriverUnpackInfo dui;
+
+ const auto fnAdd = [&fua, &pi, &dui](webgl::EffectiveFormat effFormat) {
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ };
+
+ const bool isCore = webgl->GL()->IsCoreProfile();
+
+ pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
+ dui = {LOCAL_GL_RGBA, LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
+ fnAdd(webgl::EffectiveFormat::RGBA32F);
- auto updateUsage = [authority](EffectiveFormat effectiveFormat,
- GLenum unpackFormat, GLenum unpackType)
- {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->asTexture = true;
- authority->AddUnpackOption(unpackFormat, unpackType, effectiveFormat);
- };
+ pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT};
+ dui = {LOCAL_GL_RGB, LOCAL_GL_RGB, LOCAL_GL_FLOAT};
+ fnAdd(webgl::EffectiveFormat::RGB32F);
+
+ pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
+ if (isCore) dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
+ else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
+ fnAdd(webgl::EffectiveFormat::Luminance32F);
- // Ensure require formats are initialized.
- InitWebGLFormats(authority);
+ pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
+ if (isCore) dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
+ else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
+ fnAdd(webgl::EffectiveFormat::Alpha32F);
- // Update usage to allow asTexture and add unpack
- updateUsage(EffectiveFormat::RGBA32F , LOCAL_GL_RGBA , LOCAL_GL_FLOAT);
- updateUsage(EffectiveFormat::RGB32F , LOCAL_GL_RGB , LOCAL_GL_FLOAT);
- updateUsage(EffectiveFormat::Luminance32FAlpha32F, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT);
- updateUsage(EffectiveFormat::Luminance32F , LOCAL_GL_LUMINANCE , LOCAL_GL_FLOAT);
- updateUsage(EffectiveFormat::Alpha32F , LOCAL_GL_ALPHA , LOCAL_GL_FLOAT);
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
+ if (isCore) dui = {LOCAL_GL_RG32F, LOCAL_GL_RG, LOCAL_GL_FLOAT};
+ else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
+ fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F);
}
WebGLExtensionTextureFloat::~WebGLExtensionTextureFloat()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFloat, OES_texture_float)
--- a/dom/canvas/WebGLExtensionTextureFloatLinear.cpp
+++ b/dom/canvas/WebGLExtensionTextureFloatLinear.cpp
@@ -5,42 +5,26 @@
#include "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
namespace mozilla {
-using mozilla::webgl::EffectiveFormat;
-
WebGLExtensionTextureFloatLinear::WebGLExtensionTextureFloatLinear(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- // This update requires that the authority already be populated by
- // WebGLExtensionTextureFloat. Enabling extensions to control
- // features is a mess in WebGL
-
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
- auto updateUsage = [authority](EffectiveFormat effectiveFormat) {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->isFilterable = true;
- };
-
- // Ensure require formats are initialized.
- WebGLExtensionTextureFloat::InitWebGLFormats(authority);
-
- // Update usage to allow isFilterable
- updateUsage(EffectiveFormat::RGBA32F);
- updateUsage(EffectiveFormat::RGB32F);
- updateUsage(EffectiveFormat::Luminance32FAlpha32F);
- updateUsage(EffectiveFormat::Luminance32F);
- updateUsage(EffectiveFormat::Alpha32F);
+ fua->EditUsage(webgl::EffectiveFormat::RGBA32F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::RGB32F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Luminance32FAlpha32F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Luminance32F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Alpha32F)->isFilterable = true;
}
WebGLExtensionTextureFloatLinear::~WebGLExtensionTextureFloatLinear()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFloatLinear, OES_texture_float_linear)
--- a/dom/canvas/WebGLExtensionTextureHalfFloat.cpp
+++ b/dom/canvas/WebGLExtensionTextureHalfFloat.cpp
@@ -1,64 +1,65 @@
/* 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 "WebGLExtensions.h"
+#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
namespace mozilla {
-using mozilla::webgl::EffectiveFormat;
-
-void
-WebGLExtensionTextureHalfFloat::InitWebGLFormats(webgl::FormatUsageAuthority* authority)
-{
- MOZ_ASSERT(authority);
-
- auto addFormatIfMissing = [authority](EffectiveFormat effectiveFormat)
- {
- if (!authority->GetUsage(effectiveFormat)) {
- authority->AddFormat(effectiveFormat, false, false, false, false);
- }
- };
-
- // Populate authority with any missing effective formats.
- addFormatIfMissing(EffectiveFormat::RGBA16F);
- addFormatIfMissing(EffectiveFormat::RGB16F);
- addFormatIfMissing(EffectiveFormat::Luminance16FAlpha16F);
- addFormatIfMissing(EffectiveFormat::Luminance16F);
- addFormatIfMissing(EffectiveFormat::Alpha16F);
-}
-
WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
+
+ webgl::PackingInfo pi;
+ webgl::DriverUnpackInfo dui;
+
+ const auto fnAdd = [&fua, &pi, &dui](webgl::EffectiveFormat effFormat) {
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ };
+
+ GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT;
+ if (!webgl->GL()->IsSupported(gl::GLFeature::texture_half_float)) {
+ MOZ_ASSERT(webgl->GL()->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
+ driverUnpackType = LOCAL_GL_HALF_FLOAT_OES;
+ }
+
+ const bool isCore = webgl->GL()->IsCoreProfile();
- auto updateUsage = [authority](EffectiveFormat effectiveFormat,
- GLenum unpackFormat, GLenum unpackType)
- {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->asTexture = true;
- authority->AddUnpackOption(unpackFormat, unpackType, effectiveFormat);
- };
+ pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES};
+ dui = {LOCAL_GL_RGBA, LOCAL_GL_RGBA, driverUnpackType};
+ fnAdd(webgl::EffectiveFormat::RGBA16F);
+
+ pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES};
+ dui = {LOCAL_GL_RGB, LOCAL_GL_RGB, driverUnpackType};
+ fnAdd(webgl::EffectiveFormat::RGB16F);
- InitWebGLFormats(authority);
+ pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES};
+ if (isCore) dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
+ else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, driverUnpackType};
+ fnAdd(webgl::EffectiveFormat::Luminance16F);
- // Update usage to allow asTexture and add unpack
- updateUsage(EffectiveFormat::RGBA16F , LOCAL_GL_RGBA , LOCAL_GL_HALF_FLOAT_OES);
- updateUsage(EffectiveFormat::RGB16F , LOCAL_GL_RGB , LOCAL_GL_HALF_FLOAT_OES);
- updateUsage(EffectiveFormat::Luminance16FAlpha16F, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES);
- updateUsage(EffectiveFormat::Luminance16F , LOCAL_GL_LUMINANCE , LOCAL_GL_HALF_FLOAT_OES);
- updateUsage(EffectiveFormat::Alpha16F , LOCAL_GL_ALPHA , LOCAL_GL_HALF_FLOAT_OES);
+ pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
+ if (isCore) dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
+ else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, driverUnpackType};
+ fnAdd(webgl::EffectiveFormat::Alpha16F);
+
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
+ if (isCore) dui = {LOCAL_GL_RG16F, LOCAL_GL_RG, driverUnpackType};
+ else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, driverUnpackType};
+ fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F);
}
WebGLExtensionTextureHalfFloat::~WebGLExtensionTextureHalfFloat()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureHalfFloat, OES_texture_half_float)
--- a/dom/canvas/WebGLExtensionTextureHalfFloatLinear.cpp
+++ b/dom/canvas/WebGLExtensionTextureHalfFloatLinear.cpp
@@ -5,42 +5,26 @@
#include "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#include "WebGLFormats.h"
namespace mozilla {
-using mozilla::webgl::EffectiveFormat;
-
WebGLExtensionTextureHalfFloatLinear::WebGLExtensionTextureHalfFloatLinear(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
- // This update requires that the authority already be populated by
- // WebGLExtensionTextureHalfFloat. Enabling extensions to control
- // features is a mess in WebGL
-
- webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
+ auto& fua = webgl->mFormatUsage;
- auto updateUsage = [authority](EffectiveFormat effectiveFormat) {
- webgl::FormatUsageInfo* usage = authority->GetUsage(effectiveFormat);
- MOZ_ASSERT(usage);
- usage->isFilterable = true;
- };
-
- // Ensure require formats are initialized.
- WebGLExtensionTextureHalfFloat::InitWebGLFormats(authority);
-
- // Update usage to allow isFilterable
- updateUsage(EffectiveFormat::RGBA16F);
- updateUsage(EffectiveFormat::RGB16F);
- updateUsage(EffectiveFormat::Luminance16FAlpha16F);
- updateUsage(EffectiveFormat::Luminance16F);
- updateUsage(EffectiveFormat::Alpha16F);
+ fua->EditUsage(webgl::EffectiveFormat::RGBA16F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::RGB16F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Luminance16FAlpha16F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Luminance16F)->isFilterable = true;
+ fua->EditUsage(webgl::EffectiveFormat::Alpha16F)->isFilterable = true;
}
WebGLExtensionTextureHalfFloatLinear::~WebGLExtensionTextureHalfFloatLinear()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureHalfFloatLinear, OES_texture_half_float_linear)
--- a/dom/canvas/WebGLExtensions.h
+++ b/dom/canvas/WebGLExtensions.h
@@ -33,17 +33,17 @@ class WebGLVertexArray;
class WebGLExtensionBase
: public nsWrapperCache
, public WebGLContextBoundObject
{
public:
explicit WebGLExtensionBase(WebGLContext* webgl);
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
void MarkLost();
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLExtensionBase)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLExtensionBase)
protected:
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -3,132 +3,152 @@
* 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 "WebGLFormats.h"
#include "GLDefs.h"
#include "mozilla/StaticMutex.h"
+#ifdef FOO
+#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
+#endif
+
namespace mozilla {
namespace webgl {
+// Returns an iterator to the in-place pair.
+template<typename K, typename V, typename K2, typename V2>
+static inline auto
+AlwaysInsert(std::map<K,V>& dest, const K2& key, const V2& val)
+{
+ auto res = dest.insert({ key, val });
+ DebugOnly<bool> didInsert = res.second;
+ MOZ_ASSERT(didInsert);
+
+ return res.first;
+}
+
+template<typename K, typename V, typename K2>
+static inline V*
+FindOrNull(const std::map<K,V*>& dest, const K2& key)
+{
+ auto itr = dest.find(key);
+ if (itr == dest.end())
+ return nullptr;
+
+ return itr->second;
+}
+
+// Returns a pointer to the in-place value for `key`.
+template<typename K, typename V, typename K2>
+static inline V*
+FindPtrOrNull(const std::map<K,V>& dest, const K2& key)
+{
+ auto itr = dest.find(key);
+ if (itr == dest.end())
+ return nullptr;
+
+ return &(itr->second);
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
std::map<EffectiveFormat, const CompressedFormatInfo> gCompressedFormatInfoMap;
std::map<EffectiveFormat, const FormatInfo> gFormatInfoMap;
-std::map<UnpackTuple, const FormatInfo*> gUnpackTupleMap;
-std::map<GLenum, const FormatInfo*> gSizedFormatMap;
-static const CompressedFormatInfo*
+static inline const CompressedFormatInfo*
GetCompressedFormatInfo(EffectiveFormat format)
{
MOZ_ASSERT(!gCompressedFormatInfoMap.empty());
- auto itr = gCompressedFormatInfoMap.find(format);
- if (itr == gCompressedFormatInfoMap.end())
- return nullptr;
-
- return &(itr->second);
+ return FindPtrOrNull(gCompressedFormatInfoMap, format);
}
-static const FormatInfo*
+static inline const FormatInfo*
GetFormatInfo_NoLock(EffectiveFormat format)
{
MOZ_ASSERT(!gFormatInfoMap.empty());
- auto itr = gFormatInfoMap.find(format);
- if (itr == gFormatInfoMap.end())
- return nullptr;
-
- return &(itr->second);
-}
-
-template<typename K, typename V, typename K2, typename V2>
-static void
-AlwaysInsert(std::map<K,V>& dest, const K2& key, const V2& val)
-{
- auto res = dest.insert({ key, val });
- bool didInsert = res.second;
- MOZ_ALWAYS_TRUE(didInsert);
+ return FindPtrOrNull(gFormatInfoMap, format);
}
//////////////////////////////////////////////////////////////////////////////////////////
static void
AddCompressedFormatInfo(EffectiveFormat format, uint16_t bitsPerBlock, uint8_t blockWidth,
- uint8_t blockHeight, bool requirePOT,
- SubImageUpdateBehavior subImageUpdateBehavior)
+ uint8_t blockHeight, CompressionFamily family)
{
MOZ_ASSERT(bitsPerBlock % 8 == 0);
uint16_t bytesPerBlock = bitsPerBlock / 8; // The specs always state these in bits,
// but it's only ever useful to us as
// bytes.
MOZ_ASSERT(bytesPerBlock <= 255);
const CompressedFormatInfo info = { format, uint8_t(bytesPerBlock), blockWidth,
- blockHeight, requirePOT, subImageUpdateBehavior };
+ blockHeight, family };
AlwaysInsert(gCompressedFormatInfoMap, format, info);
}
static void
InitCompressedFormatInfo()
{
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_ETC2 , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ETC2 , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA8_ETC2_EAC , 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC , 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_R11_EAC , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RG11_EAC , 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_R11_EAC , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_RG11_EAC , 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_ETC2 , 64, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ETC2 , 64, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA8_ETC2_EAC , 128, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC , 128, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_R11_EAC , 64, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RG11_EAC , 128, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_R11_EAC , 64, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_RG11_EAC , 128, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 , 64, 4, 4, CompressionFamily::ES3);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, 64, 4, 4, CompressionFamily::ES3);
// AMD_compressed_ATC_texture
- AddCompressedFormatInfo(EffectiveFormat::ATC_RGB_AMD , 64, 4, 4, false, SubImageUpdateBehavior::Forbidden);
- AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_EXPLICIT_ALPHA_AMD , 128, 4, 4, false, SubImageUpdateBehavior::Forbidden);
- AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD, 128, 4, 4, false, SubImageUpdateBehavior::Forbidden);
+ AddCompressedFormatInfo(EffectiveFormat::ATC_RGB_AMD , 64, 4, 4, CompressionFamily::ATC);
+ AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_EXPLICIT_ALPHA_AMD , 128, 4, 4, CompressionFamily::ATC);
+ AddCompressedFormatInfo(EffectiveFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD, 128, 4, 4, CompressionFamily::ATC);
// EXT_texture_compression_s3tc
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1 , 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1, 64, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3, 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5, 128, 4, 4, false, SubImageUpdateBehavior::BlockAligned);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1_EXT , 64, 4, 4, CompressionFamily::S3TC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1_EXT, 64, 4, 4, CompressionFamily::S3TC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);
// IMG_texture_compression_pvrtc
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_4BPPV1 , 256, 8, 8, true, SubImageUpdateBehavior::FullOnly);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_4BPPV1, 256, 8, 8, true, SubImageUpdateBehavior::FullOnly);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_2BPPV1 , 256, 16, 8, true, SubImageUpdateBehavior::FullOnly);
- AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_2BPPV1, 256, 16, 8, true, SubImageUpdateBehavior::FullOnly);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_4BPPV1 , 256, 8, 8, CompressionFamily::PVRTC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_4BPPV1, 256, 8, 8, CompressionFamily::PVRTC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_2BPPV1 , 256, 16, 8, CompressionFamily::PVRTC);
+ AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_2BPPV1, 256, 16, 8, CompressionFamily::PVRTC);
// OES_compressed_ETC1_RGB8_texture
- AddCompressedFormatInfo(EffectiveFormat::ETC1_RGB8, 64, 4, 4, false, SubImageUpdateBehavior::Forbidden);
+ AddCompressedFormatInfo(EffectiveFormat::ETC1_RGB8_OES, 64, 4, 4, CompressionFamily::ETC1);
}
//////////////////////////////////////////////////////////////////////////////////////////
static void
-AddFormatInfo(EffectiveFormat format, const char* name, uint8_t bytesPerPixel,
- UnsizedFormat unsizedFormat, ComponentType colorComponentType)
+AddFormatInfo(EffectiveFormat format, const char* name, GLenum sizedFormat,
+ uint8_t bytesPerPixel, UnsizedFormat unsizedFormat, bool isSRGB,
+ ComponentType componentType)
{
bool isColorFormat = false;
bool hasAlpha = false;
bool hasDepth = false;
bool hasStencil = false;
switch (unsizedFormat) {
case UnsizedFormat::L:
case UnsizedFormat::R:
case UnsizedFormat::RG:
case UnsizedFormat::RGB:
isColorFormat = true;
break;
- case UnsizedFormat::A: // 'Color format' in the spec just means color-attachable.
+ case UnsizedFormat::A: // Alpha is a 'color format' since it's 'color-attachable'.
case UnsizedFormat::LA:
case UnsizedFormat::RGBA:
isColorFormat = true;
hasAlpha = true;
break;
case UnsizedFormat::D:
hasDepth = true;
@@ -145,1015 +165,700 @@ AddFormatInfo(EffectiveFormat format, co
default:
MOZ_CRASH("Missing UnsizedFormat case.");
}
const CompressedFormatInfo* compressedFormatInfo = GetCompressedFormatInfo(format);
MOZ_ASSERT(!bytesPerPixel == bool(compressedFormatInfo));
- const FormatInfo info = { format, name, unsizedFormat, colorComponentType,
- bytesPerPixel, isColorFormat, hasAlpha, hasDepth,
+ const FormatInfo info = { format, name, sizedFormat, unsizedFormat, componentType,
+ bytesPerPixel, isColorFormat, isSRGB, hasAlpha, hasDepth,
hasStencil, compressedFormatInfo };
- AlwaysInsert(gFormatInfoMap, format, info);
+ const auto itr = AlwaysInsert(gFormatInfoMap, format, info);
}
static void
-InitFormatInfoMap()
+InitFormatInfo()
{
-#ifdef FOO
-#error FOO is already defined!
-#endif
-
-#define FOO(x) EffectiveFormat::x, #x
+#define FOO(x) EffectiveFormat::x, #x, LOCAL_GL_ ## x
// GLES 3.0.4, p130-132, table 3.13
- AddFormatInfo(FOO(R8 ), 1, UnsizedFormat::R , ComponentType::NormUInt );
- AddFormatInfo(FOO(R8_SNORM ), 1, UnsizedFormat::R , ComponentType::NormInt );
- AddFormatInfo(FOO(RG8 ), 2, UnsizedFormat::RG , ComponentType::NormUInt );
- AddFormatInfo(FOO(RG8_SNORM ), 2, UnsizedFormat::RG , ComponentType::NormInt );
- AddFormatInfo(FOO(RGB8 ), 3, UnsizedFormat::RGB , ComponentType::NormUInt );
- AddFormatInfo(FOO(RGB8_SNORM ), 3, UnsizedFormat::RGB , ComponentType::NormInt );
- AddFormatInfo(FOO(RGB565 ), 2, UnsizedFormat::RGB , ComponentType::NormUInt );
- AddFormatInfo(FOO(RGBA4 ), 2, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(RGB5_A1 ), 2, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(RGBA8 ), 4, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(RGBA8_SNORM ), 4, UnsizedFormat::RGBA, ComponentType::NormInt );
- AddFormatInfo(FOO(RGB10_A2 ), 4, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(RGB10_A2UI ), 4, UnsizedFormat::RGBA, ComponentType::UInt );
+ AddFormatInfo(FOO(R8 ), 1, UnsizedFormat::R , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(R8_SNORM ), 1, UnsizedFormat::R , false, ComponentType::NormInt );
+ AddFormatInfo(FOO(RG8 ), 2, UnsizedFormat::RG , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RG8_SNORM ), 2, UnsizedFormat::RG , false, ComponentType::NormInt );
+ AddFormatInfo(FOO(RGB8 ), 3, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGB8_SNORM ), 3, UnsizedFormat::RGB , false, ComponentType::NormInt );
+ AddFormatInfo(FOO(RGB565 ), 2, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGBA4 ), 2, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGB5_A1 ), 2, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGBA8 ), 4, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGBA8_SNORM ), 4, UnsizedFormat::RGBA, false, ComponentType::NormInt );
+ AddFormatInfo(FOO(RGB10_A2 ), 4, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(RGB10_A2UI ), 4, UnsizedFormat::RGBA, false, ComponentType::UInt );
- AddFormatInfo(FOO(SRGB8 ), 3, UnsizedFormat::RGB , ComponentType::NormUIntSRGB);
- AddFormatInfo(FOO(SRGB8_ALPHA8 ), 4, UnsizedFormat::RGBA, ComponentType::NormUIntSRGB);
+ AddFormatInfo(FOO(SRGB8 ), 3, UnsizedFormat::RGB , true , ComponentType::NormUInt);
+ AddFormatInfo(FOO(SRGB8_ALPHA8 ), 4, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
- AddFormatInfo(FOO(R16F ), 2, UnsizedFormat::R , ComponentType::Float );
- AddFormatInfo(FOO(RG16F ), 4, UnsizedFormat::RG , ComponentType::Float );
- AddFormatInfo(FOO(RGB16F ), 6, UnsizedFormat::RGB , ComponentType::Float );
- AddFormatInfo(FOO(RGBA16F ), 8, UnsizedFormat::RGBA, ComponentType::Float );
- AddFormatInfo(FOO(R32F ), 4, UnsizedFormat::R , ComponentType::Float );
- AddFormatInfo(FOO(RG32F ), 8, UnsizedFormat::RG , ComponentType::Float );
- AddFormatInfo(FOO(RGB32F ), 12, UnsizedFormat::RGB , ComponentType::Float );
- AddFormatInfo(FOO(RGBA32F ), 16, UnsizedFormat::RGBA, ComponentType::Float );
+ AddFormatInfo(FOO(R16F ), 2, UnsizedFormat::R , false, ComponentType::Float );
+ AddFormatInfo(FOO(RG16F ), 4, UnsizedFormat::RG , false, ComponentType::Float );
+ AddFormatInfo(FOO(RGB16F ), 6, UnsizedFormat::RGB , false, ComponentType::Float );
+ AddFormatInfo(FOO(RGBA16F ), 8, UnsizedFormat::RGBA, false, ComponentType::Float );
+ AddFormatInfo(FOO(R32F ), 4, UnsizedFormat::R , false, ComponentType::Float );
+ AddFormatInfo(FOO(RG32F ), 8, UnsizedFormat::RG , false, ComponentType::Float );
+ AddFormatInfo(FOO(RGB32F ), 12, UnsizedFormat::RGB , false, ComponentType::Float );
+ AddFormatInfo(FOO(RGBA32F ), 16, UnsizedFormat::RGBA, false, ComponentType::Float );
- AddFormatInfo(FOO(R11F_G11F_B10F), 4, UnsizedFormat::RGB , ComponentType::Float );
- AddFormatInfo(FOO(RGB9_E5 ), 4, UnsizedFormat::RGB , ComponentType::SharedExp );
+ AddFormatInfo(FOO(R11F_G11F_B10F), 4, UnsizedFormat::RGB , false, ComponentType::Float );
+ AddFormatInfo(FOO(RGB9_E5 ), 4, UnsizedFormat::RGB , false, ComponentType::Float );
- AddFormatInfo(FOO(R8I ), 1, UnsizedFormat::R , ComponentType::Int );
- AddFormatInfo(FOO(R8UI ), 1, UnsizedFormat::R , ComponentType::UInt );
- AddFormatInfo(FOO(R16I ), 2, UnsizedFormat::R , ComponentType::Int );
- AddFormatInfo(FOO(R16UI ), 2, UnsizedFormat::R , ComponentType::UInt );
- AddFormatInfo(FOO(R32I ), 4, UnsizedFormat::R , ComponentType::Int );
- AddFormatInfo(FOO(R32UI ), 4, UnsizedFormat::R , ComponentType::UInt );
+ AddFormatInfo(FOO(R8I ), 1, UnsizedFormat::R , false, ComponentType::Int );
+ AddFormatInfo(FOO(R8UI ), 1, UnsizedFormat::R , false, ComponentType::UInt );
+ AddFormatInfo(FOO(R16I ), 2, UnsizedFormat::R , false, ComponentType::Int );
+ AddFormatInfo(FOO(R16UI ), 2, UnsizedFormat::R , false, ComponentType::UInt );
+ AddFormatInfo(FOO(R32I ), 4, UnsizedFormat::R , false, ComponentType::Int );
+ AddFormatInfo(FOO(R32UI ), 4, UnsizedFormat::R , false, ComponentType::UInt );
- AddFormatInfo(FOO(RG8I ), 2, UnsizedFormat::RG , ComponentType::Int );
- AddFormatInfo(FOO(RG8UI ), 2, UnsizedFormat::RG , ComponentType::UInt );
- AddFormatInfo(FOO(RG16I ), 4, UnsizedFormat::RG , ComponentType::Int );
- AddFormatInfo(FOO(RG16UI ), 4, UnsizedFormat::RG , ComponentType::UInt );
- AddFormatInfo(FOO(RG32I ), 8, UnsizedFormat::RG , ComponentType::Int );
- AddFormatInfo(FOO(RG32UI ), 8, UnsizedFormat::RG , ComponentType::UInt );
+ AddFormatInfo(FOO(RG8I ), 2, UnsizedFormat::RG , false, ComponentType::Int );
+ AddFormatInfo(FOO(RG8UI ), 2, UnsizedFormat::RG , false, ComponentType::UInt );
+ AddFormatInfo(FOO(RG16I ), 4, UnsizedFormat::RG , false, ComponentType::Int );
+ AddFormatInfo(FOO(RG16UI ), 4, UnsizedFormat::RG , false, ComponentType::UInt );
+ AddFormatInfo(FOO(RG32I ), 8, UnsizedFormat::RG , false, ComponentType::Int );
+ AddFormatInfo(FOO(RG32UI ), 8, UnsizedFormat::RG , false, ComponentType::UInt );
- AddFormatInfo(FOO(RGB8I ), 3, UnsizedFormat::RGB , ComponentType::Int );
- AddFormatInfo(FOO(RGB8UI ), 3, UnsizedFormat::RGB , ComponentType::UInt );
- AddFormatInfo(FOO(RGB16I ), 6, UnsizedFormat::RGB , ComponentType::Int );
- AddFormatInfo(FOO(RGB16UI ), 6, UnsizedFormat::RGB , ComponentType::UInt );
- AddFormatInfo(FOO(RGB32I ), 12, UnsizedFormat::RGB , ComponentType::Int );
- AddFormatInfo(FOO(RGB32UI ), 12, UnsizedFormat::RGB , ComponentType::UInt );
+ AddFormatInfo(FOO(RGB8I ), 3, UnsizedFormat::RGB , false, ComponentType::Int );
+ AddFormatInfo(FOO(RGB8UI ), 3, UnsizedFormat::RGB , false, ComponentType::UInt );
+ AddFormatInfo(FOO(RGB16I ), 6, UnsizedFormat::RGB , false, ComponentType::Int );
+ AddFormatInfo(FOO(RGB16UI ), 6, UnsizedFormat::RGB , false, ComponentType::UInt );
+ AddFormatInfo(FOO(RGB32I ), 12, UnsizedFormat::RGB , false, ComponentType::Int );
+ AddFormatInfo(FOO(RGB32UI ), 12, UnsizedFormat::RGB , false, ComponentType::UInt );
- AddFormatInfo(FOO(RGBA8I ), 4, UnsizedFormat::RGBA, ComponentType::Int );
- AddFormatInfo(FOO(RGBA8UI ), 4, UnsizedFormat::RGBA, ComponentType::UInt );
- AddFormatInfo(FOO(RGBA16I ), 8, UnsizedFormat::RGBA, ComponentType::Int );
- AddFormatInfo(FOO(RGBA16UI ), 8, UnsizedFormat::RGBA, ComponentType::UInt );
- AddFormatInfo(FOO(RGBA32I ), 16, UnsizedFormat::RGBA, ComponentType::Int );
- AddFormatInfo(FOO(RGBA32UI ), 16, UnsizedFormat::RGBA, ComponentType::UInt );
+ AddFormatInfo(FOO(RGBA8I ), 4, UnsizedFormat::RGBA, false, ComponentType::Int );
+ AddFormatInfo(FOO(RGBA8UI ), 4, UnsizedFormat::RGBA, false, ComponentType::UInt );
+ AddFormatInfo(FOO(RGBA16I ), 8, UnsizedFormat::RGBA, false, ComponentType::Int );
+ AddFormatInfo(FOO(RGBA16UI ), 8, UnsizedFormat::RGBA, false, ComponentType::UInt );
+ AddFormatInfo(FOO(RGBA32I ), 16, UnsizedFormat::RGBA, false, ComponentType::Int );
+ AddFormatInfo(FOO(RGBA32UI ), 16, UnsizedFormat::RGBA, false, ComponentType::UInt );
// GLES 3.0.4, p133, table 3.14
- AddFormatInfo(FOO(DEPTH_COMPONENT16 ), 2, UnsizedFormat::D , ComponentType::None);
- AddFormatInfo(FOO(DEPTH_COMPONENT24 ), 3, UnsizedFormat::D , ComponentType::None);
- AddFormatInfo(FOO(DEPTH_COMPONENT32F), 4, UnsizedFormat::D , ComponentType::None);
- AddFormatInfo(FOO(DEPTH24_STENCIL8 ), 4, UnsizedFormat::DS, ComponentType::None);
- AddFormatInfo(FOO(DEPTH32F_STENCIL8 ), 5, UnsizedFormat::DS, ComponentType::None);
+ AddFormatInfo(FOO(DEPTH_COMPONENT16 ), 2, UnsizedFormat::D , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(DEPTH_COMPONENT24 ), 3, UnsizedFormat::D , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(DEPTH_COMPONENT32F), 4, UnsizedFormat::D , false, ComponentType::Float);
+ AddFormatInfo(FOO(DEPTH24_STENCIL8 ), 4, UnsizedFormat::DS, false, ComponentType::None);
+ AddFormatInfo(FOO(DEPTH32F_STENCIL8 ), 5, UnsizedFormat::DS, false, ComponentType::None);
// GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
- AddFormatInfo(FOO(STENCIL_INDEX8), 1, UnsizedFormat::S, ComponentType::None);
-
- // GLES 3.0.4, p128, table 3.12.
- AddFormatInfo(FOO(Luminance8Alpha8), 2, UnsizedFormat::LA, ComponentType::NormUInt);
- AddFormatInfo(FOO(Luminance8 ), 1, UnsizedFormat::L , ComponentType::NormUInt);
- AddFormatInfo(FOO(Alpha8 ), 1, UnsizedFormat::A , ComponentType::None );
+ AddFormatInfo(FOO(STENCIL_INDEX8), 1, UnsizedFormat::S, false, ComponentType::UInt);
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4 p286+ $C.1 "ETC Compressed Texture Image Formats"
- AddFormatInfo(FOO(COMPRESSED_RGB8_ETC2 ), 0, UnsizedFormat::RGB , ComponentType::NormUInt );
- AddFormatInfo(FOO(COMPRESSED_SRGB8_ETC2 ), 0, UnsizedFormat::RGB , ComponentType::NormUIntSRGB);
- AddFormatInfo(FOO(COMPRESSED_RGBA8_ETC2_EAC ), 0, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC ), 0, UnsizedFormat::RGBA, ComponentType::NormUIntSRGB);
- AddFormatInfo(FOO(COMPRESSED_R11_EAC ), 0, UnsizedFormat::R , ComponentType::NormUInt );
- AddFormatInfo(FOO(COMPRESSED_RG11_EAC ), 0, UnsizedFormat::RG , ComponentType::NormUInt );
- AddFormatInfo(FOO(COMPRESSED_SIGNED_R11_EAC ), 0, UnsizedFormat::R , ComponentType::NormInt );
- AddFormatInfo(FOO(COMPRESSED_SIGNED_RG11_EAC ), 0, UnsizedFormat::RG , ComponentType::NormInt );
- AddFormatInfo(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), 0, UnsizedFormat::RGBA, ComponentType::NormUInt );
- AddFormatInfo(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), 0, UnsizedFormat::RGBA, ComponentType::NormUIntSRGB);
+ AddFormatInfo(FOO(COMPRESSED_RGB8_ETC2 ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_SRGB8_ETC2 ), 0, UnsizedFormat::RGB , true , ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA8_ETC2_EAC ), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC ), 0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_R11_EAC ), 0, UnsizedFormat::R , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RG11_EAC ), 0, UnsizedFormat::RG , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_SIGNED_R11_EAC ), 0, UnsizedFormat::R , false, ComponentType::NormInt );
+ AddFormatInfo(FOO(COMPRESSED_SIGNED_RG11_EAC ), 0, UnsizedFormat::RG , false, ComponentType::NormInt );
+ AddFormatInfo(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), 0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
// AMD_compressed_ATC_texture
- AddFormatInfo(FOO(ATC_RGB_AMD ), 0, UnsizedFormat::RGB , ComponentType::NormUInt);
- AddFormatInfo(FOO(ATC_RGBA_EXPLICIT_ALPHA_AMD ), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
- AddFormatInfo(FOO(ATC_RGBA_INTERPOLATED_ALPHA_AMD), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
+ AddFormatInfo(FOO(ATC_RGB_AMD ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(ATC_RGBA_EXPLICIT_ALPHA_AMD ), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(ATC_RGBA_INTERPOLATED_ALPHA_AMD), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
// EXT_texture_compression_s3tc
- AddFormatInfo(FOO(COMPRESSED_RGB_S3TC_DXT1 ), 0, UnsizedFormat::RGB , ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT1), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT3), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT5), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
// IMG_texture_compression_pvrtc
- AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_4BPPV1 ), 0, UnsizedFormat::RGB , ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_2BPPV1 ), 0, UnsizedFormat::RGB , ComponentType::NormUInt);
- AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1), 0, UnsizedFormat::RGBA, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_4BPPV1 ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_2BPPV1 ), 0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1), 0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
// OES_compressed_ETC1_RGB8_texture
- AddFormatInfo(FOO(ETC1_RGB8), 0, UnsizedFormat::RGB, ComponentType::NormUInt);
-
- // OES_texture_float
- AddFormatInfo(FOO(Luminance32FAlpha32F), 2, UnsizedFormat::LA, ComponentType::Float);
- AddFormatInfo(FOO(Luminance32F ), 1, UnsizedFormat::L , ComponentType::Float);
- AddFormatInfo(FOO(Alpha32F ), 1, UnsizedFormat::A , ComponentType::Float);
-
- // OES_texture_half_float
- AddFormatInfo(FOO(Luminance16FAlpha16F), 2, UnsizedFormat::LA, ComponentType::Float);
- AddFormatInfo(FOO(Luminance16F ), 1, UnsizedFormat::L , ComponentType::Float);
- AddFormatInfo(FOO(Alpha16F ), 1, UnsizedFormat::A , ComponentType::Float);
+ AddFormatInfo(FOO(ETC1_RGB8_OES), 0, UnsizedFormat::RGB, false, ComponentType::NormUInt);
#undef FOO
-}
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void
-AddUnpackTuple(GLenum unpackFormat, GLenum unpackType, EffectiveFormat effectiveFormat)
-{
- const UnpackTuple unpack = { unpackFormat, unpackType };
- const FormatInfo* info = GetFormatInfo_NoLock(effectiveFormat);
- MOZ_ASSERT(info);
-
- AlwaysInsert(gUnpackTupleMap, unpack, info);
-}
-
-static void
-InitUnpackTupleMap()
-{
- AddUnpackTuple(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
- AddUnpackTuple(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4 );
- AddUnpackTuple(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
- AddUnpackTuple(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
- AddUnpackTuple(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
-
- AddUnpackTuple(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8Alpha8);
- AddUnpackTuple(LOCAL_GL_LUMINANCE , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8 );
- AddUnpackTuple(LOCAL_GL_ALPHA , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Alpha8 );
-
- AddUnpackTuple(LOCAL_GL_RGB , LOCAL_GL_FLOAT, EffectiveFormat::RGB32F );
- AddUnpackTuple(LOCAL_GL_RGBA , LOCAL_GL_FLOAT, EffectiveFormat::RGBA32F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT, EffectiveFormat::Luminance32FAlpha32F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE , LOCAL_GL_FLOAT, EffectiveFormat::Luminance32F);
- AddUnpackTuple(LOCAL_GL_ALPHA , LOCAL_GL_FLOAT, EffectiveFormat::Alpha32F);
+ // 'Virtual' effective formats have no sizedFormat.
+#define FOO(x) EffectiveFormat::x, #x, 0
- AddUnpackTuple(LOCAL_GL_RGB , LOCAL_GL_HALF_FLOAT, EffectiveFormat::RGB16F );
- AddUnpackTuple(LOCAL_GL_RGBA , LOCAL_GL_HALF_FLOAT, EffectiveFormat::RGBA16F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT, EffectiveFormat::Luminance16FAlpha16F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE , LOCAL_GL_HALF_FLOAT, EffectiveFormat::Luminance16F);
- AddUnpackTuple(LOCAL_GL_ALPHA , LOCAL_GL_HALF_FLOAT, EffectiveFormat::Alpha16F);
-
- // Everyone's favorite problem-child:
- AddUnpackTuple(LOCAL_GL_RGB , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGB16F );
- AddUnpackTuple(LOCAL_GL_RGBA , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::RGBA16F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::Luminance16FAlpha16F);
- AddUnpackTuple(LOCAL_GL_LUMINANCE , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::Luminance16F);
- AddUnpackTuple(LOCAL_GL_ALPHA , LOCAL_GL_HALF_FLOAT_OES, EffectiveFormat::Alpha16F);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-static void
-AddSizedFormat(GLenum sizedFormat, EffectiveFormat effectiveFormat)
-{
- const FormatInfo* info = GetFormatInfo_NoLock(effectiveFormat);
- MOZ_ASSERT(info);
-
- AlwaysInsert(gSizedFormatMap, sizedFormat, info);
-}
-
-static void
-InitSizedFormatMap()
-{
- // GLES 3.0.4, p128-129 "Required Texture Formats"
-
- // "Texture and renderbuffer color formats"
-#ifdef FOO
-#error FOO is already defined!
-#endif
-
-#define FOO(x) AddSizedFormat(LOCAL_GL_ ## x, EffectiveFormat::x)
+ // GLES 3.0.4, p128, table 3.12.
+ AddFormatInfo(FOO(Luminance8Alpha8), 2, UnsizedFormat::LA, false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(Luminance8 ), 1, UnsizedFormat::L , false, ComponentType::NormUInt);
+ AddFormatInfo(FOO(Alpha8 ), 1, UnsizedFormat::A , false, ComponentType::NormUInt);
- FOO(RGBA32I);
- FOO(RGBA32UI);
- FOO(RGBA16I);
- FOO(RGBA16UI);
- FOO(RGBA8);
- FOO(RGBA8I);
- FOO(RGBA8UI);
- FOO(SRGB8_ALPHA8);
- FOO(RGB10_A2);
- FOO(RGB10_A2UI);
- FOO(RGBA4);
- FOO(RGB5_A1);
-
- FOO(RGB8);
- FOO(RGB565);
-
- FOO(RG32I);
- FOO(RG32UI);
- FOO(RG16I);
- FOO(RG16UI);
- FOO(RG8);
- FOO(RG8I);
- FOO(RG8UI);
-
- FOO(R32I);
- FOO(R32UI);
- FOO(R16I);
- FOO(R16UI);
- FOO(R8);
- FOO(R8I);
- FOO(R8UI);
+ // OES_texture_float
+ AddFormatInfo(FOO(Luminance32FAlpha32F), 2, UnsizedFormat::LA, false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance32F ), 1, UnsizedFormat::L , false, ComponentType::Float);
+ AddFormatInfo(FOO(Alpha32F ), 1, UnsizedFormat::A , false, ComponentType::Float);
- // "Texture-only color formats"
- FOO(RGBA32F);
- FOO(RGBA16F);
- FOO(RGBA8_SNORM);
-
- FOO(RGB32F);
- FOO(RGB32I);
- FOO(RGB32UI);
-
- FOO(RGB16F);
- FOO(RGB16I);
- FOO(RGB16UI);
-
- FOO(RGB8_SNORM);
- FOO(RGB8I);
- FOO(RGB8UI);
- FOO(SRGB8);
-
- FOO(R11F_G11F_B10F);
- FOO(RGB9_E5);
-
- FOO(RG32F);
- FOO(RG16F);
- FOO(RG8_SNORM);
-
- FOO(R32F);
- FOO(R16F);
- FOO(R8_SNORM);
-
- // "Depth formats"
- FOO(DEPTH_COMPONENT32F);
- FOO(DEPTH_COMPONENT24);
- FOO(DEPTH_COMPONENT16);
-
- // "Combined depth+stencil formats"
- FOO(DEPTH32F_STENCIL8);
- FOO(DEPTH24_STENCIL8);
-
- // GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
- FOO(STENCIL_INDEX8);
+ // OES_texture_half_float
+ AddFormatInfo(FOO(Luminance16FAlpha16F), 2, UnsizedFormat::LA, false, ComponentType::Float);
+ AddFormatInfo(FOO(Luminance16F ), 1, UnsizedFormat::L , false, ComponentType::Float);
+ AddFormatInfo(FOO(Alpha16F ), 1, UnsizedFormat::A , false, ComponentType::Float);
#undef FOO
}
//////////////////////////////////////////////////////////////////////////////////////////
bool gAreFormatTablesInitialized = false;
static void
-EnsureInitFormatTables()
+EnsureInitFormatTables(const StaticMutexAutoLock&) // Prove that you locked it!
{
if (MOZ_LIKELY(gAreFormatTablesInitialized))
return;
gAreFormatTablesInitialized = true;
InitCompressedFormatInfo();
- InitFormatInfoMap();
- InitUnpackTupleMap();
- InitSizedFormatMap();
+ InitFormatInfo();
}
//////////////////////////////////////////////////////////////////////////////////////////
// Public funcs
StaticMutex gFormatMapMutex;
const FormatInfo*
-GetFormatInfo(EffectiveFormat format)
+GetFormat(EffectiveFormat format)
{
StaticMutexAutoLock lock(gFormatMapMutex);
- EnsureInitFormatTables();
+ EnsureInitFormatTables(lock);
return GetFormatInfo_NoLock(format);
}
-const FormatInfo*
-GetInfoByUnpackTuple(GLenum unpackFormat, GLenum unpackType)
+//////////////////////////////////////////////////////////////////////////////////////////
+
+uint8_t
+BytesPerPixel(const PackingInfo& packing)
{
- StaticMutexAutoLock lock(gFormatMapMutex);
- EnsureInitFormatTables();
+ uint8_t bytesPerChannel;
+ switch (packing.type) {
+ 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:
+ return 2;
+
+ case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+ case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+ case LOCAL_GL_UNSIGNED_INT_24_8:
+ case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
+ return 4;
+
+ case LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ return 8;
+
+ // Alright, that's all the fixed-size unpackTypes.
+
+ case LOCAL_GL_BYTE:
+ case LOCAL_GL_UNSIGNED_BYTE:
+ bytesPerChannel = 1;
+ break;
+
+ case LOCAL_GL_SHORT:
+ case LOCAL_GL_UNSIGNED_SHORT:
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+ bytesPerChannel = 2;
+ break;
- const UnpackTuple unpack = { unpackFormat, unpackType };
+ case LOCAL_GL_INT:
+ case LOCAL_GL_UNSIGNED_INT:
+ case LOCAL_GL_FLOAT:
+ bytesPerChannel = 4;
+ break;
+
+ default:
+ MOZ_CRASH("invalid PackingInfo");
+ }
- MOZ_ASSERT(!gUnpackTupleMap.empty());
- auto itr = gUnpackTupleMap.find(unpack);
- if (itr == gUnpackTupleMap.end())
- return nullptr;
+ uint8_t channels;
+ switch (packing.format) {
+ case LOCAL_GL_RG:
+ case LOCAL_GL_RG_INTEGER:
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ channels = 2;
+ break;
- return itr->second;
+ case LOCAL_GL_RGB:
+ case LOCAL_GL_RGB_INTEGER:
+ channels = 3;
+ break;
+
+ case LOCAL_GL_RGBA:
+ case LOCAL_GL_RGBA_INTEGER:
+ channels = 4;
+ break;
+
+ default:
+ channels = 1;
+ break;
+ }
+
+ return bytesPerChannel * channels;
}
-const FormatInfo*
-GetInfoBySizedFormat(GLenum sizedFormat)
-{
- StaticMutexAutoLock lock(gFormatMapMutex);
- EnsureInitFormatTables();
-
- MOZ_ASSERT(!gSizedFormatMap.empty());
- auto itr = gSizedFormatMap.find(sizedFormat);
- if (itr == gSizedFormatMap.end())
- return nullptr;
-
- return itr->second;
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-bool
-FormatUsageInfo::CanUnpackWith(GLenum unpackFormat, GLenum unpackType) const
-{
- const UnpackTuple key = { unpackFormat, unpackType };
- auto itr = validUnpacks.find(key);
- return itr != validUnpacks.end();
-}
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// FormatUsageAuthority
+void
+FormatUsageInfo::AddUnpack(const PackingInfo& key, const DriverUnpackInfo& value)
+{
+ auto itr = AlwaysInsert(validUnpacks, key, value);
+
+ if (!idealUnpack) {
+ // First one!
+ idealUnpack = &(itr->second);
+ }
+}
+
+bool
+FormatUsageInfo::IsUnpackValid(const PackingInfo& key,
+ const DriverUnpackInfo** const out_value) const
+{
+ auto itr = validUnpacks.find(key);
+ if (itr == validUnpacks.end())
+ return false;
+
+ *out_value = &(itr->second);
+ return true;
+}
+
+////////////////////////////////////////
+
+static inline void
+SetUsage(FormatUsageAuthority* fua, EffectiveFormat effFormat, bool isRenderable,
+ bool isFilterable)
+{
+ MOZ_ASSERT(!fua->GetUsage(effFormat));
+
+ auto usage = fua->EditUsage(effFormat);
+ usage->isRenderable = isRenderable;
+ usage->isFilterable = isFilterable;
+}
+
+static void
+AddLegacyFormats_LA8(FormatUsageAuthority* fua, gl::GLContext* gl)
+{
+ PackingInfo pi;
+ DriverUnpackInfo dui;
+
+ const auto fnAdd = [fua, &pi, &dui](EffectiveFormat effFormat) {
+ auto usage = fua->EditUsage(effFormat);
+ fua->AddUnsizedTexFormat(pi, usage);
+ usage->AddUnpack(pi, dui);
+ };
+
+ const bool isCore = gl->IsCoreProfile();
+
+ pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
+ if (isCore) dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
+ else dui = {LOCAL_GL_LUMINANCE, LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Luminance8);
+
+ pi = {LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ if (isCore) dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
+ else dui = {LOCAL_GL_ALPHA, LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Alpha8);
+
+ pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ if (isCore) dui = {LOCAL_GL_RG8, LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE};
+ else dui = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
+ fnAdd(EffectiveFormat::Luminance8Alpha8);
+}
+
+static void
+AddBasicUnsizedFormats(FormatUsageAuthority* fua, gl::GLContext* gl)
+{
+ const auto fnAddSimpleUnsized = [fua](GLenum unpackFormat, GLenum unpackType,
+ EffectiveFormat effFormat)
+ {
+ auto usage = fua->EditUsage(effFormat);
+
+ const PackingInfo pi = {unpackFormat, unpackType};
+ fua->AddUnsizedTexFormat(pi, usage);
+
+ const DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
+ usage->AddUnpack(pi, dui);
+ };
+
+ // GLES 2.0.25, p63, Table 3.4
+
+ fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
+ fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4 );
+ fnAddSimpleUnsized(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
+ fnAddSimpleUnsized(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
+ fnAddSimpleUnsized(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
+
+ // L, A, LA
+ AddLegacyFormats_LA8(fua, gl);
+}
+
UniquePtr<FormatUsageAuthority>
FormatUsageAuthority::CreateForWebGL1(gl::GLContext* gl)
{
UniquePtr<FormatUsageAuthority> ret(new FormatUsageAuthority);
+ const auto ptr = ret.get();
////////////////////////////////////////////////////////////////////////////
-
-#ifdef FOO
-#error FOO is already defined!
-#endif
-
-#define FOO(effFormat,rbFormat,isRenderable,texInternalFormat,texUnpackFormat,texUnpackType,isFilterable) \
- ret->AddFormat(EffectiveFormat::effFormat, LOCAL_GL_ ## rbFormat, isRenderable, \
- LOCAL_GL_ ## texInternalFormat, LOCAL_GL_ ## texUnpackFormat, \
- LOCAL_GL_ ## texUnpackType, isFilterable)
+ // Usages
// GLES 2.0.25, p117, Table 4.5
// RGBA8 is made renderable in WebGL 1.0, "Framebuffer Object Attachments"
- // | |render|tex internal |tex unpack | |filter
- // effective format |RB format |able |format |format |tex unpack type |able
+ // render filter
+ // able able
+ SetUsage(ptr, EffectiveFormat::RGBA8 , true , true);
+ SetUsage(ptr, EffectiveFormat::RGBA4 , true , true);
+ SetUsage(ptr, EffectiveFormat::RGB5_A1, true , true);
+ SetUsage(ptr, EffectiveFormat::RGB8 , false, true);
+ SetUsage(ptr, EffectiveFormat::RGB565 , true , true);
- FOO(RGBA8 , NONE , true , RGBA , RGBA , UNSIGNED_BYTE , true );
- FOO(RGBA4 , RGBA4 , true , RGBA , RGBA , UNSIGNED_SHORT_4_4_4_4, true );
- FOO(RGB5_A1 , RGB5_A1 , true , RGBA , RGBA , UNSIGNED_SHORT_5_5_5_1, true );
- FOO(RGB8 , NONE , false, RGB , RGB , UNSIGNED_BYTE , true );
- FOO(RGB565 , RGB565 , true , RGB , RGB , UNSIGNED_SHORT_5_6_5 , true );
+ SetUsage(ptr, EffectiveFormat::Luminance8Alpha8, false, true);
+ SetUsage(ptr, EffectiveFormat::Luminance8 , false, true);
+ SetUsage(ptr, EffectiveFormat::Alpha8 , false, true);
- FOO(Luminance8Alpha8 , NONE , false, LUMINANCE_ALPHA, LUMINANCE_ALPHA, UNSIGNED_BYTE , true );
- FOO(Luminance8 , NONE , false, LUMINANCE , LUMINANCE , UNSIGNED_BYTE , true );
- FOO(Alpha8 , NONE , false, ALPHA , ALPHA , UNSIGNED_BYTE , true );
-
- FOO(DEPTH_COMPONENT16, DEPTH_COMPONENT16, true , NONE , NONE , NONE , false);
- FOO(STENCIL_INDEX8 , STENCIL_INDEX8 , true , NONE , NONE , NONE , false);
+ SetUsage(ptr, EffectiveFormat::DEPTH_COMPONENT16, true, false);
+ SetUsage(ptr, EffectiveFormat::STENCIL_INDEX8 , true, false);
// Added in WebGL 1.0 spec:
- FOO(DEPTH24_STENCIL8 , DEPTH24_STENCIL8 , true , NONE , NONE , NONE , false);
+ SetUsage(ptr, EffectiveFormat::DEPTH24_STENCIL8, true, false);
+
+ ////////////////////////////////////
+ // RB formats
+
+#define FOO(x) ptr->AddRBFormat(LOCAL_GL_ ## x, ptr->GetUsage(EffectiveFormat::x))
+
+ FOO(RGBA4 );
+ FOO(RGB5_A1 );
+ FOO(RGB565 );
+ FOO(DEPTH_COMPONENT16);
+ FOO(STENCIL_INDEX8 );
+ //FOO(DEPTH24_STENCIL8 );
#undef FOO
+ ptr->AddRBFormat(LOCAL_GL_DEPTH_STENCIL,
+ ptr->GetUsage(EffectiveFormat::DEPTH24_STENCIL8));
+
////////////////////////////////////////////////////////////////////////////
- // GLES 2.0.25, p63, Table 3.4
-
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
- ret->AddUnpackOption(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
- ret->AddUnpackOption(LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
-
- ret->AddUnpackOption(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8Alpha8);
- ret->AddUnpackOption(LOCAL_GL_LUMINANCE , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8 );
- ret->AddUnpackOption(LOCAL_GL_ALPHA , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Alpha8 );
-
+ AddBasicUnsizedFormats(ptr, gl);
return Move(ret);
}
-static void
-AddES3TexFormat(FormatUsageAuthority* that, EffectiveFormat format, GLenum sizedFormat,
- bool isRenderable, GLenum unpackFormat, GLenum unpackType,
- bool isFilterable)
-{
- GLenum rbFormat = isRenderable ? sizedFormat : 0;
-
- that->AddFormat(format, rbFormat, isRenderable, sizedFormat, unpackFormat, unpackType,
- isFilterable);
-}
-
UniquePtr<FormatUsageAuthority>
-FormatUsageAuthority::CreateForWebGL2()
+FormatUsageAuthority::CreateForWebGL2(gl::GLContext* gl)
{
UniquePtr<FormatUsageAuthority> ret(new FormatUsageAuthority);
FormatUsageAuthority* const ptr = ret.get();
- ////////////////////////////////////////////////////////////////////////////
+ const auto fnAddES3TexFormat = [ptr](GLenum sizedFormat, EffectiveFormat effFormat,
+ bool isRenderable, bool isFilterable)
+ {
+ SetUsage(ptr, effFormat, isRenderable, isFilterable);
+ auto usage = ptr->GetUsage(effFormat);
+ ptr->AddSizedTexFormat(sizedFormat, usage);
-#ifdef FOO
-#error FOO is already defined!
-#endif
+ if (isRenderable) {
+ ptr->AddRBFormat(sizedFormat, usage);
+ }
+ };
-#define FOO(effFormat,sizedFormat,isRenderable,unpackFormat,unpackType,isFilterable) \
- AddES3TexFormat(ptr, EffectiveFormat::effFormat, LOCAL_GL_ ## sizedFormat, \
- isRenderable, LOCAL_GL_ ## unpackFormat, LOCAL_GL_ ## unpackType,\
- isFilterable)
+ ////////////////////////////////////////////////////////////////////////////
// For renderable, see GLES 3.0.4, p212 "Framebuffer Completeness"
// For filterable, see GLES 3.0.4, p161 "...a texture is complete unless..."
// GLES 3.0.4, p128-129 "Required Texture Formats"
// GLES 3.0.4, p130-132, table 3.13
- // | |render|tex internal |tex unpack | |filter
- // effective format |RB format |able |format |format |tex unpack type |able
-
- FOO(R8 , NONE , true , RGBA , RGBA , UNSIGNED_BYTE , true );
+#define FOO(x) LOCAL_GL_ ## x, EffectiveFormat::x
- // render filter
- // able able
- AddES3TexFormat(ptr, EffectiveFormat::R8 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::R8_SNORM , false, true );
- AddES3TexFormat(ptr, EffectiveFormat::RG8 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RG8_SNORM , false, true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB8 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB8_SNORM , false, true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB565 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGBA4 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB5_A1 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGBA8 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGBA8_SNORM, false, true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB10_A2 , true , true );
- AddES3TexFormat(ptr, EffectiveFormat::RGB10_A2UI , true , false);
+ // render filter
+ // able able
+ fnAddES3TexFormat(FOO(R8 ), true , true );
+ fnAddES3TexFormat(FOO(R8_SNORM ), false, true );
+ fnAddES3TexFormat(FOO(RG8 ), true , true );
+ fnAddES3TexFormat(FOO(RG8_SNORM ), false, true );
+ fnAddES3TexFormat(FOO(RGB8 ), true , true );
+ fnAddES3TexFormat(FOO(RGB8_SNORM ), false, true );
+ fnAddES3TexFormat(FOO(RGB565 ), true , true );
+ fnAddES3TexFormat(FOO(RGBA4 ), true , true );
+ fnAddES3TexFormat(FOO(RGB5_A1 ), true , true );
+ fnAddES3TexFormat(FOO(RGBA8 ), true , true );
+ fnAddES3TexFormat(FOO(RGBA8_SNORM), false, true );
+ fnAddES3TexFormat(FOO(RGB10_A2 ), true , true );
+ fnAddES3TexFormat(FOO(RGB10_A2UI ), true , false);
- AddES3TexFormat(ptr, EffectiveFormat::SRGB8 , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::SRGB8_ALPHA8, true , true);
+ fnAddES3TexFormat(FOO(SRGB8 ), false, true);
+ fnAddES3TexFormat(FOO(SRGB8_ALPHA8), true , true);
- AddES3TexFormat(ptr, EffectiveFormat::R16F , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::RG16F , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::RGB16F , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA16F, false, true);
+ fnAddES3TexFormat(FOO(R16F ), false, true);
+ fnAddES3TexFormat(FOO(RG16F ), false, true);
+ fnAddES3TexFormat(FOO(RGB16F ), false, true);
+ fnAddES3TexFormat(FOO(RGBA16F), false, true);
+
+ fnAddES3TexFormat(FOO(R32F ), false, false);
+ fnAddES3TexFormat(FOO(RG32F ), false, false);
+ fnAddES3TexFormat(FOO(RGB32F ), false, false);
+ fnAddES3TexFormat(FOO(RGBA32F), false, false);
- AddES3TexFormat(ptr, EffectiveFormat::R32F , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG32F , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB32F , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA32F, false, false);
+ fnAddES3TexFormat(FOO(R11F_G11F_B10F), false, true);
+ fnAddES3TexFormat(FOO(RGB9_E5 ), false, true);
- AddES3TexFormat(ptr, EffectiveFormat::R11F_G11F_B10F, false, true);
- AddES3TexFormat(ptr, EffectiveFormat::RGB9_E5 , false, true);
-
- AddES3TexFormat(ptr, EffectiveFormat::R8I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::R8UI , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::R16I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::R16UI, true, false);
- AddES3TexFormat(ptr, EffectiveFormat::R32I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::R32UI, true, false);
+ fnAddES3TexFormat(FOO(R8I ), true, false);
+ fnAddES3TexFormat(FOO(R8UI ), true, false);
+ fnAddES3TexFormat(FOO(R16I ), true, false);
+ fnAddES3TexFormat(FOO(R16UI), true, false);
+ fnAddES3TexFormat(FOO(R32I ), true, false);
+ fnAddES3TexFormat(FOO(R32UI), true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG8I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG8UI , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG16I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG16UI, true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG32I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RG32UI, true, false);
+ fnAddES3TexFormat(FOO(RG8I ), true, false);
+ fnAddES3TexFormat(FOO(RG8UI ), true, false);
+ fnAddES3TexFormat(FOO(RG16I ), true, false);
+ fnAddES3TexFormat(FOO(RG16UI), true, false);
+ fnAddES3TexFormat(FOO(RG32I ), true, false);
+ fnAddES3TexFormat(FOO(RG32UI), true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB8I , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB8UI , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB16I , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB16UI, false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB32I , false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGB32UI, false, false);
+ fnAddES3TexFormat(FOO(RGB8I ), false, false);
+ fnAddES3TexFormat(FOO(RGB8UI ), false, false);
+ fnAddES3TexFormat(FOO(RGB16I ), false, false);
+ fnAddES3TexFormat(FOO(RGB16UI), false, false);
+ fnAddES3TexFormat(FOO(RGB32I ), false, false);
+ fnAddES3TexFormat(FOO(RGB32UI), false, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA8I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA8UI , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA16I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA16UI, true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA32I , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::RGBA32UI, true, false);
+ fnAddES3TexFormat(FOO(RGBA8I ), true, false);
+ fnAddES3TexFormat(FOO(RGBA8UI ), true, false);
+ fnAddES3TexFormat(FOO(RGBA16I ), true, false);
+ fnAddES3TexFormat(FOO(RGBA16UI), true, false);
+ fnAddES3TexFormat(FOO(RGBA32I ), true, false);
+ fnAddES3TexFormat(FOO(RGBA32UI), true, false);
// GLES 3.0.4, p133, table 3.14
// GLES 3.0.4, p161 "...a texture is complete unless..."
- AddES3TexFormat(ptr, EffectiveFormat::DEPTH_COMPONENT16 , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::DEPTH_COMPONENT24 , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::DEPTH_COMPONENT32F, true, false);
- AddES3TexFormat(ptr, EffectiveFormat::DEPTH24_STENCIL8 , true, false);
- AddES3TexFormat(ptr, EffectiveFormat::DEPTH32F_STENCIL8 , true, false);
+ fnAddES3TexFormat(FOO(DEPTH_COMPONENT16 ), true, false);
+ fnAddES3TexFormat(FOO(DEPTH_COMPONENT24 ), true, false);
+ fnAddES3TexFormat(FOO(DEPTH_COMPONENT32F), true, false);
+ fnAddES3TexFormat(FOO(DEPTH24_STENCIL8 ), true, false);
+ fnAddES3TexFormat(FOO(DEPTH32F_STENCIL8 ), true, false);
// GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
- AddES3TexFormat(ptr, EffectiveFormat::STENCIL_INDEX8, true, false);
-
+ fnAddES3TexFormat(FOO(STENCIL_INDEX8), true, false);
+/*
// GLES 3.0.4, p128, table 3.12.
// Unsized RGBA/RGB formats are renderable, other unsized are not.
- AddES3TexFormat(ptr, EffectiveFormat::Luminance8Alpha8, false, true);
- AddES3TexFormat(ptr, EffectiveFormat::Luminance8 , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::Alpha8 , false, true);
-
+ fnAddES3TexFormat(FOO(Luminance8Alpha8, false, true);
+ fnAddES3TexFormat(FOO(Luminance8 , false, true);
+ fnAddES3TexFormat(FOO(Alpha8 , false, true);
+*/
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
// (jgilbert) I can't find where these are established as filterable.
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_RGB8_ETC2 , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_SRGB8_ETC2 , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_RGBA8_ETC2_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_R11_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_RG11_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_SIGNED_R11_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_SIGNED_RG11_EAC , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 , false, true);
- AddES3TexFormat(ptr, EffectiveFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_RGB8_ETC2 ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_SRGB8_ETC2 ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_RGBA8_ETC2_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_R11_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_RG11_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_SIGNED_R11_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_SIGNED_RG11_EAC ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), false, true);
+ fnAddES3TexFormat(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), false, true);
+
+#undef FOO
+
+ const auto fnAddSizedUnpack = [ptr](EffectiveFormat effFormat, GLenum internalFormat,
+ GLenum unpackFormat, GLenum unpackType)
+ {
+ auto usage = ptr->EditUsage(effFormat);
+
+ const PackingInfo pi = {unpackFormat, unpackType};
+ const DriverUnpackInfo dui = {internalFormat, unpackFormat, unpackType};
+ usage->AddUnpack(pi, dui);
+ };
+
+#define FOO(x) EffectiveFormat::x, LOCAL_GL_ ## x
////////////////////////////////////////////////////////////////////////////
// GLES 3.0.4 p111-113
// RGBA
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB5_A1 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA4 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::SRGB8_ALPHA8);
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_BYTE , EffectiveFormat::RGBA8_SNORM );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 , EffectiveFormat::RGBA4 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 , EffectiveFormat::RGB5_A1 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV, EffectiveFormat::RGB10_A2 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV, EffectiveFormat::RGB5_A1 );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT , EffectiveFormat::RGBA16F );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_FLOAT , EffectiveFormat::RGBA32F );
- ret->AddUnpackOption(LOCAL_GL_RGBA, LOCAL_GL_FLOAT , EffectiveFormat::RGBA16F );
+ fnAddSizedUnpack(FOO(RGBA8 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGBA4 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 );
+ fnAddSizedUnpack(FOO(RGBA4 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGB5_A1 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 );
+ fnAddSizedUnpack(FOO(RGB5_A1 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGB5_A1 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);
+ fnAddSizedUnpack(FOO(SRGB8_ALPHA8), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGBA8_SNORM ), LOCAL_GL_RGBA, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(RGB10_A2 ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);
+ fnAddSizedUnpack(FOO(RGBA16F ), LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(RGBA16F ), LOCAL_GL_RGBA, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(RGBA32F ), LOCAL_GL_RGBA, LOCAL_GL_FLOAT );
+
// RGBA_INTEGER
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGBA8UI );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_BYTE , EffectiveFormat::RGBA8I );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_SHORT , EffectiveFormat::RGBA16UI );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_SHORT , EffectiveFormat::RGBA16I );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::RGBA32UI );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT , EffectiveFormat::RGBA32I );
- ret->AddUnpackOption(LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV, EffectiveFormat::RGB10_A2UI);
+ fnAddSizedUnpack(FOO(RGBA8UI ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGBA8I ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(RGBA16UI ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_SHORT );
+ fnAddSizedUnpack(FOO(RGBA16I ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_SHORT );
+ fnAddSizedUnpack(FOO(RGBA32UI ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(RGBA32I ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT );
+ fnAddSizedUnpack(FOO(RGB10_A2UI), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);
// RGB
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB565 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::SRGB8 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_BYTE , EffectiveFormat::RGB8_SNORM );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5 , EffectiveFormat::RGB565 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV, EffectiveFormat::R11F_G11F_B10F);
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV , EffectiveFormat::RGB9_E5 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT , EffectiveFormat::RGB16F );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT , EffectiveFormat::R11F_G11F_B10F);
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT , EffectiveFormat::RGB9_E5 );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_FLOAT , EffectiveFormat::RGB32F );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_FLOAT , EffectiveFormat::RGB16F );
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_FLOAT , EffectiveFormat::R11F_G11F_B10F);
- ret->AddUnpackOption(LOCAL_GL_RGB, LOCAL_GL_FLOAT , EffectiveFormat::RGB9_E5 );
+ fnAddSizedUnpack(FOO(RGB8 ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(SRGB8 ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGB565 ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5 );
+ fnAddSizedUnpack(FOO(RGB565 ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGB8_SNORM ), LOCAL_GL_RGB, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV);
+ fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(RGB16F ), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(RGB16F ), LOCAL_GL_RGB, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(RGB9_E5 ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV );
+ fnAddSizedUnpack(FOO(RGB9_E5 ), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(RGB9_E5 ), LOCAL_GL_RGB, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(RGB32F ), LOCAL_GL_RGB, LOCAL_GL_FLOAT );
// RGB_INTEGER
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RGB8UI );
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_BYTE , EffectiveFormat::RGB8I );
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_SHORT, EffectiveFormat::RGB16UI);
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_SHORT , EffectiveFormat::RGB16I );
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::RGB32UI);
- ret->AddUnpackOption(LOCAL_GL_RGB_INTEGER, LOCAL_GL_INT , EffectiveFormat::RGB32I );
-
+ fnAddSizedUnpack(FOO(RGB8UI ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RGB8I ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(RGB16UI), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
+ fnAddSizedUnpack(FOO(RGB16I ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_SHORT );
+ fnAddSizedUnpack(FOO(RGB32UI), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(RGB32I ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_INT );
// RG
- ret->AddUnpackOption(LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::RG8 );
- ret->AddUnpackOption(LOCAL_GL_RG, LOCAL_GL_BYTE , EffectiveFormat::RG8_SNORM);
- ret->AddUnpackOption(LOCAL_GL_RG, LOCAL_GL_HALF_FLOAT , EffectiveFormat::RG16F );
- ret->AddUnpackOption(LOCAL_GL_RG, LOCAL_GL_FLOAT , EffectiveFormat::RG32F );
- ret->AddUnpackOption(LOCAL_GL_RG, LOCAL_GL_FLOAT , EffectiveFormat::RG16F );
+ fnAddSizedUnpack(FOO(RG8 ), LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE);
+ fnAddSizedUnpack(FOO(RG8_SNORM), LOCAL_GL_RG, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(RG16F ), LOCAL_GL_RG, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(RG16F ), LOCAL_GL_RG, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(RG32F ), LOCAL_GL_RG, LOCAL_GL_FLOAT );
// RG_INTEGER
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::RG8UI );
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_BYTE , EffectiveFormat::RG8I );
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_SHORT, EffectiveFormat::RG16UI);
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_SHORT , EffectiveFormat::RG16I );
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::RG32UI);
- ret->AddUnpackOption(LOCAL_GL_RG_INTEGER, LOCAL_GL_INT , EffectiveFormat::RG32I );
+ fnAddSizedUnpack(FOO(RG8UI ), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(RG8I ), LOCAL_GL_RG_INTEGER, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(RG16UI), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
+ fnAddSizedUnpack(FOO(RG16I ), LOCAL_GL_RG_INTEGER, LOCAL_GL_SHORT );
+ fnAddSizedUnpack(FOO(RG32UI), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(RG32I ), LOCAL_GL_RG_INTEGER, LOCAL_GL_INT );
// RED
- ret->AddUnpackOption(LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::R8 );
- ret->AddUnpackOption(LOCAL_GL_RED, LOCAL_GL_BYTE , EffectiveFormat::R8_SNORM);
- ret->AddUnpackOption(LOCAL_GL_RED, LOCAL_GL_HALF_FLOAT , EffectiveFormat::R16F );
- ret->AddUnpackOption(LOCAL_GL_RED, LOCAL_GL_FLOAT , EffectiveFormat::R32F );
- ret->AddUnpackOption(LOCAL_GL_RED, LOCAL_GL_FLOAT , EffectiveFormat::R16F );
+ fnAddSizedUnpack(FOO(R8 ), LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE);
+ fnAddSizedUnpack(FOO(R8_SNORM), LOCAL_GL_RED, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(R16F ), LOCAL_GL_RED, LOCAL_GL_HALF_FLOAT );
+ fnAddSizedUnpack(FOO(R16F ), LOCAL_GL_RED, LOCAL_GL_FLOAT );
+ fnAddSizedUnpack(FOO(R32F ), LOCAL_GL_RED, LOCAL_GL_FLOAT );
// RED_INTEGER
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_BYTE , EffectiveFormat::R8UI );
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_BYTE , EffectiveFormat::R8I );
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_SHORT, EffectiveFormat::R16UI);
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_SHORT , EffectiveFormat::R16I );
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::R32UI);
- ret->AddUnpackOption(LOCAL_GL_RED_INTEGER, LOCAL_GL_INT , EffectiveFormat::R32I );
+ fnAddSizedUnpack(FOO(R8UI ), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
+ fnAddSizedUnpack(FOO(R8I ), LOCAL_GL_RED_INTEGER, LOCAL_GL_BYTE );
+ fnAddSizedUnpack(FOO(R16UI), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
+ fnAddSizedUnpack(FOO(R16I ), LOCAL_GL_RED_INTEGER, LOCAL_GL_SHORT );
+ fnAddSizedUnpack(FOO(R32UI), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(R32I ), LOCAL_GL_RED_INTEGER, LOCAL_GL_INT );
// DEPTH_COMPONENT
- ret->AddUnpackOption(LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_SHORT, EffectiveFormat::DEPTH_COMPONENT16 );
- ret->AddUnpackOption(LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::DEPTH_COMPONENT24 );
- ret->AddUnpackOption(LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT , EffectiveFormat::DEPTH_COMPONENT16 );
- ret->AddUnpackOption(LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_FLOAT , EffectiveFormat::DEPTH_COMPONENT32F);
+ fnAddSizedUnpack(FOO(DEPTH_COMPONENT16 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_SHORT);
+ fnAddSizedUnpack(FOO(DEPTH_COMPONENT16 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(DEPTH_COMPONENT24 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT );
+ fnAddSizedUnpack(FOO(DEPTH_COMPONENT32F), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_FLOAT );
// DEPTH_STENCIL
- ret->AddUnpackOption(LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_UNSIGNED_INT_24_8 , EffectiveFormat::DEPTH24_STENCIL8 );
- ret->AddUnpackOption(LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV, EffectiveFormat::DEPTH32F_STENCIL8);
+ fnAddSizedUnpack(FOO(DEPTH24_STENCIL8 ), LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_UNSIGNED_INT_24_8 );
+ fnAddSizedUnpack(FOO(DEPTH32F_STENCIL8), LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
- // Unsized formats
- ret->AddUnpackOption(LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8Alpha8);
- ret->AddUnpackOption(LOCAL_GL_LUMINANCE , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8 );
- ret->AddUnpackOption(LOCAL_GL_ALPHA , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Alpha8 );
+#undef FOO
+
+ AddBasicUnsizedFormats(ptr, gl);
return Move(ret);
}
//////////////////////////////////////////////////////////////////////////////////////////
-FormatUsageInfo*
-FormatUsageAuthority::GetUsage(EffectiveFormat format)
+void
+FormatUsageAuthority::AddRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage)
+{
+ AlwaysInsert(mRBFormatMap, sizedFormat, usage);
+}
+
+void
+FormatUsageAuthority::AddSizedTexFormat(GLenum sizedFormat, const FormatUsageInfo* usage)
+{
+ AlwaysInsert(mSizedTexFormatMap, sizedFormat, usage);
+}
+
+void
+FormatUsageAuthority::AddUnsizedTexFormat(const PackingInfo& pi,
+ const FormatUsageInfo* usage)
+{
+ AlwaysInsert(mUnsizedTexFormatMap, pi, usage);
+}
+
+const FormatUsageInfo*
+FormatUsageAuthority::GetRBUsage(GLenum sizedFormat) const
+{
+ return FindOrNull(mRBFormatMap, sizedFormat);
+}
+
+const FormatUsageInfo*
+FormatUsageAuthority::GetSizedTexUsage(GLenum sizedFormat) const
{
- auto itr = mInfoMap.find(format);
+ return FindOrNull(mSizedTexFormatMap, sizedFormat);
+}
+
+const FormatUsageInfo*
+FormatUsageAuthority::GetUnsizedTexUsage(const PackingInfo& pi) const
+{
+ return FindOrNull(mUnsizedTexFormatMap, pi);
+}
+
+FormatUsageInfo*
+FormatUsageAuthority::EditUsage(EffectiveFormat format)
+{
+ auto itr = mUsageMap.find(format);
- if (itr == mInfoMap.end())
+ if (itr == mUsageMap.end()) {
+ const FormatInfo* formatInfo = GetFormat(format);
+ MOZ_RELEASE_ASSERT(formatInfo);
+
+ FormatUsageInfo usage(formatInfo);
+ itr = AlwaysInsert(mUsageMap, format, usage);
+ }
+
+ return &(itr->second);
+}
+
+const FormatUsageInfo*
+FormatUsageAuthority::GetUsage(EffectiveFormat format) const
+{
+ auto itr = mUsageMap.find(format);
+ if (itr == mUsageMap.end())
return nullptr;
return &(itr->second);
}
-void
-FormatUsageAuthority::AddFormat(EffectiveFormat format, GLenum rbInternalFormat,
- bool isRenderable, GLenum texInternalFormat,
- bool isFilterable)
-{
- MOZ_ASSERT_IF(rbInternalFormat, isRenderable);
- MOZ_ASSERT_IF(isFilterable, texInternalFormat);
-
- const FormatInfo* formatInfo = GetFormatInfo(format);
- MOZ_RELEASE_ASSERT(formatInfo);
-
- FormatUsageInfo usage = { formatInfo, rbInternalFormat, isRenderable,
- texInternalFormat, isFilterable, std::set<UnpackTuple>() };
- AlwaysInsert(mInfoMap, format, usage);
-}
-
-void
-FormatUsageAuthority::AddUnpackOption(GLenum unpackFormat, GLenum unpackType,
- EffectiveFormat effectiveFormat)
-{
- const UnpackTuple unpack = { unpackFormat, unpackType };
- FormatUsageInfo* usage = GetUsage(effectiveFormat);
- MOZ_RELEASE_ASSERT(usage);
- if (!usage)
- return;
-
- MOZ_RELEASE_ASSERT(usage->asTexture);
-
- auto res = usage->validUnpacks.insert(unpack);
- bool didInsert = res.second;
- MOZ_ALWAYS_TRUE(didInsert);
-}
-
////////////////////////////////////////////////////////////////////////////////
-struct ComponentSizes
-{
- GLubyte redSize;
- GLubyte greenSize;
- GLubyte blueSize;
- GLubyte alphaSize;
- GLubyte depthSize;
- GLubyte stencilSize;
-};
-
-static ComponentSizes kComponentSizes[] = {
- // GLES 3.0.4, p128-129, "Required Texture Formats"
- // "Texture and renderbuffer color formats"
- { 32, 32, 32, 32, 0, 0 }, // RGBA32I,
- { 32, 32, 32, 32, 0, 0 }, // RGBA32UI,
- { 16, 16, 16, 16, 0, 0 }, // RGBA16I,
- { 16, 16, 16, 16, 0, 0 }, // RGBA16UI,
- { 8, 8, 8, 8, 0, 0 }, // RGBA8,
- { 8, 8, 8, 8, 0, 0 }, // RGBA8I,
- { 8, 8, 8, 8, 0, 0 }, // RGBA8UI,
- { 8, 8, 8, 8, 0, 0 }, // SRGB8_ALPHA8,
- { 10, 10, 10, 2, 0, 0 }, // RGB10_A2,
- { 10, 10, 10, 2, 0, 0 }, // RGB10_A2UI,
- { 4, 4, 4, 4, 0, 0 }, // RGBA4,
- { 5, 5, 5, 1, 0, 0 }, // RGB5_A1,
-
- { 8, 8, 8, 0, 0, 0 }, // RGB8,
- { 8, 8, 8, 0, 0, 0 }, // RGB565,
-
- { 32, 32, 0, 0, 0, 0 }, // RG32I,
- { 32, 32, 0, 0, 0, 0 }, // RG32UI,
- { 16, 16, 0, 0, 0, 0 }, // RG16I,
- { 16, 16, 0, 0, 0, 0 }, // RG16UI,
- { 8, 8, 0, 0, 0, 0 }, // RG8,
- { 8, 8, 0, 0, 0, 0 }, // RG8I,
- { 8, 8, 0, 0, 0, 0 }, // RG8UI,
-
- { 32, 0, 0, 0, 0, 0 }, // R32I,
- { 32, 0, 0, 0, 0, 0 }, // R32UI,
- { 16, 0, 0, 0, 0, 0 }, // R16I,
- { 16, 0, 0, 0, 0, 0 }, // R16UI,
- { 8, 0, 0, 0, 0, 0 }, // R8,
- { 8, 0, 0, 0, 0, 0 }, // R8I,
- { 8, 0, 0, 0, 0, 0 }, // R8UI,
-
- // "Texture-only color formats"
- { 32, 32, 32, 32, 0, 0 }, // RGBA32F,
- { 16, 16, 16, 16, 0, 0 }, // RGBA16F,
- { 8, 8, 8, 8, 0, 0 }, // RGBA8_SNORM,
-
- { 32, 32, 32, 0, 0, 0 }, // RGB32F,
- { 32, 32, 32, 0, 0, 0 }, // RGB32I,
- { 32, 32, 32, 0, 0, 0 }, // RGB32UI,
-
- { 16, 16, 16, 0, 0, 0 }, // RGB16F,
- { 16, 16, 16, 0, 0, 0 }, // RGB16I,
- { 16, 16, 16, 0, 0, 0 }, // RGB16UI,
-
- { 8, 8, 8, 0, 0, 0 }, // RGB8_SNORM,
- { 8, 8, 8, 0, 0, 0 }, // RGB8I,
- { 8, 8, 8, 0, 0, 0 }, // RGB8UI,
- { 8, 8, 8, 0, 0, 0 }, // SRGB8,
-
- { 11, 11, 11, 0, 0, 0 }, // R11F_G11F_B10F,
- { 9, 9, 9, 0, 0, 0 }, // RGB9_E5,
-
- { 32, 32, 0, 0, 0, 0 }, // RG32F,
- { 16, 16, 0, 0, 0, 0 }, // RG16F,
- { 8, 8, 0, 0, 0, 0 }, // RG8_SNORM,
-
- { 32, 0, 0, 0, 0, 0 }, // R32F,
- { 16, 0, 0, 0, 0, 0 }, // R16F,
- { 8, 0, 0, 0, 0, 0 }, // R8_SNORM,
-
- // "Depth formats"
- { 0, 0, 0, 0, 32, 0 }, // DEPTH_COMPONENT32F,
- { 0, 0, 0, 0, 24, 0 }, // DEPTH_COMPONENT24,
- { 0, 0, 0, 0, 16, 0 }, // DEPTH_COMPONENT16,
-
- // "Combined depth+stencil formats"
- { 0, 0, 0, 0, 32, 8 }, // DEPTH32F_STENCIL0,
- { 0, 0, 0, 0, 24, 8 }, // DEPTH24_STENCIL8,
-
- // GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
- { 0, 0, 0, 0, 0, 8 }, // STENCIL_INDEX8,
-
- // GLES 3.0.4, p128, table 3.12.
- { 8, 8, 8, 8, 0, 0 }, // Luminance8Alpha8,
- { 8, 8, 8, 0, 0, 0 }, // Luminance8,
- { 0, 0, 0, 8, 0, 0 }, // Alpha8,
-
- // GLES 3.0.4, p147, table 3.19
- // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_R11_EAC,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_SIGNED_R11_EAC,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RG11_EAC,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_SIGNED_RG11_EAC,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGB8_ETC2,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_SRGB8_ETC2,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA8_ETC2_EAC,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
-
- // AMD_compressed_ATC_texture
- { 8, 8, 8, 0, 0, 0 }, // ATC_RGB_AMD,
- { 8, 8, 8, 8, 0, 0 }, // ATC_RGBA_EXPLICIT_ALPHA_AMD,
- { 8, 8, 8, 8, 0, 0 }, // ATC_RGBA_INTERPOLATED_ALPHA_AMD,
-
- // EXT_texture_compression_s3tc
- { 8, 8, 8, 0, 0, 0 }, // COMPRESSED_RGB_S3TC_DXT1,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA_S3TC_DXT1,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA_S3TC_DXT3,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA_S3TC_DXT5,
-
- // IMG_texture_compression_pvrtc
- { 8, 8, 8, 0, 0, 0 }, // COMPRESSED_RGB_PVRTC_4BPPV1,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA_PVRTC_4BPPV1,
- { 8, 8, 8, 0, 0, 0 }, // COMPRESSED_RGB_PVRTC_2BPPV1,
- { 8, 8, 8, 8, 0, 0 }, // COMPRESSED_RGBA_PVRTC_2BPPV1,
-
- // OES_compressed_ETC1_RGB8_texture
- { 8, 8, 8, 0, 0, 0 }, // ETC1_RGB8,
-
- // OES_texture_float
- { 32, 32, 32, 32, 0, 0 }, // Luminance32FAlpha32F,
- { 32, 32, 32, 0, 0, 0 }, // Luminance32F,
- { 0, 0, 0, 32, 0, 0 }, // Alpha32F,
-
- // OES_texture_half_float
- { 16, 16, 16, 16, 0, 0 }, // Luminance16FAlpha16F,
- { 16, 16, 16, 0, 0, 0 }, // Luminance16F,
- { 0, 0, 0, 16, 0, 0 }, // Alpha16F,
-
- { 0, } // MAX
-};
-
-GLint
-GetComponentSize(EffectiveFormat format, GLenum component)
-{
- ComponentSizes compSize = kComponentSizes[(int) format];
- switch (component) {
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
- case LOCAL_GL_RENDERBUFFER_RED_SIZE:
- case LOCAL_GL_RED_BITS:
- return compSize.redSize;
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
- case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
- case LOCAL_GL_GREEN_BITS:
- return compSize.greenSize;
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
- case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
- case LOCAL_GL_BLUE_BITS:
- return compSize.blueSize;
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
- case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
- case LOCAL_GL_ALPHA_BITS:
- return compSize.alphaSize;
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
- case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
- case LOCAL_GL_DEPTH_BITS:
- return compSize.depthSize;
- case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
- case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
- case LOCAL_GL_STENCIL_BITS:
- return compSize.stencilSize;
- }
-
- return 0;
-}
-
-static GLenum kComponentTypes[] = {
- // GLES 3.0.4, p128-129, "Required Texture Formats"
- // "Texture and renderbuffer color formats"
- LOCAL_GL_INT, // RGBA32I,
- LOCAL_GL_UNSIGNED_INT, // RGBA32UI,
- LOCAL_GL_INT, // RGBA16I,
- LOCAL_GL_UNSIGNED_INT, // RGBA16UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGBA8,
- LOCAL_GL_INT, // RGBA8I,
- LOCAL_GL_UNSIGNED_INT, // RGBA8UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // SRGB8_ALPHA8,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGB10_A2,
- LOCAL_GL_UNSIGNED_INT, // RGB10_A2UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGBA4,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGB5_A1,
-
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGB8,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RGB565,
-
- LOCAL_GL_INT, // RG32I,
- LOCAL_GL_UNSIGNED_INT, // RG32UI,
- LOCAL_GL_INT, // RG16I,
- LOCAL_GL_UNSIGNED_INT, // RG16UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // RG8,
- LOCAL_GL_INT, // RG8I,
- LOCAL_GL_UNSIGNED_INT, // RG8UI,
-
- LOCAL_GL_INT, // R32I,
- LOCAL_GL_UNSIGNED_INT, // R32UI,
- LOCAL_GL_INT, // R16I,
- LOCAL_GL_UNSIGNED_INT, // R16UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // R8,
- LOCAL_GL_INT, // R8I,
- LOCAL_GL_UNSIGNED_INT, // R8UI,
-
- // "Texture-only color formats"
- LOCAL_GL_FLOAT, // RGBA32F,
- LOCAL_GL_FLOAT, // RGBA16F,
- LOCAL_GL_SIGNED_NORMALIZED, // RGBA8_SNORM,
-
- LOCAL_GL_FLOAT, // RGB32F,
- LOCAL_GL_INT, // RGB32I,
- LOCAL_GL_UNSIGNED_INT, // RGB32UI,
-
- LOCAL_GL_FLOAT, // RGB16F,
- LOCAL_GL_INT, // RGB16I,
- LOCAL_GL_UNSIGNED_INT, // RGB16UI,
-
- LOCAL_GL_SIGNED_NORMALIZED, // RGB8_SNORM,
- LOCAL_GL_INT, // RGB8I,
- LOCAL_GL_UNSIGNED_INT, // RGB8UI,
- LOCAL_GL_UNSIGNED_NORMALIZED, // SRGB8,
-
- LOCAL_GL_FLOAT, // R11F_G11F_B10F,
- LOCAL_GL_FLOAT, // RGB9_E5,
-
- LOCAL_GL_FLOAT, // RG32F,
- LOCAL_GL_FLOAT, // RG16F,
- LOCAL_GL_SIGNED_NORMALIZED, // RG8_SNORM,
-
- LOCAL_GL_FLOAT, // R32F,
- LOCAL_GL_FLOAT, // R16F,
- LOCAL_GL_SIGNED_NORMALIZED, // R8_SNORM,
-
- // "Depth formats"
- LOCAL_GL_FLOAT, // DEPTH_COMPONENT32F,
- LOCAL_GL_UNSIGNED_NORMALIZED, // DEPTH_COMPONENT24,
- LOCAL_GL_UNSIGNED_NORMALIZED, // DEPTH_COMPONENT16,
-
- // "Combined depth+stencil formats"
- LOCAL_GL_FLOAT, // DEPTH32F_STENCIL8,
- LOCAL_GL_UNSIGNED_NORMALIZED, // DEPTH24_STENCIL8,
-
- // GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
- LOCAL_GL_UNSIGNED_NORMALIZED, // STENCIL_INDEX8,
-
- // GLES 3.0.4, p128, table 3.12.
- LOCAL_GL_UNSIGNED_NORMALIZED, // Luminance8Alpha8,
- LOCAL_GL_UNSIGNED_NORMALIZED, // Luminance8,
- LOCAL_GL_UNSIGNED_NORMALIZED, // Alpha8,
-
- // GLES 3.0.4, p147, table 3.19
- // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_R11_EAC,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_SIGNED_R11_EAC,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RG11_EAC,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_SIGNED_RG11_EAC,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGB8_ETC2,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_SRGB8_ETC2,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA8_ETC2_EAC,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
-
- // AMD_compressed_ATC_texture
- LOCAL_GL_UNSIGNED_NORMALIZED, // ATC_RGB_AMD,
- LOCAL_GL_UNSIGNED_NORMALIZED, // ATC_RGBA_EXPLICIT_ALPHA_AMD,
- LOCAL_GL_UNSIGNED_NORMALIZED, // ATC_RGBA_INTERPOLATED_ALPHA_AMD,
-
- // EXT_texture_compression_s3tc
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGB_S3TC_DXT1,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA_S3TC_DXT1,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA_S3TC_DXT3,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA_S3TC_DXT5,
-
- // IMG_texture_compression_pvrtc
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGB_PVRTC_4BPPV1,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA_PVRTC_4BPPV1,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGB_PVRTC_2BPPV1,
- LOCAL_GL_UNSIGNED_NORMALIZED, // COMPRESSED_RGBA_PVRTC_2BPPV1,
-
- // OES_compressed_ETC1_RGB8_texture
- LOCAL_GL_UNSIGNED_NORMALIZED, // ETC1_RGB8,
-
- // OES_texture_float
- LOCAL_GL_FLOAT, // Luminance32FAlpha32F,
- LOCAL_GL_FLOAT, // Luminance32F,
- LOCAL_GL_FLOAT, // Alpha32F,
-
- // OES_texture_half_float
- LOCAL_GL_FLOAT, // Luminance16FAlpha16F,
- LOCAL_GL_FLOAT, // Luminance16F,
- LOCAL_GL_FLOAT, // Alpha16F,
-
- LOCAL_GL_NONE // MAX
-};
-
-GLenum
-GetComponentType(EffectiveFormat format)
-{
- return kComponentTypes[(int) format];
-}
-
-GLenum
-GetColorEncoding(EffectiveFormat format)
-{
- const bool isSRGB = (GetFormatInfo(format)->colorComponentType ==
- ComponentType::NormUIntSRGB);
- return (isSRGB) ? LOCAL_GL_SRGB : LOCAL_GL_LINEAR;
-}
-
} // namespace webgl
} // namespace mozilla
--- a/dom/canvas/WebGLFormats.h
+++ b/dom/canvas/WebGLFormats.h
@@ -88,20 +88,17 @@ enum class EffectiveFormat : EffectiveFo
// "Combined depth+stencil formats"
DEPTH32F_STENCIL8,
DEPTH24_STENCIL8,
// GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
STENCIL_INDEX8,
- // GLES 3.0.4, p128, table 3.12.
- Luminance8Alpha8,
- Luminance8,
- Alpha8,
+ ////////////////////////////////////
// GLES 3.0.4, p147, table 3.19
// GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
COMPRESSED_R11_EAC,
COMPRESSED_SIGNED_R11_EAC,
COMPRESSED_RG11_EAC,
COMPRESSED_SIGNED_RG11_EAC,
COMPRESSED_RGB8_ETC2,
@@ -112,29 +109,36 @@ enum class EffectiveFormat : EffectiveFo
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
// AMD_compressed_ATC_texture
ATC_RGB_AMD,
ATC_RGBA_EXPLICIT_ALPHA_AMD,
ATC_RGBA_INTERPOLATED_ALPHA_AMD,
// EXT_texture_compression_s3tc
- COMPRESSED_RGB_S3TC_DXT1,
- COMPRESSED_RGBA_S3TC_DXT1,
- COMPRESSED_RGBA_S3TC_DXT3,
- COMPRESSED_RGBA_S3TC_DXT5,
+ COMPRESSED_RGB_S3TC_DXT1_EXT,
+ COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ COMPRESSED_RGBA_S3TC_DXT3_EXT,
+ COMPRESSED_RGBA_S3TC_DXT5_EXT,
// IMG_texture_compression_pvrtc
COMPRESSED_RGB_PVRTC_4BPPV1,
COMPRESSED_RGBA_PVRTC_4BPPV1,
COMPRESSED_RGB_PVRTC_2BPPV1,
COMPRESSED_RGBA_PVRTC_2BPPV1,
// OES_compressed_ETC1_RGB8_texture
- ETC1_RGB8,
+ ETC1_RGB8_OES,
+
+ ////////////////////////////////////
+
+ // GLES 3.0.4, p128, table 3.12.
+ Luminance8Alpha8,
+ Luminance8,
+ Alpha8,
// OES_texture_float
Luminance32FAlpha32F,
Luminance32F,
Alpha32F,
// OES_texture_half_float
Luminance16FAlpha16F,
@@ -152,127 +156,147 @@ enum class UnsizedFormat : uint8_t {
LA,
L,
A,
D,
S,
DS,
};
-// GLES 3.0.4 p114 Table 3.4
+// GLES 3.0.4 p114 Table 3.4, p240
enum class ComponentType : uint8_t {
- None, // DEPTH_COMPONENT32F
+ None, // DEPTH24_STENCIL8
Int, // RGBA32I
- UInt, // RGBA32UI
+ UInt, // RGBA32UI, STENCIL_INDEX8
NormInt, // RGBA8_SNORM
- NormUInt, // RGBA8
- NormUIntSRGB, // SRGB8_ALPHA8
+ NormUInt, // RGBA8, DEPTH_COMPONENT16
Float, // RGBA32F
- SharedExp, // RGB9_E5
};
-enum class SubImageUpdateBehavior : uint8_t {
- Forbidden,
- FullOnly,
- BlockAligned,
+enum class CompressionFamily : uint8_t {
+ ETC1,
+ ES3, // ETC2 or EAC
+ ATC,
+ S3TC,
+ PVRTC,
};
////////////////////////////////////////////////////////////////////////////////
-struct CompressedFormatInfo {
+struct CompressedFormatInfo
+{
const EffectiveFormat effectiveFormat;
const uint8_t bytesPerBlock;
const uint8_t blockWidth;
const uint8_t blockHeight;
- const bool requirePOT;
- const SubImageUpdateBehavior subImageUpdateBehavior;
+ const CompressionFamily family;
};
-struct FormatInfo {
+struct FormatInfo
+{
const EffectiveFormat effectiveFormat;
const char* const name;
+ const GLenum sizedFormat;
const UnsizedFormat unsizedFormat;
- const ComponentType colorComponentType;
- const uint8_t bytesPerPixel; // 0 iff `!!compression`.
- const bool isColorFormat; // This *does* include alpha-only formats.
- const bool hasAlpha;
+ const ComponentType componentType;
+ const uint8_t estimatedBytesPerPixel; // 0 iff `!!compression`. Only use this for
+ const bool isColorFormat; // memory usage estimation. Use
+ const bool isSRGB; // BytesPerPixel(packingFormat, packingType) for
+ const bool hasAlpha; // calculating pack/unpack byte count.
const bool hasDepth;
const bool hasStencil;
const CompressedFormatInfo* const compression;
};
-//////////////////////////////////////////////////////////////////////////////////////////
-
-const FormatInfo* GetFormatInfo(EffectiveFormat format);
-const FormatInfo* GetInfoByUnpackTuple(GLenum unpackFormat, GLenum unpackType);
-const FormatInfo* GetInfoBySizedFormat(GLenum sizedFormat);
-
-////////////////////////////////////////
+struct PackingInfo
+{
+ GLenum format;
+ GLenum type;
-struct UnpackTuple {
- const GLenum format;
- const GLenum type;
-
- bool operator <(const UnpackTuple& x) const
+ bool operator <(const PackingInfo& x) const
{
- if (format == x.format) {
- return type < x.type;
- }
+ if (format != x.format)
+ return format < x.format;
- return format < x.format;
+ return type < x.type;
}
};
-struct FormatUsageInfo {
- const FormatInfo* const formatInfo;
+struct DriverUnpackInfo
+{
+ GLenum internalFormat;
+ GLenum unpackFormat;
+ GLenum unpackType;
+};
- GLenum rbInternalFormat;
- bool isRenderable;
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const FormatInfo* GetFormat(EffectiveFormat format);
+uint8_t BytesPerPixel(const PackingInfo& packing);
+/*
+GLint ComponentSize(const FormatInfo* format, GLenum component);
+GLenum ComponentType(const FormatInfo* format);
+*/
+////////////////////////////////////////
- GLenum texInternalFormat;
- GLenum nativeUnpackFormat;
- GLenum nativeUnpackType;
+struct FormatUsageInfo
+{
+ const FormatInfo* const format;
+ bool isRenderable;
bool isFilterable;
+ std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
+ const DriverUnpackInfo* idealUnpack;
+ //const GLint* textureSwizzleRGBA;
- std::set<UnpackTuple> validUnpacks;
+ FormatUsageInfo(const FormatInfo* _format)
+ : format(_format)
+ , isRenderable(false)
+ , isFilterable(false)
+ , idealUnpack(nullptr)
+ { }
- bool CanUnpackWith(GLenum unpackFormat, GLenum unpackType) const;
+ void AddUnpack(const PackingInfo& key, const DriverUnpackInfo& value);
+ bool IsUnpackValid(const PackingInfo& key,
+ const DriverUnpackInfo** const out_value) const;
};
class FormatUsageAuthority
{
- std::map<EffectiveFormat, FormatUsageInfo> mInfoMap;
+ std::map<EffectiveFormat, FormatUsageInfo> mUsageMap;
+
+ std::map<GLenum, const FormatUsageInfo*> mRBFormatMap;
+ std::map<GLenum, const FormatUsageInfo*> mSizedTexFormatMap;
+ std::map<PackingInfo, const FormatUsageInfo*> mUnsizedTexFormatMap;
public:
static UniquePtr<FormatUsageAuthority> CreateForWebGL1(gl::GLContext* gl);
static UniquePtr<FormatUsageAuthority> CreateForWebGL2(gl::GLContext* gl);
private:
FormatUsageAuthority() { }
public:
- void AddFormat(EffectiveFormat format, GLenum rbInternalFormat, bool isRenderable,
- GLenum texInternalFormat, bool isFilterable);
+ void AddRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
+ void AddSizedTexFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
+ void AddUnsizedTexFormat(const PackingInfo& pi, const FormatUsageInfo* usage);
- void AddUnpackOption(GLenum unpackFormat, GLenum unpackType,
- EffectiveFormat effectiveFormat);
+ const FormatUsageInfo* GetRBUsage(GLenum sizedFormat) const;
+ const FormatUsageInfo* GetSizedTexUsage(GLenum sizedFormat) const;
+ const FormatUsageInfo* GetUnsizedTexUsage(const PackingInfo& pi) const;
- FormatUsageInfo* GetUsage(EffectiveFormat format);
- FormatUsageInfo* GetUsage(const FormatInfo* format)
+ FormatUsageInfo* EditUsage(EffectiveFormat format);
+
+ const FormatUsageInfo* GetUsage(EffectiveFormat format) const;
+
+ const FormatUsageInfo* GetUsage(const FormatInfo* format) const
{
if (!format)
return nullptr;
return GetUsage(format->effectiveFormat);
}
};
-////////////////////////////////////////////////////////////////////////////////
-
-GLint GetComponentSize(EffectiveFormat format, GLenum component);
-GLenum GetComponentType(EffectiveFormat format);
-GLenum GetColorEncoding(EffectiveFormat format);
-
} // namespace webgl
} // namespace mozilla
#endif // WEBGL_FORMATS_H_
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -45,55 +45,56 @@ WebGLFBAttachPoint::IsDeleteRequested()
bool
WebGLFBAttachPoint::IsDefined() const
{
return (Renderbuffer() && Renderbuffer()->IsDefined()) ||
(Texture() && Texture()->ImageInfoAt(mTexImageTarget,
mTexImageLevel).IsDefined());
}
-TexInternalFormat
+const webgl::FormatUsageInfo*
WebGLFBAttachPoint::Format() const
{
MOZ_ASSERT(IsDefined());
if (Texture())
return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).mFormat;
if (Renderbuffer())
- return Renderbuffer()->InternalFormat();
+ return Renderbuffer()->Format();
- return LOCAL_GL_NONE;
+ return nullptr;
}
bool
WebGLFBAttachPoint::HasAlpha() const
{
- return FormatHasAlpha(Format());
+ return Format()->format->hasAlpha;
}
-GLenum
+const webgl::FormatUsageInfo*
WebGLFramebuffer::GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const
{
MOZ_ASSERT(attachment.IsDefined());
MOZ_ASSERT(attachment.Texture() || attachment.Renderbuffer());
- return attachment.Format().get();
+ return attachment.Format();
}
bool
WebGLFBAttachPoint::IsReadableFloat() const
{
- TexInternalFormat internalformat = Format();
- MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
+ auto formatUsage = Format();
+ MOZ_ASSERT(formatUsage);
- TexType type = TypeFromInternalFormat(internalformat);
- return type == LOCAL_GL_FLOAT ||
- type == LOCAL_GL_HALF_FLOAT_OES ||
- type == LOCAL_GL_HALF_FLOAT;
+ auto format = formatUsage->format;
+ if (!format->isColorFormat)
+ return false;
+
+ return format->componentType == webgl::ComponentType::Float;
}
void
WebGLFBAttachPoint::Clear()
{
if (mRenderbufferPtr) {
MOZ_ASSERT(!mTexturePtr);
mRenderbufferPtr->UnmarkAttachment(*this);
@@ -160,17 +161,17 @@ WebGLFBAttachPoint::HasUninitializedImag
void
WebGLFBAttachPoint::SetImageDataStatus(WebGLImageDataStatus newStatus)
{
if (!HasImage())
return;
if (mRenderbufferPtr) {
- mRenderbufferPtr->SetImageDataStatus(newStatus);
+ mRenderbufferPtr->mImageDataStatus = newStatus;
return;
}
MOZ_ASSERT(mTexturePtr);
auto& imageInfo = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel);
MOZ_ASSERT(imageInfo.IsDefined());
@@ -179,17 +180,17 @@ WebGLFBAttachPoint::SetImageDataStatus(W
}
bool
WebGLFBAttachPoint::HasImage() const
{
if (Texture() && Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).IsDefined())
return true;
- if (Renderbuffer())
+ if (Renderbuffer() && Renderbuffer()->IsDefined())
return true;
return false;
}
void
WebGLFBAttachPoint::Size(uint32_t* const out_width, uint32_t* const out_height) const
{
@@ -210,165 +211,56 @@ WebGLFBAttachPoint::Size(uint32_t* const
}
void
WebGLFBAttachPoint::OnBackingStoreRespecified() const
{
mFB->InvalidateFramebufferStatus();
}
-/*
-const WebGLRectangleObject&
-WebGLFBAttachPoint::RectangleObject() const
-{
- MOZ_ASSERT(HasImage(),
- "Make sure it has an image before requesting the rectangle.");
-
- if (Texture()) {
- MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
- return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
- }
-
- if (Renderbuffer())
- return *Renderbuffer();
-
- MOZ_CRASH("Should not get here.");
-}
-*/
-// The following IsValidFBOTextureXXX functions check the internal format that
-// is used by GL or GL ES texture formats. This corresponds to the state that
-// is stored in WebGLTexture::ImageInfo::InternalFormat()
-
-static inline bool
-IsValidFBOTextureDepthFormat(GLenum internalformat)
-{
- return IsGLDepthFormat(internalformat);
-}
-
-static inline bool
-IsValidFBOTextureDepthStencilFormat(GLenum internalformat)
-{
- return IsGLDepthStencilFormat(internalformat);
-}
-
-// The following IsValidFBORenderbufferXXX functions check the internal format
-// that is stored by WebGLRenderbuffer::InternalFormat(). Valid values can be
-// found in WebGLContext::RenderbufferStorage.
-
-static inline bool
-IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
-{
- return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
-}
-
-static inline bool
-IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
-{
- return internalFormat == LOCAL_GL_DEPTH_STENCIL;
-}
-
-static inline bool
-IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
-{
- return internalFormat == LOCAL_GL_STENCIL_INDEX8;
-}
-
-bool
-WebGLContext::IsFormatValidForFB(TexInternalFormat format) const
-{
- switch (format.get()) {
- case LOCAL_GL_RGB8:
- case LOCAL_GL_RGBA8:
- case LOCAL_GL_RGB565:
- case LOCAL_GL_RGB5_A1:
- case LOCAL_GL_RGBA4:
- return true;
-
- case LOCAL_GL_SRGB8:
- case LOCAL_GL_SRGB8_ALPHA8_EXT:
- return IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
-
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_RGBA32F:
- return IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float);
-
- case LOCAL_GL_RGB16F:
- case LOCAL_GL_RGBA16F:
- return IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float);
- }
-
- return false;
-}
-
bool
WebGLFBAttachPoint::IsComplete() const
{
if (!HasImage())
return false;
uint32_t width;
uint32_t height;
Size(&width, &height);
if (!width || !height)
return false;
- if (Texture()) {
- const auto& imageInfo = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
- MOZ_ASSERT(imageInfo.IsDefined());
-
- const auto format = imageInfo.mFormat;
-
- if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
- return IsGLDepthFormat(format);
-
- if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) {
- // Textures can't have the correct format for stencil buffers.
- return false;
- }
-
- if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
- return IsGLDepthStencilFormat(format);
+ auto formatUsage = Format();
+ if (!formatUsage->isRenderable)
+ return false;
- if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
- mAttachmentPoint <= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0 - 1 +
- WebGLContext::kMaxColorAttachments))
- {
- WebGLContext* webgl = Texture()->Context();
- return webgl->IsFormatValidForFB(format);
- }
- MOZ_ASSERT(false, "Invalid WebGL attachment point?");
- return false;
- }
-
- MOZ_ASSERT(Renderbuffer());
- GLenum internalFormat = Renderbuffer()->InternalFormat();
-
- if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
- return IsValidFBORenderbufferDepthFormat(internalFormat);
-
- if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
- return IsValidFBORenderbufferStencilFormat(internalFormat);
-
- if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
- return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
+ auto format = formatUsage->format;
if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mAttachmentPoint <= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0 - 1 +
WebGLContext::kMaxColorAttachments))
{
- WebGLContext* webgl = Renderbuffer()->Context();
- return webgl->IsFormatValidForFB(internalFormat);
+ return format->isColorFormat;
}
- MOZ_ASSERT(false, "Invalid WebGL attachment point?");
- return false;
+
+ if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
+ return format->hasDepth && !format->hasStencil;
+
+ if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
+ return !format->hasDepth && format->hasStencil;
+
+ if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+ return format->hasDepth && format->hasStencil;
+
+ MOZ_CRASH("Invalid WebGL attachment point?");
}
void
WebGLFBAttachPoint::FinalizeAttachment(gl::GLContext* gl,
- FBAttachment attachmentLoc) const
+ FBAttachment attachmentLoc) const
{
if (!HasImage()) {
switch (attachmentLoc.get()) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_STENCIL_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
break;
@@ -378,17 +270,17 @@ WebGLFBAttachPoint::FinalizeAttachment(g
break;
}
return;
}
MOZ_ASSERT(HasImage());
if (Texture()) {
- MOZ_ASSERT(gl == Texture()->Context()->GL());
+ MOZ_ASSERT(gl == Texture()->mContext->GL());
const GLenum imageTarget = ImageTarget().get();
const GLint mipLevel = MipLevel();
const GLint layer = Layer();
const GLuint glName = Texture()->mGLName;
switch (imageTarget) {
case LOCAL_GL_TEXTURE_2D:
@@ -431,40 +323,40 @@ WebGLFBAttachPoint::FinalizeAttachment(g
Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
return;
}
MOZ_CRASH();
}
JS::Value
-WebGLFBAttachPoint::GetParameter(WebGLContext* context, GLenum pname)
+WebGLFBAttachPoint::GetParameter(WebGLContext* context, GLenum target, GLenum attachment,
+ GLenum pname)
{
- // TODO: WebGLTexture and WebGLRenderbuffer should store FormatInfo instead of doing
- // this dance every time.
- const GLenum internalFormat = EffectiveInternalFormat().get();
- const webgl::FormatInfo* info = webgl::GetInfoBySizedFormat(internalFormat);
- MOZ_ASSERT(info);
-
WebGLTexture* tex = Texture();
+ bool isPNameValid = false;
switch (pname) {
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
- return JS::Int32Value(webgl::GetComponentSize(info->effectiveFormat, pname));
-
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
- return JS::Int32Value(webgl::GetComponentType(info->effectiveFormat));
+ isPNameValid = true;
+ break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
- return JS::Int32Value(webgl::GetColorEncoding(info->effectiveFormat));
+ if (tex->mContext->IsWebGL2() ||
+ tex->mContext->IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
+ {
+ isPNameValid = true;
+ }
+ break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
if (tex) {
return JS::Int32Value(MipLevel());
}
break;
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
@@ -485,19 +377,28 @@ WebGLFBAttachPoint::GetParameter(WebGLCo
{
layer = Layer();
}
return JS::Int32Value(layer);
}
break;
}
- context->ErrorInvalidEnum("getFramebufferParameter: Invalid combination of "
- "attachment and pname.");
- return JS::NullValue();
+ if (!isPNameValid) {
+ context->ErrorInvalidEnum("getFramebufferParameter: Invalid combination of "
+ "attachment and pname.");
+ return JS::NullValue();
+ }
+
+ gl::GLContext* gl = tex->mContext->GL();
+ gl->MakeCurrent();
+
+ GLint ret = 0;
+ gl->fGetFramebufferAttachmentParameteriv(target, attachment, pname, &ret);
+ return JS::Int32Value(ret);
}
////////////////////////////////////////////////////////////////////////////////
// WebGLFramebuffer
WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
: WebGLContextBoundObject(webgl)
, mGLName(fbo)
@@ -741,19 +642,19 @@ WebGLFramebuffer::AllImageRectsMatch() c
{
MOZ_ASSERT(HasDefinedAttachments());
MOZ_ASSERT(!HasIncompleteAttachments());
uint32_t width = 0;
uint32_t height = 0;
bool imageRectsMatch = true;
- imageRectsMatch &= MatchOrReplaceSize(mColorAttachment0, &width, &height);
- imageRectsMatch &= MatchOrReplaceSize(mDepthAttachment, &width, &height);
- imageRectsMatch &= MatchOrReplaceSize(mStencilAttachment, &width, &height);
+ imageRectsMatch &= MatchOrReplaceSize(mColorAttachment0, &width, &height);
+ imageRectsMatch &= MatchOrReplaceSize(mDepthAttachment, &width, &height);
+ imageRectsMatch &= MatchOrReplaceSize(mStencilAttachment, &width, &height);
imageRectsMatch &= MatchOrReplaceSize(mDepthStencilAttachment, &width, &height);
const size_t moreColorAttachmentCount = mMoreColorAttachments.Length();
for (size_t i = 0; i < moreColorAttachmentCount; i++) {
imageRectsMatch &= MatchOrReplaceSize(mMoreColorAttachments[i], &width, &height);
}
return imageRectsMatch;
@@ -984,41 +885,37 @@ WebGLFramebuffer::FinalizeAttachments()
GLenum attachPoint = LOCAL_GL_COLOR_ATTACHMENT0 + 1 + i;
mMoreColorAttachments[i].FinalizeAttachment(gl, attachPoint);
}
FinalizeDrawAndReadBuffers(gl, mColorAttachment0.IsDefined());
}
bool
-WebGLFramebuffer::ValidateForRead(const char* info, TexInternalFormat* const out_format,
+WebGLFramebuffer::ValidateForRead(const char* funcName,
+ const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height)
{
+ if (!CheckAndInitializeAttachments()) {
+ mContext->ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
+ funcName);
+ return false;
+ }
+
if (mReadBufferMode == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
- " NONE.", info);
+ " NONE.", funcName);
return false;
}
const auto& attachPoint = GetAttachPoint(mReadBufferMode);
- if (!CheckAndInitializeAttachments()) {
- mContext->ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
- return false;
- }
-
- GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
- if (!HasCompletePlanes(readPlaneBits)) {
- mContext->ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
- " correct color/depth/stencil type.");
- return false;
- }
-
if (!attachPoint.IsDefined()) {
- mContext->ErrorInvalidOperation("readPixels: ");
+ mContext->ErrorInvalidOperation("%s: THe attachment specified for reading is"
+ " null.", funcName);
return false;
}
*out_format = attachPoint.Format();
attachPoint.Size(out_width, out_height);
return true;
}
@@ -1032,20 +929,18 @@ AttachmentsDontMatch(const WebGLFBAttach
if (a.Renderbuffer()) {
return (a.Renderbuffer() != b.Renderbuffer());
}
return false;
}
JS::Value
-WebGLFramebuffer::GetAttachmentParameter(JSContext* cx,
- GLenum attachment,
- GLenum pname,
- ErrorResult& rv)
+WebGLFramebuffer::GetAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment,
+ GLenum pname, ErrorResult* const out_error)
{
// "If a framebuffer object is bound to target, then attachment must be one of the
// attachment points of the framebuffer listed in table 4.6."
switch (attachment) {
case LOCAL_GL_DEPTH_ATTACHMENT:
case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
break;
@@ -1100,35 +995,35 @@ WebGLFramebuffer::GetAttachmentParameter
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
if (objectType == LOCAL_GL_NONE) {
return JS::NullValue();
}
if (objectType == LOCAL_GL_RENDERBUFFER) {
const WebGLRenderbuffer* rb = fba.Renderbuffer();
- return mContext->WebGLObjectAsJSValue(cx, rb, rv);
+ return mContext->WebGLObjectAsJSValue(cx, rb, *out_error);
}
/* If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE, then */
if (objectType == LOCAL_GL_TEXTURE) {
const WebGLTexture* tex = fba.Texture();
- return mContext->WebGLObjectAsJSValue(cx, tex, rv);
+ return mContext->WebGLObjectAsJSValue(cx, tex, *out_error);
}
break;
}
if (objectType == LOCAL_GL_NONE) {
mContext->ErrorInvalidOperation("getFramebufferAttachmentParameter: No "
"attachment at %s",
mContext->EnumName(attachment));
return JS::NullValue();
}
- return fba.GetParameter(mContext, pname);
+ return fba.GetParameter(mContext, target, attachment, pname);
}
////////////////////////////////////////////////////////////////////////////////
// Goop.
JSObject*
WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -41,17 +41,17 @@ public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, FBAttachment attachmentPoint);
~WebGLFBAttachPoint();
void Unlink();
bool IsDefined() const;
bool IsDeleteRequested() const;
- TexInternalFormat Format() const;
+ const webgl::FormatUsageInfo* Format() const;
bool HasAlpha() const;
bool IsReadableFloat() const;
void Clear();
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
@@ -87,17 +87,18 @@ public:
//const WebGLRectangleObject& RectangleObject() const;
bool HasImage() const;
bool IsComplete() const;
void FinalizeAttachment(gl::GLContext* gl,
FBAttachment attachmentLoc) const;
- JS::Value GetParameter(WebGLContext* context, GLenum pname);
+ JS::Value GetParameter(WebGLContext* context, GLenum target, GLenum attachment,
+ GLenum pname);
void OnBackingStoreRespecified() const;
};
class WebGLFramebuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLFramebuffer>
, public LinkedListElement<WebGLFramebuffer>
@@ -156,17 +157,17 @@ public:
GLint layer);
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments() const;
bool AllImageRectsMatch() const;
FBStatus PrecheckFramebufferStatus() const;
FBStatus CheckFramebufferStatus() const;
- GLenum
+ const webgl::FormatUsageInfo*
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
bool HasDepthStencilConflict() const {
return int(mDepthAttachment.IsDefined()) +
int(mStencilAttachment.IsDefined()) +
int(mDepthStencilAttachment.IsDefined()) >= 2;
}
@@ -193,17 +194,17 @@ public:
WebGLFBAttachPoint& GetAttachPoint(FBAttachment attachPointEnum);
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
void FinalizeAttachments() const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
@@ -217,18 +218,19 @@ public:
const char* funcName) const;
void EnsureColorAttachPoints(size_t colorAttachmentId);
void InvalidateFramebufferStatus() const {
mStatus = 0;
}
- bool ValidateForRead(const char* info, TexInternalFormat* const out_format,
+ bool ValidateForRead(const char* info,
+ const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
- JS::Value GetAttachmentParameter(JSContext* cx, GLenum attachment, GLenum pname,
- ErrorResult& rv);
+ JS::Value GetAttachmentParameter(JSContext* cx, GLenum target, GLenum attachment,
+ GLenum pname, ErrorResult* const out_error);
};
} // namespace mozilla
#endif // WEBGL_FRAMEBUFFER_H_
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -264,20 +264,18 @@ protected:
// as well as comparison with the current context.
class WebGLContextBoundObject
{
public:
explicit WebGLContextBoundObject(WebGLContext* webgl);
bool IsCompatibleWithContext(WebGLContext* other);
- WebGLContext* Context() const { return mContext; }
-
+ WebGLContext* const mContext;
protected:
- WebGLContext* const mContext;
const uint32_t mContextGeneration;
};
// this class is a mixin for GL objects that have dimensions
// that we need to track.
class WebGLRectangleObject
{
public:
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -162,17 +162,17 @@ QueryProgramInfo(WebGLProgram* prog, gl:
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
userName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
#endif
const bool isArray = false;
- AddActiveInfo(prog->Context(), elemCount, elemType, isArray, userName, mappedName,
+ AddActiveInfo(prog->mContext, elemCount, elemType, isArray, userName, mappedName,
&info->activeAttribs, &info->attribMap);
// Collect active locations:
GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
if (loc == -1)
MOZ_CRASH("Active attrib has no location.");
info->activeAttribLocs.insert(loc);
@@ -227,17 +227,17 @@ QueryProgramInfo(WebGLProgram* prog, gl:
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
(int)isArray, baseMappedName.BeginReading(),
baseUserName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
- AddActiveInfo(prog->Context(), elemCount, elemType, isArray, baseUserName,
+ AddActiveInfo(prog->mContext, elemCount, elemType, isArray, baseUserName,
baseMappedName, &info->activeUniforms, &info->uniformMap);
}
// Uniform Blocks
if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
GLuint numActiveUniformBlocks = 0;
gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -191,17 +191,17 @@ public:
bool IsLinked() const { return mMostRecentLinkInfo; }
const webgl::LinkedProgramInfo* LinkInfo() const {
return mMostRecentLinkInfo.get();
}
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;
private:
~WebGLProgram();
bool LinkAndUpdate();
--- a/dom/canvas/WebGLQuery.h
+++ b/dom/canvas/WebGLQuery.h
@@ -28,17 +28,17 @@ public:
return mType != 0;
}
// WebGLRefCountedObject
void Delete();
// nsWrapperCache
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
// NS
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQuery)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQuery)
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -46,20 +46,20 @@ WebGLRenderbuffer::WrapObject(JSContext*
{
return dom::WebGLRenderbufferBinding::Wrap(cx, this, givenProto);
}
WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mPrimaryRB(0)
, mSecondaryRB(0)
- , mInternalFormat(0)
- , mInternalFormatForGL(0)
+ , mFormat(nullptr)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
, mSamples(1)
+ , mIsUsingSecondary(false)
#ifdef ANDROID
, mIsRB(false)
#endif
{
mContext->MakeContextCurrent();
mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
if (!SupportsDepthStencil(mContext->gl))
@@ -81,72 +81,31 @@ WebGLRenderbuffer::Delete()
#ifdef ANDROID
mIsRB = false;
#endif
}
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)
+ if (!mFormat)
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
- }
+ auto bytesPerPixel = mFormat->format->estimatedBytesPerPixel;
+ uint64_t pixels = uint64_t(mWidth) * uint64_t(mHeight);
+
+ uint64_t totalSize = pixels * bytesPerPixel;
+
+ // If we have the same bytesPerPixel whether or not we have a secondary RB.
+ if (mSecondaryRB && !mIsUsingSecondary) {
+ totalSize += 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;
+ return int64_t(totalSize);
}
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
@@ -167,76 +126,116 @@ static void
RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
GLenum internalFormat, GLsizei width,
GLsizei height)
{
MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
MOZ_ASSERT(samples >= 0);
MOZ_ASSERT(samples <= gl->MaxSamples());
+ // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
+ GLenum internalFormatForGL = internalFormat;
+
+ switch (internalFormat) {
+ case LOCAL_GL_RGBA4:
+ case LOCAL_GL_RGB5_A1:
+ // 16-bit RGBA formats are not supported on desktop GL
+ if (!gl->IsGLES())
+ internalFormatForGL = LOCAL_GL_RGBA8;
+ break;
+
+ case LOCAL_GL_RGB565:
+ // the RGB565 format is not supported on desktop GL
+ if (!gl->IsGLES())
+ internalFormatForGL = LOCAL_GL_RGB8;
+ break;
+
+ case LOCAL_GL_DEPTH_COMPONENT16:
+ if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
+ internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
+ else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
+ internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
+ break;
+
+ case LOCAL_GL_DEPTH_STENCIL:
+ // We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
+ internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
+ break;
+
+ default:
+ break;
+ }
+
if (samples > 0) {
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
- internalFormat, width, height);
+ internalFormatForGL, width, height);
} else {
- gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width,
+ gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormatForGL, width,
height);
}
}
void
-WebGLRenderbuffer::RenderbufferStorage(GLsizei samples, GLenum internalFormat,
- GLsizei width, GLsizei height) const
+WebGLRenderbuffer::RenderbufferStorage(GLsizei samples,
+ const webgl::FormatUsageInfo* format,
+ GLsizei width, GLsizei height)
{
MOZ_ASSERT(mContext->mBoundRenderbuffer == this);
- InvalidateStatusOfAttachedFBs();
gl::GLContext* gl = mContext->gl;
MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check.
- GLenum primaryFormat = internalFormat;
+ GLenum primaryFormat = format->format->sizedFormat;
GLenum secondaryFormat = 0;
if (NeedsDepthStencilEmu(mContext->gl, primaryFormat)) {
primaryFormat = DepthStencilDepthFormat(gl);
secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
}
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
height);
- if (!mSecondaryRB) {
- MOZ_ASSERT(!secondaryFormat);
- return;
+ if (mSecondaryRB) {
+ // 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.
+ gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
+ if (secondaryFormat) {
+ RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
+ height);
+ } else {
+ RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
+ }
}
- // 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.
- gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
- if (secondaryFormat) {
- RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
- height);
- } else {
- RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
- }
+
+ mSamples = samples;
+ mFormat = format;
+ mWidth = width;
+ mHeight = height;
+ mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
+ mIsUsingSecondary = bool(secondaryFormat);
+
+ InvalidateStatusOfAttachedFBs();
}
void
WebGLRenderbuffer::FramebufferRenderbuffer(FBAttachment attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment.get(),
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
return;
}
GLuint stencilRB = mPrimaryRB;
- if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
+ if (mIsUsingSecondary) {
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,
@@ -246,30 +245,23 @@ WebGLRenderbuffer::FramebufferRenderbuff
GLint
WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
RBParam pname) const
{
gl::GLContext* gl = mContext->gl;
switch (pname.get()) {
case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
- if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
- if (gl->WorkAroundDriverBugs() &&
- gl->Renderer() == gl::GLRenderer::Tegra)
- {
- return 8;
- }
+ if (!mFormat)
+ return 0;
- gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
+ if (!mFormat->format->hasStencil)
+ return 0;
- GLint i = 0;
- gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
- return i;
- }
- // Fall through otherwise.
+ return 8;
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:
@@ -280,14 +272,23 @@ WebGLRenderbuffer::GetRenderbufferParame
}
}
MOZ_ASSERT(false,
"This function should only be called with valid `pname`.");
return 0;
}
+GLenum
+WebGLRenderbuffer::GetInternalFormat() const
+{
+ if (!mFormat)
+ return 0;
+
+ return mFormat->format->sizedFormat;
+}
+
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLRenderbuffer)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLRenderbuffer, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLRenderbuffer, Release)
} // namespace mozilla
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -9,16 +9,19 @@
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
#include "WebGLFramebufferAttachable.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
namespace mozilla {
+namespace webgl {
+struct FormatUsageInfo;
+}
class WebGLRenderbuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLRenderbuffer>
, public LinkedListElement<WebGLRenderbuffer>
, public WebGLRectangleObject
, public WebGLContextBoundObject
, public WebGLFramebufferAttachable
@@ -28,83 +31,70 @@ public:
void Delete();
bool HasUninitializedImageData() const {
MOZ_ASSERT(mImageDataStatus != WebGLImageDataStatus::NoImageData);
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
}
- void SetImageDataStatus(WebGLImageDataStatus x) {
- // there is no way to go from having image data to not having any
- MOZ_ASSERT(x != WebGLImageDataStatus::NoImageData ||
- mImageDataStatus == WebGLImageDataStatus::NoImageData);
- mImageDataStatus = x;
- }
-
bool IsDefined() const {
- if (mInternalFormat == LOCAL_GL_NONE) {
+ if (!mFormat) {
MOZ_ASSERT(!mWidth && !mHeight);
return false;
}
return true;
}
GLsizei Samples() const { return mSamples; }
- void SetSamples(GLsizei samples) { mSamples = samples; }
GLuint PrimaryGLName() const { return mPrimaryRB; }
- GLenum InternalFormat() const { return mInternalFormat; }
- void SetInternalFormat(GLenum internalFormat) {
- mInternalFormat = internalFormat;
- }
+ const webgl::FormatUsageInfo* Format() const { return mFormat; }
- GLenum InternalFormatForGL() const { return mInternalFormatForGL; }
- void SetInternalFormatForGL(GLenum internalFormatForGL) {
- mInternalFormatForGL = internalFormatForGL;
- }
+ GLenum GetInternalFormat() const;
int64_t MemoryUsage() const;
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
void BindRenderbuffer() const;
- void RenderbufferStorage(GLsizei samples, GLenum internalFormat,
- GLsizei width, GLsizei height) const;
+ void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
+ GLsizei width, GLsizei height);
void FramebufferRenderbuffer(FBAttachment attachment) const;
// Only handles a subset of `pname`s.
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
protected:
~WebGLRenderbuffer() {
DeleteOnce();
}
GLuint mPrimaryRB;
GLuint mSecondaryRB;
- GLenum mInternalFormat;
- GLenum mInternalFormatForGL;
+ const webgl::FormatUsageInfo* mFormat;
WebGLImageDataStatus mImageDataStatus;
GLsizei mSamples;
+ bool mIsUsingSecondary;
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
// This shows up on Android 2.3 emulator.
//
// So we track the `is a Renderbuffer` state ourselves.
bool mIsRB;
#endif
friend class WebGLContext;
friend class WebGLFramebuffer;
+ friend class WebGLFBAttachPoint;
};
} // namespace mozilla
#endif // WEBGL_RENDERBUFFER_H_
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -30,17 +30,17 @@ WebGLSampler::Delete()
mContext->gl->fDeleteSamplers(1, &mGLName);
removeFrom(mContext->mSamplers);
}
WebGLContext*
WebGLSampler::GetParentObject() const
{
- return Context();
+ return mContext;
}
JSObject*
WebGLSampler::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLSamplerBinding::Wrap(cx, this, givenProto);
}
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -6,16 +6,17 @@
#include "WebGLShader.h"
#include "angle/ShaderLang.h"
#include "GLContext.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/MemoryReporting.h"
#include "nsPrintfCString.h"
#include "nsString.h"
+#include "prenv.h"
#include "WebGLContext.h"
#include "WebGLObjectModel.h"
#include "WebGLShaderValidator.h"
#include "WebGLValidateStrings.h"
namespace mozilla {
// On success, writes to out_validator and out_translatedSource.
@@ -162,45 +163,46 @@ WebGLShader::ShaderSource(const nsAStrin
StripComments stripComments(source);
const nsAString& cleanSource = Substring(stripComments.result().Elements(),
stripComments.length());
if (!ValidateGLSLString(cleanSource, mContext, "shaderSource"))
return;
// We checked that the source stripped of comments is in the
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
- NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
+ const NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
if (mContext->gl->WorkAroundDriverBugs()) {
const size_t maxSourceLength = 0x3ffff;
if (sourceCString.Length() > maxSourceLength) {
mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
" characters. (Driver workaround)",
maxSourceLength);
return;
}
}
- // HACK - dump shader source
- {
-/*
- printf_stderr("//-*- glsl -*-\n");
- // Wow - Roll Your Own For Each Lines because printf_stderr has a hard-coded internal size, so long strings are truncated.
- const nsString& src = shader->Source();
+ if (PR_GetEnv("MOZ_WEBGL_DUMP_SHADERS")) {
+ printf_stderr("////////////////////////////////////////\n");
+ printf_stderr("// MOZ_WEBGL_DUMP_SHADERS:\n");
+
+ // Wow - Roll Your Own Foreach-Lines because printf_stderr has a hard-coded
+ // internal size, so long strings are truncated.
+
int32_t start = 0;
- int32_t end = src.Find("\n", false, start, -1);
+ int32_t end = sourceCString.Find("\n", false, start, -1);
while (end > -1) {
- printf_stderr("%s\n", NS_ConvertUTF16toUTF8(nsDependentSubstring(src, start, end - start)).get());
+ const nsCString line(sourceCString.BeginReading() + start, end - start);
+ printf_stderr("%s\n", line.BeginReading());
start = end + 1;
- end = src.Find("\n", false, start, -1);
+ end = sourceCString.Find("\n", false, start, -1);
}
- printf_stderr("//\n");
-*/
+
+ printf_stderr("////////////////////////////////////////\n");
}
- // HACK
mSource = source;
mCleanSource = sourceCString;
}
void
WebGLShader::CompileShader()
{
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -71,17 +71,17 @@ public:
const std::vector<nsCString>& varyings,
GLenum bufferMode,
std::vector<std::string>* out_mappedVaryings) const;
// Other funcs
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
void Delete();
- WebGLContext* GetParentObject() const { return Context(); }
+ WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
public:
const GLuint mGLName;
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -142,16 +142,17 @@ public:
MOZ_ASSERT(IsValueLegal(mValue));
}
GLenum get() const {
MOZ_ASSERT(mValue != NonexistantGLenum);
return mValue;
}
+
bool operator==(const StrongGLenum& other) const {
return get() == other.get();
}
bool operator!=(const StrongGLenum& other) const {
return get() != other.get();
}
--- a/dom/canvas/WebGLSync.cpp
+++ b/dom/canvas/WebGLSync.cpp
@@ -29,17 +29,17 @@ WebGLSync::Delete()
mContext->gl->fDeleteSync(mGLName);
mGLName = 0;
LinkedListElement<WebGLSync>::remove();
}
WebGLContext*
WebGLSync::GetParentObject() const
{
- return Context();
+ return mContext;
}
// -------------------------------------------------------------------------
// IMPLEMENT NS
JSObject*
WebGLSync::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLSyncBinding::Wrap(cx, this, givenProto);
--- a/dom/canvas/WebGLTexelConversions.cpp
+++ b/dom/canvas/WebGLTexelConversions.cpp
@@ -321,83 +321,83 @@ public:
bool Success() const {
return mSuccess;
}
};
} // end anonymous namespace
bool
-WebGLContext::ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
- const uint8_t* src, uint8_t* dst,
- WebGLTexelFormat srcFormat, bool srcPremultiplied,
- WebGLTexelFormat dstFormat, bool dstPremultiplied,
- size_t dstTexelSize)
+ConvertImage(size_t width, size_t height,
+ const void* srcBegin, size_t srcStride, gl::OriginPos srcOrigin,
+ WebGLTexelFormat srcFormat, bool srcPremultiplied,
+ void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
+ WebGLTexelFormat dstFormat, bool dstPremultiplied)
{
- if (width <= 0 || height <= 0)
- return true;
-
- const bool FormatsRequireNoPremultiplicationOp =
- !HasAlpha(srcFormat) ||
- !HasColor(srcFormat) ||
- !HasColor(dstFormat);
-
- if (srcFormat == dstFormat &&
- (FormatsRequireNoPremultiplicationOp || srcPremultiplied == dstPremultiplied))
- {
- // fast exit path: we just have to memcpy all the rows.
- //
- // The case where absolutely nothing needs to be done is supposed to have
- // been handled earlier (in TexImage2D_base, etc).
- //
- // So the case we're handling here is when even though no format conversion is needed,
- // we still might have to flip vertically and/or to adjust to a different stride.
-
- MOZ_ASSERT(mPixelStoreFlipY || srcStride != dstStride, "Performance trap -- should handle this case earlier, to avoid memcpy");
-
- size_t row_size = width * dstTexelSize; // doesn't matter, src and dst formats agree
- const uint8_t* ptr = src;
- const uint8_t* src_end = src + height * srcStride;
-
- uint8_t* dst_row = mPixelStoreFlipY
- ? dst + (height-1) * dstStride
- : dst;
- ptrdiff_t dstStrideSigned(dstStride);
- ptrdiff_t dst_delta = mPixelStoreFlipY ? -dstStrideSigned : dstStrideSigned;
-
- while(ptr != src_end) {
- memcpy(dst_row, ptr, row_size);
- ptr += srcStride;
- dst_row += dst_delta;
- }
- return true;
- }
-
if (srcFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion ||
dstFormat == WebGLTexelFormat::FormatNotSupportingAnyConversion)
{
return false;
}
- uint8_t* dstStart = dst;
- ptrdiff_t signedDstStride = dstStride;
- if (mPixelStoreFlipY) {
- dstStart = dst + (height - 1) * dstStride;
- signedDstStride = -signedDstStride;
+ if (!width || !height)
+ return true;
+
+ const bool shouldYFlip = (srcOrigin != dstOrigin);
+
+ const bool canSkipPremult = (!HasAlpha(srcFormat) ||
+ !HasColor(srcFormat) ||
+ !HasColor(dstFormat));
+
+ WebGLTexelPremultiplicationOp premultOp;
+ if (canSkipPremult) {
+ premultOp = WebGLTexelPremultiplicationOp::None;
+ } else if (!srcPremultiplied && dstPremultiplied) {
+ premultOp = WebGLTexelPremultiplicationOp::Premultiply;
+ } else if (srcPremultiplied && !dstPremultiplied) {
+ premultOp = WebGLTexelPremultiplicationOp::Unpremultiply;
+ } else {
+ premultOp = WebGLTexelPremultiplicationOp::None;
}
- WebGLImageConverter converter(width, height, src, dstStart, srcStride, signedDstStride);
+ const uint8_t* srcItr = (const uint8_t*)srcBegin;
+ const uint8_t* const srcEnd = srcItr + srcStride * height;
+ uint8_t* dstItr = (uint8_t*)dstBegin;
+ ptrdiff_t dstItrStride = dstStride;
+ if (shouldYFlip) {
+ dstItr = dstItr + dstStride * (height - 1);
+ dstItrStride = -dstItrStride;
+ }
- const WebGLTexelPremultiplicationOp premultiplicationOp
- = FormatsRequireNoPremultiplicationOp ? WebGLTexelPremultiplicationOp::None
- : (!srcPremultiplied && dstPremultiplied) ? WebGLTexelPremultiplicationOp::Premultiply
- : (srcPremultiplied && !dstPremultiplied) ? WebGLTexelPremultiplicationOp::Unpremultiply
- : WebGLTexelPremultiplicationOp::None;
+ if (srcFormat == dstFormat && premultOp == WebGLTexelPremultiplicationOp::None) {
+ // Fast exit path: we just have to memcpy all the rows.
+ //
+ // The case where absolutely nothing needs to be done is supposed to have
+ // been handled earlier (in TexImage2D_base, etc).
+ //
+ // So the case we're handling here is when even though no format conversion is
+ // needed, we still might have to flip vertically and/or to adjust to a different
+ // stride.
+
+ MOZ_ASSERT(!shouldYFlip || srcStride != dstStride,
+ "Performance trap -- should handle this case earlier to avoid memcpy");
- converter.run(srcFormat, dstFormat, premultiplicationOp);
+ const auto bytesPerPixel = TexelBytesForFormat(srcFormat);
+ const size_t bytesPerRow = bytesPerPixel * width;
+
+ while (srcItr != srcEnd) {
+ memcpy(dstItr, srcItr, bytesPerRow);
+ srcItr += srcStride;
+ dstItr += dstItrStride;
+ }
+ return true;
+ }
+
+ WebGLImageConverter converter(width, height, srcItr, dstItr, srcStride, dstItrStride);
+ converter.run(srcFormat, dstFormat, premultOp);
if (!converter.Success()) {
// the dst image may be left uninitialized, so we better not try to
// continue even in release builds. This should never happen anyway,
// and would be a bug in our code.
NS_RUNTIMEABORT("programming mistake in WebGL texture conversions");
}
--- a/dom/canvas/WebGLTexelConversions.h
+++ b/dom/canvas/WebGLTexelConversions.h
@@ -33,16 +33,24 @@
#endif
#include "WebGLTypes.h"
#include <stdint.h>
#include "mozilla/Attributes.h"
namespace mozilla {
+bool ConvertImage(size_t width, size_t height,
+ const void* srcBegin, size_t srcStride, gl::OriginPos srcOrigin,
+ WebGLTexelFormat srcFormat, bool srcPremultiplied,
+ void* dstBegin, size_t dstStride, gl::OriginPos dstOrigin,
+ WebGLTexelFormat dstFormat, bool dstPremultiplied);
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
// single precision float
// seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm
// half precision float
// seeeeemmmmmmmmmm
// IEEE 16bits floating point:
const uint16_t kFloat16Value_Zero = 0x0000; // = 0000000000000000b
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -98,17 +98,17 @@ WebGLTexture::ImageInfo::OnRespecify() c
}
size_t
WebGLTexture::ImageInfo::MemoryUsage() const
{
if (!IsDefined())
return 0;
- const auto bytesPerTexel = mFormat->formatInfo->bytesPerPixel;
+ const auto bytesPerTexel = mFormat->format->estimatedBytesPerPixel;
return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bytesPerTexel;
}
void
WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex)
{
MOZ_ASSERT(tex);
MOZ_ASSERT(this >= &tex->mImageInfoArr[0]);
@@ -164,28 +164,28 @@ WebGLTexture::MemoryUsage() const
return 0;
size_t result = 0;
MOZ_CRASH("todo");
return result;
}
void
-WebGLTexture::SetImageInfoAtFace(uint8_t face, uint32_t level, const ImageInfo& val)
+WebGLTexture::SetImageInfo(ImageInfo* target, const ImageInfo& newInfo)
{
- ImageInfoAtFace(face, level) = val;
+ *target = newInfo;
InvalidateFakeBlackCache();
}
void
-WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& val)
+WebGLTexture::SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo)
{
for (uint8_t i = 0; i < mFaceCount; i++) {
- ImageInfoAtFace(i, level) = val;
+ ImageInfoAtFace(i, level) = newInfo;
}
InvalidateFakeBlackCache();
}
static inline uint32_t
MaxMipmapLevelsForSize(const WebGLTexture::ImageInfo& info)
{
@@ -288,42 +288,16 @@ WebGLTexture::IsCubeComplete() const
{
return false;
}
}
return true;
}
-static bool
-IsColorFormat(TexInternalFormat format)
-{
- TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(format);
-
- // ALPHA *is* a "color format"!
- return unsizedformat != LOCAL_GL_DEPTH_COMPONENT &&
- unsizedformat != LOCAL_GL_DEPTH_STENCIL &&
- unsizedformat != LOCAL_GL_STENCIL_INDEX;
-}
-
-static bool
-FormatSupportsFiltering(WebGLContext* webgl, TexInternalFormat format)
-{
- TexType type = TypeFromInternalFormat(format);
-
- if (type == LOCAL_GL_FLOAT)
- return webgl->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear);
-
- MOZ_ASSERT(type != LOCAL_GL_HALF_FLOAT_OES);
- if (type == LOCAL_GL_HALF_FLOAT)
- return webgl->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear);
-
- return true;
-}
-
bool
WebGLTexture::IsComplete(const char** const out_reason) const
{
// Texture completeness is established at GLES 3.0.4, p160-161.
// "[A] texture is complete unless any of the following conditions hold true:"
// "* Any dimension of the `level_base` array is not positive."
const ImageInfo& baseImageInfo = BaseImageInfo();
@@ -356,17 +330,17 @@ WebGLTexture::IsComplete(const char** co
}
const bool isMinFilteringNearest = (mMinFilter == LOCAL_GL_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
const bool isMagFilteringNearest = (mMagFilter == LOCAL_GL_NEAREST);
const bool isFilteringNearestOnly = (isMinFilteringNearest && isMagFilteringNearest);
if (!isFilteringNearestOnly) {
auto formatUsage = baseImageInfo.mFormat;
- auto format = formatUsage->formatInfo;
+ auto format = formatUsage->format;
// "* The effective internal format specified for the texture arrays is a sized
// internal color format that is not texture-filterable, and either the
// magnification filter is not NEAREST or the minification filter is neither
// NEAREST nor NEAREST_MIPMAP_NEAREST."
// Since all (GLES3) unsized color formats are filterable just like their sized
// equivalents, we don't have to care whether its sized or not.
if (format->isColorFormat && !formatUsage->isFilterable) {
@@ -461,27 +435,28 @@ WebGLTexture::MaxEffectiveMipmapLevel()
const auto& imageInfo = BaseImageInfo();
MOZ_ASSERT(imageInfo.IsDefined());
uint32_t maxLevelBySize = mBaseMipmapLevel + imageInfo.MaxMipmapLevels() - 1;
return std::min<uint32_t>(maxLevelBySize, mMaxMipmapLevel);
}
bool
-WebGLTexture::ResolveFakeBlackStatus(WebGLTextureFakeBlackStatus* const out)
+WebGLTexture::ResolveFakeBlackStatus(const char* funcName,
+ WebGLTextureFakeBlackStatus* const out)
{
- if (!ResolveFakeBlackStatus())
+ if (!ResolveFakeBlackStatus(funcName))
return false;
*out = mFakeBlackStatus;
return true;
}
bool
-WebGLTexture::ResolveFakeBlackStatus()
+WebGLTexture::ResolveFakeBlackStatus(const char* funcName)
{
if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown))
return true;
const char* incompleteReason;
if (!IsComplete(&incompleteReason)) {
if (incompleteReason) {
mContext->GenerateWarning("An active texture is going to be rendered as if it"
@@ -522,225 +497,60 @@ WebGLTexture::ResolveFakeBlackStatus()
// Alright, we have both initialized and uninitialized data, so we have to initialize
// the uninitialized images. Feel free to be slow.
mContext->GenerateWarning("An active texture contains TexImages with uninitialized"
" data along with TexImages with initialized data, forcing"
" the implementation to (slowly) initialize the"
" uninitialized TexImages.");
+ GLenum baseTexImageTarget = mTarget.get();
+ if (baseTexImageTarget == LOCAL_GL_TEXTURE_CUBE_MAP)
+ baseTexImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+
for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
for (uint8_t face = 0; face < mFaceCount; face++) {
- if (!EnsureInitializedImageData(face, level))
+ TexImageTarget target = baseTexImageTarget + face;
+ if (!EnsureImageDataInitialized(funcName, target, level))
return false; // The world just exploded.
}
}
mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
return true;
}
-static bool
-ClearByMask(WebGLContext* webgl, GLbitfield mask)
-{
- gl::GLContext* gl = webgl->GL();
- MOZ_ASSERT(gl->IsCurrent());
-
- GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
- if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
- return false;
-
- bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false};
- if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
- colorAttachmentsMask[0] = true;
- }
-
- webgl->ForceClearFramebufferWithDefaultValues(false, mask, colorAttachmentsMask);
- return true;
-}
-
-// `mask` from glClear.
-static bool
-ClearWithTempFB(WebGLContext* webgl, GLuint tex,
- TexImageTarget texImageTarget, GLint level,
- TexInternalFormat baseInternalFormat,
- GLsizei width, GLsizei height)
+bool
+WebGLTexture::EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
+ uint32_t level)
{
- 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))
+ auto& imageInfo = ImageInfoAt(target, level);
+ if (imageInfo.IsDataInitialized())
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);
-}
-
-static TexImageTarget
-TexImageTargetFromFace(TexTarget target, uint8_t face)
-{
- if (target != LOCAL_GL_TEXTURE_CUBE_MAP)
- return target.get();
-
- return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+ return InitializeImageData(funcName, target, level);
}
bool
-WebGLTexture::EnsureInitializedImageData(uint8_t face, uint32_t level)
+WebGLTexture::InitializeImageData(const char* funcName, TexImageTarget target,
+ uint32_t level)
{
- ImageInfo& imageInfo = ImageInfoAtFace(face, level);
+ auto& imageInfo = ImageInfoAt(target, level);
MOZ_ASSERT(imageInfo.IsDefined());
-
- if (imageInfo.IsDataInitialized())
- return true;
-
- mContext->MakeContextCurrent();
-
- const TexImageTarget texImageTarget = TexImageTargetFromFace(mTarget, face);
-
- // Try to clear with glClear.
- if (mTarget == LOCAL_GL_TEXTURE_2D) {
- bool cleared = ClearWithTempFB(mContext, mGLName, texImageTarget, level,
- imageInfo.mFormat, imageInfo.mHeight,
- imageInfo.mWidth);
- if (cleared) {
- imageInfo.SetIsDataInitialized(true, this);
- return true;
- }
- }
-
- // That didn't work. Try uploading zeros then.
- auto formatUsage = imageInfo.mFormat;
- auto format = formatUsage->formatInfo;
-
- const auto unpackAlignment = mContext->mPixelStoreUnpackAlignment;
- CheckedUint32 checked_byteLength = WebGLContext::GetImageSize(imageInfo.mHeight,
- imageInfo.mWidth,
- imageInfo.mDepth,
- format->bytesPerTexel,
- unpackAlignment);
- MOZ_ASSERT(checked_byteLength.isValid()); // Should have been checked earlier.
-
- size_t byteCount = checked_byteLength.value();
+ MOZ_ASSERT(!imageInfo.IsDataInitialized());
- UniquePtr<uint8_t> zeros((uint8_t*)calloc(1, byteCount));
- if (zeros == nullptr) {
- // Failed to allocate memory. Lose the context. Return OOM error.
- mContext->ForceLoseContext(true);
- mContext->ErrorOutOfMemory("EnsureInitializedImageData: Failed to alloc %u "
- "bytes to clear image target `%s` level `%d`.",
- byteCount, mContext->EnumName(texImageTarget.get()),
- level);
- return false;
- }
-
- gl::GLContext* gl = mContext->gl;
- gl::ScopedBindTexture autoBindTex(gl, mGLName, mTarget.get());
-
- GLenum driverInternalFormat = LOCAL_GL_NONE;
- GLenum driverUnpackFormat = LOCAL_GL_NONE;
- GLenum driverUnpackType = LOCAL_GL_NONE;
- DriverFormatsFromEffectiveInternalFormat(gl, imageFormat, &driverInternalFormat,
- &driverUnpackFormat, &driverUnpackType);
+ const bool respecifyTexture = false;
+ const auto& usage = imageInfo.mFormat;
+ const auto& width = imageInfo.mWidth;
+ const auto& height = imageInfo.mHeight;
+ const auto& depth = imageInfo.mDepth;
- mContext->GetAndFlushUnderlyingGLErrors();
- if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
- gl->fTexSubImage3D(texImageTarget.get(), level, 0, 0, 0, imageInfo.mWidth,
- imageInfo.mHeight, imageInfo.mDepth, driverUnpackFormat,
- driverUnpackType, zeros.get());
- } else {
- MOZ_ASSERT(imageInfo.mDepth == 1);
- gl->fTexSubImage2D(texImageTarget.get(), level, 0, 0, imageInfo.mWidth,
- imageInfo.mHeight, driverUnpackFormat, driverUnpackType,
- zeros.get());
- }
-
- GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
- if (error) {
- // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover
- // from this here.
- if (error != LOCAL_GL_OUT_OF_MEMORY) {
- printf_stderr("Error: 0x%4x\n", error);
- gfxCriticalError() << "GL context GetAndFlushUnderlyingGLErrors " << gfx::hexa(error);
- // Errors on texture upload have been related to video
- // memory exposure in the past, which is a security issue.
- // Force loss of context.
- mContext->ForceLoseContext(true);
- return false;
- }
-
- // Out-of-memory uploading pixels to GL. Lose context and report OOM.
- mContext->ForceLoseContext(true);
- mContext->ErrorOutOfMemory("EnsureNoUninitializedImageData: Failed to "
- "upload texture of width: %u, height: %u, "
- "depth: %u to target %s level %d.",
- imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
- mContext->EnumName(texImageTarget.get()), level);
+ if (!ZeroTextureData(mContext, funcName, respecifyTexture, target, level, usage, 0, 0,
+ 0, width, height, depth))
+ {
return false;
}
imageInfo.SetIsDataInitialized(true, this);
return true;
}
void
@@ -755,46 +565,57 @@ WebGLTexture::ClampLevelBaseAndMax()
// `[level_base, levels-1]`, where `levels` is the parameter passed to
// TexStorage* for the texture object."
mBaseMipmapLevel = Clamp<uint32_t>(mBaseMipmapLevel, 0, mImmutableLevelCount - 1);
mMaxMipmapLevel = Clamp<uint32_t>(mMaxMipmapLevel, mBaseMipmapLevel,
mImmutableLevelCount - 1);
}
void
-WebGLTexture::PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel)
+WebGLTexture::PopulateMipChain(uint32_t firstLevel, uint32_t lastLevel)
{
- const ImageInfo& baseImageInfo = ImageInfoAtFace(0, baseLevel);
+ const ImageInfo& baseImageInfo = ImageInfoAtFace(0, firstLevel);
MOZ_ASSERT(baseImageInfo.IsDefined());
uint32_t refWidth = baseImageInfo.mWidth;
uint32_t refHeight = baseImageInfo.mHeight;
uint32_t refDepth = baseImageInfo.mDepth;
MOZ_ASSERT(refWidth && refHeight && refDepth);
- for (uint32_t level = baseLevel; level <= maxLevel; level++) {
+ for (uint32_t level = firstLevel; level <= lastLevel; level++) {
const ImageInfo cur(baseImageInfo.mFormat, refWidth, refHeight, refDepth,
baseImageInfo.IsDataInitialized());
SetImageInfosAtLevel(level, cur);
- // Higher levels are unaffected.
- if (refWidth == 1 &&
- refHeight == 1 &&
- refDepth == 1)
- {
- break;
+ bool isMinimal = (refWidth == 1 &&
+ refHeight == 1);
+ if (mTarget == LOCAL_GL_TEXTURE_3D) {
+ isMinimal &= (refDepth == 1);
}
- refWidth = std::max(uint32_t(1), refWidth / 2);
+ // Higher levels are unaffected.
+ if (isMinimal)
+ break;
+
+ refWidth = std::max(uint32_t(1), refWidth / 2);
refHeight = std::max(uint32_t(1), refHeight / 2);
- refDepth = std::max(uint32_t(1), refDepth / 2);
+ if (mTarget == LOCAL_GL_TEXTURE_3D) { // But not TEXTURE_2D_ARRAY!
+ refDepth = std::max(uint32_t(1), refDepth / 2);
+ }
}
}
+void
+WebGLTexture::InvalidateFakeBlackCache()
+{
+ mContext->InvalidateFakeBlackCache();
+ mFakeBlackStatus = WebGLTextureFakeBlackStatus::Unknown;
+}
+
//////////////////////////////////////////////////////////////////////////////////////////
// GL calls
bool
WebGLTexture::BindTexture(TexTarget texTarget)
{
// silently ignore a deleted texture
if (IsDeleted())
@@ -855,24 +676,24 @@ WebGLTexture::GenerateMipmap(TexTarget t
}
if (!mContext->IsWebGL2() && !baseImageInfo.IsPowerOfTwo()) {
mContext->ErrorInvalidOperation("generateMipmap: The base level of the texture does not"
" have power-of-two dimensions.");
return;
}
- auto format = baseImageInfo.mFormat;
- if (IsTextureFormatCompressed(format)) {
+ auto format = baseImageInfo.mFormat->format;
+ if (format->compression) {
mContext->ErrorInvalidOperation("generateMipmap: Texture data at base level is"
" compressed.");
return;
}
- if ((IsGLDepthFormat(format) || IsGLDepthStencilFormat(format)))
+ if (format->hasDepth)
return mContext->ErrorInvalidOperation("generateMipmap: Depth textures are not supported");
// Done with validation. Do the operation.
mContext->MakeContextCurrent();
gl::GLContext* gl = mContext->gl;
if (gl->WorkAroundDriverBugs()) {
@@ -1106,14 +927,16 @@ WebGLTexture::TexParameter(TexTarget tex
mContext->MakeContextCurrent();
if (maybeIntParam)
mContext->gl->fTexParameteri(texTarget.get(), pname, intParam);
else
mContext->gl->fTexParameterf(texTarget.get(), pname, floatParam);
}
+////////////////////////////////////////////////////////////////////////////////
+
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)
} // namespace mozilla
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -10,30 +10,35 @@
#include <map>
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/TypedArray.h"
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
-#include "WebGLContextUtils.h"
#include "WebGLFramebufferAttachable.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
namespace mozilla {
class ErrorResult;
+class WebGLContext;
namespace dom {
class Element;
class ImageData;
class ArrayBufferViewOrSharedArrayBufferView;
} // namespace dom
+namespace webgl {
+class TexUnpackBlob;
+} // namespace webgl
+
+
bool
DoesTargetMatchDimensions(WebGLContext* webgl, TexImageTarget target, uint8_t dims,
const char* funcName);
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
class WebGLTexture final
@@ -81,36 +86,36 @@ protected:
// decl for `mImageInfoArr`.
public:
class ImageInfo;
// And in turn, it needs these forwards:
protected:
// We need to forward these.
- void SetImageInfoAtFace(uint8_t face, uint32_t level, const ImageInfo& val);
- void SetImageInfosAtLevel(uint32_t level, const ImageInfo& val);
+ void SetImageInfo(ImageInfo* target, const ImageInfo& newInfo);
+ void SetImageInfosAtLevel(uint32_t level, const ImageInfo& newInfo);
public:
// We store information about the various images that are part of this
// texture. (cubemap faces, mipmap levels)
class ImageInfo
{
- friend void WebGLTexture::SetImageInfoAtFace(uint8_t face, uint32_t level,
- const ImageInfo& val);
+ friend void WebGLTexture::SetImageInfo(ImageInfo* target,
+ const ImageInfo& newInfo);
friend void WebGLTexture::SetImageInfosAtLevel(uint32_t level,
- const ImageInfo& val);
+ const ImageInfo& newInfo);
public:
static const ImageInfo kUndefined;
// This is the "effective internal format" of the texture, an official
// OpenGL spec concept, see OpenGL ES 3.0.3 spec, section 3.8.3, page
// 126 and below.
- const TexInternalFormat mFormat;
+ const webgl::FormatUsageInfo* const mFormat;
const uint32_t mWidth;
const uint32_t mHeight;
const uint32_t mDepth;
protected:
bool mIsDataInitialized;
@@ -120,27 +125,25 @@ public:
ImageInfo()
: mFormat(LOCAL_GL_NONE)
, mWidth(0)
, mHeight(0)
, mDepth(0)
, mIsDataInitialized(false)
{ }
- ImageInfo(TexInternalFormat format, uint32_t width, uint32_t height,
+ ImageInfo(const webgl::FormatUsageInfo* format, uint32_t width, uint32_t height,
uint32_t depth, bool isDataInitialized)
: mFormat(format)
, mWidth(width)
, mHeight(height)
, mDepth(depth)
, mIsDataInitialized(isDataInitialized)
{
- MOZ_ASSERT(mFormat != LOCAL_GL_NONE);
- MOZ_ASSERT_IF(!IsCompressedTextureFormat(mFormat.get()),
- mFormat != UnsizedInternalFormatFromInternalFormat(mFormat));
+ MOZ_ASSERT(mFormat);
}
void Clear();
~ImageInfo() {
if (!IsDefined())
Clear();
}
@@ -187,174 +190,103 @@ public:
explicit WebGLTexture(WebGLContext* webgl, GLuint tex);
void Delete();
bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
TexTarget Target() const { return mTarget; }
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
protected:
~WebGLTexture() {
DeleteOnce();
}
+
public:
////////////////////////////////////
// GL calls
bool BindTexture(TexTarget texTarget);
void GenerateMipmap(TexTarget texTarget);
JS::Value GetTexParameter(TexTarget texTarget, GLenum pname);
bool IsTexture() const;
void TexParameter(TexTarget texTarget, GLenum pname, GLint* maybeIntParam,
GLfloat* maybeFloatParam);
////////////////////////////////////
// WebGLTextureUpload.cpp
- void CompressedTexImage2D(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLint border, const dom::ArrayBufferViewOrSharedArrayBufferView& view);
-
- void CompressedTexImage3D(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLsizei depth, GLint border, GLsizei imageSize,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view);
-
-
- void CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset, GLsizei width,
- GLsizei height, GLenum unpackFormat,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view);
-
- void CompressedTexSubImage3D(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset, GLint zOffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum unpackFormat, GLsizei imageSize,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view);
-
-
- void CopyTexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
- GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-
-
- void CopyTexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLint x, GLint y, GLsizei width,
- GLsizei height);
-
- void CopyTexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
- GLsizei height);
-
+ void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum unpackFormat, GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView);
- void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLint border, GLenum unpackFormat,
- GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv);
- void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
- GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult* const out_rv);
- void TexImage2D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
- GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
- ErrorResult* const out_rv);
-
- void TexImage3D(TexImageTarget target, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth, GLint border,
- GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv);
-
-
- void TexStorage2D(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
- GLsizei width, GLsizei height);
- void TexStorage3D(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth);
-
+ void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::ImageData* imageData);
- void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLsizei width, GLsizei height, GLenum unpackFormat,
- GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv);
- void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLenum unpackFormat, GLenum unpackType,
- dom::ImageData* imageData, ErrorResult* const out_rv);
- void TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLenum unpackFormat, GLenum unpackType,
- dom::Element* elem, ErrorResult* const out_rv);
-
- void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
- GLsizei depth, GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv);
- void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLint zOffset, GLenum unpackFormat,
- GLenum unpackType, dom::ImageData* imageData,
- ErrorResult* const out_rv);
- void TexSubImage3D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLint zOffset, GLenum unpackFormat,
- GLenum unpackType, dom::Element* elem, ErrorResult* const out_rv);
+ void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLenum unpackFormat, GLenum unpackType,
+ dom::Element* elem, ErrorResult* const out_error);
protected:
-
- /** Like glTexImage2D, but if the call may change the texture size, checks
- * any GL error generated by this glTexImage2D call and returns it.
- */
- GLenum CheckedTexImage2D(TexImageTarget texImageTarget, GLint level,
- TexInternalFormat internalFormat, GLsizei width,
- GLsizei height, GLint border, TexFormat format,
- TexType type, const GLvoid* data);
+ void TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLint border, GLenum unpackFormat,
+ GLenum unpackType, webgl::TexUnpackBlob* blob);
- bool ValidateTexStorage(TexImageTarget texImageTarget, GLsizei levels, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- const char* funcName);
- void SpecifyTexStorage(GLsizei levels, TexInternalFormat internalFormat,
- GLsizei width, GLsizei height, GLsizei depth);
-
- void CopyTexSubImage2D_base(TexImageTarget texImageTarget,
- GLint level, GLenum rawInternalFormat,
- GLint xoffset, GLint yoffset, GLint x, GLint y,
- GLsizei width, GLsizei height, GLint border, bool isSub);
+ bool ValidateTexImageSpecification(const char* funcName, TexImageTarget target,
+ GLint level, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ WebGLTexture::ImageInfo** const out_imageInfo);
+ bool ValidateTexImageSelection(const char* funcName, TexImageTarget target,
+ GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth,
+ WebGLTexture::ImageInfo** const out_imageInfo);
- bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLenum unpackFormat,
- GLenum unpackType, dom::Element* elem);
+public:
+ void TexStorage(const char* funcName, TexTarget target, GLsizei levels,
+ GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth);
+protected:
+ void TexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLint border, GLenum unpackFormat,
+ GLenum unpackType, webgl::TexUnpackBlob* blob);
+ void TexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLenum unpackFormat,
+ GLenum unpackType, webgl::TexUnpackBlob* blob);
+public:
+ void CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+ void CompressedTexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view);
+ void CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+ void CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLint x, GLint y,
+ GLsizei width, GLsizei height);
- // If jsArrayType is MaxTypedArrayViewType, it means no array.
- void TexImage2D_base(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLsizei srcStrideOrZero, GLint border, GLenum unpackFormat,
- GLenum unpackType, void* data, uint32_t byteLength,
- js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat,
- bool srcPremultiplied);
- void TexSubImage2D_base(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLsizei width, GLsizei height,
- GLsizei srcStrideOrZero, GLenum unpackFormat,
- GLenum unpackType, void* pixels, uint32_t byteLength,
- js::Scalar::Type jsArrayType, WebGLTexelFormat srcFormat,
- bool srcPremultiplied);
+ ////////////////////////////////////
- bool ValidateTexStorage(TexTarget texTarget, GLsizei levels, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- const char* info);
- bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
-
+protected:
void ClampLevelBaseAndMax();
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
- ////////////////////////////////////
-
-protected:
uint32_t MaxEffectiveMipmapLevel() const;
static uint8_t FaceForTarget(TexImageTarget texImageTarget) {
GLenum rawTexImageTarget = texImageTarget.get();
switch (rawTexImageTarget) {
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -388,35 +320,33 @@ public:
const ImageInfo& ImageInfoAt(TexImageTarget texImageTarget, GLint level) const {
return const_cast<WebGLTexture*>(this)->ImageInfoAt(texImageTarget, level);
}
void SetImageInfoAt(TexImageTarget texImageTarget, GLint level,
const ImageInfo& val)
{
auto face = FaceForTarget(texImageTarget);
- return SetImageInfoAtFace(face, level, val);
+ ImageInfo* target = &ImageInfoAt(texImageTarget, level);
+ SetImageInfo(target, val);
}
const ImageInfo& BaseImageInfo() const {
if (mBaseMipmapLevel >= kMaxLevelCount)
return ImageInfo::kUndefined;
return ImageInfoAtFace(0, mBaseMipmapLevel);
}
size_t MemoryUsage() const;
+ bool InitializeImageData(const char* funcName, TexImageTarget target, uint32_t level);
protected:
- bool EnsureInitializedImageData(uint8_t face, uint32_t level);
-
- bool EnsureInitializedImageData(TexImageTarget texImageTarget, uint32_t level) {
- auto face = FaceForTarget(texImageTarget);
- return EnsureInitializedImageData(face, level);
- }
+ bool EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
+ uint32_t level);
bool CheckFloatTextureFilterParams() const {
// Without OES_texture_float_linear, only NEAREST and
// NEAREST_MIMPAMP_NEAREST are supported.
return mMagFilter == LOCAL_GL_NEAREST &&
(mMinFilter == LOCAL_GL_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
}
@@ -445,26 +375,24 @@ public:
bool IsComplete(const char** const out_reason) const;
bool IsMipmapCubeComplete() const;
bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
// Fake black status
protected:
- bool ResolveFakeBlackStatus();
+ bool ResolveFakeBlackStatus(const char* funcName);
public:
- bool ResolveFakeBlackStatus(WebGLTextureFakeBlackStatus* const out);
+ bool ResolveFakeBlackStatus(const char* funcName,
+ WebGLTextureFakeBlackStatus* const out);
WebGLTextureFakeBlackStatus FakeBlackStatus() const { return mFakeBlackStatus; }
- void InvalidateFakeBlackCache() {
- mContext->InvalidateFakeBlackCache();
- mFakeBlackStatus = WebGLTextureFakeBlackStatus::Unknown;
- }
+ void InvalidateFakeBlackCache();
};
inline TexImageTarget
TexImageTargetForTargetAndFace(TexTarget target, uint8_t face)
{
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_3D:
@@ -473,11 +401,28 @@ TexImageTargetForTargetAndFace(TexTarget
case LOCAL_GL_TEXTURE_CUBE_MAP:
MOZ_ASSERT(face < 6);
return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
default:
MOZ_CRASH();
}
}
+already_AddRefed<mozilla::layers::Image>
+ImageFromVideo(dom::HTMLVideoElement* elem);
+
+GLenum
+DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLenum internalFormat,
+ GLsizei width, GLsizei height, GLsizei depth, GLenum unpackFormat,
+ GLenum unpackType, const void* data);
+GLenum
+DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum unpackFormat, GLenum unpackType, const void* data);
+GLenum
+DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
+ GLsizei dataSize, const void* data);
+
} // namespace mozilla
#endif // WEBGL_TEXTURE_H_
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -6,26 +6,330 @@
#include "WebGLTexture.h"
#include <algorithm>
#include "CanvasUtils.h"
#include "GLBlitHelper.h"
#include "GLContext.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/ImageData.h"
+#include "mozilla/gfx/SourceSurfaceRawData.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Scoped.h"
#include "ScopedGLHelpers.h"
+#include "TexUnpackBlob.h"
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
#include "WebGLTexelConversions.h"
namespace mozilla {
+/* This file handles:
+ * TexStorage2D(texTarget, levels, internalFormat, width, height)
+ * TexStorage3D(texTarget, levels, intenralFormat, width, height, depth)
+ *
+ * TexImage2D(texImageTarget, level, internalFormat, width, height, border, unpackFormat,
+ * unpackType, data)
+ * TexImage3D(texImageTarget, level, internalFormat, width, height, depth, border,
+ * unpackFormat, unpackType, data)
+ * TexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height, unpackFormat,
+ * unpackType, data)
+ * TexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, width, height, depth,
+ * unpackFormat, unpackType, data)
+ *
+ * CompressedTexImage2D(texImageTarget, level, internalFormat, width, height, border,
+ * imageSize, data)
+ * CompressedTexImage3D(texImageTarget, level, internalFormat, width, height, depth,
+ * border, imageSize, data)
+ * CompressedTexSubImage2D(texImageTarget, level, xOffset, yOffset, width, height,
+ * sizedUnpackFormat, imageSize, data)
+ * CompressedTexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, width,
+ * height, depth, sizedUnpackFormat, imageSize, data)
+ *
+ * CopyTexImage2D(texImageTarget, level, internalFormat, x, y, width, height, border)
+ * CopyTexImage3D - "Because the framebuffer is inhererntly two-dimensional, there is no
+ * CopyTexImage3D command."
+ * CopyTexSubImage2D(texImageTarget, level, xOffset, yOffset, x, y, width, height)
+ * CopyTexSubImage3D(texImageTarget, level, xOffset, yOffset, zOffset, x, y, width,
+ * height)
+ */
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Some functions need an extra level of indirection, particularly for DOM Elements.
+
+already_AddRefed<mozilla::layers::Image>
+ImageFromVideo(dom::HTMLVideoElement* elem)
+{
+ uint16_t readyState;
+ if (NS_SUCCEEDED(elem->GetReadyState(&readyState)) &&
+ readyState < elem->HAVE_CURRENT_DATA)
+ {
+ // No frame inside, just return
+ return nullptr;
+ }
+
+ RefPtr<layers::ImageContainer> container = elem->GetImageContainer();
+ if (!container)
+ return nullptr;
+
+ nsAutoTArray<layers::ImageContainer::OwningImage, 4> currentImages;
+ container->GetCurrentImages(¤tImages);
+
+ if (!currentImages.Length())
+ return nullptr;
+
+ RefPtr<mozilla::layers::Image> ret = currentImages[0].mImage;
+ return ret.forget();
+}
+
+static already_AddRefed<gfx::DataSourceSurface>
+DataFromElement(dom::Element* elem, WebGLContext* webgl)
+{
+ const auto sfeRes = webgl->SurfaceFromElement(elem);
+
+ RefPtr<gfx::DataSourceSurface> data;
+ WebGLTexelFormat srcFormat;
+ nsresult rv = webgl->SurfaceFromElementResultToImageSurface(sfeRes, &data,
+ &srcFormat);
+ if (NS_FAILED(rv) || !data)
+ return nullptr;
+
+ return data.forget();
+}
+
+////////////////////////////////////////
+// ArrayBufferView?
+
+static inline bool
+DoesJSTypeMatchUnpackType(GLenum unpackType, js::Scalar::Type jsType)
+{
+ switch (unpackType) {
+ case LOCAL_GL_BYTE:
+ return jsType == js::Scalar::Type::Int8;
+
+ case LOCAL_GL_UNSIGNED_BYTE:
+ return jsType == js::Scalar::Type::Uint8 ||
+ jsType == js::Scalar::Type::Uint8Clamped;
+
+ case LOCAL_GL_SHORT:
+ return jsType == js::Scalar::Type::Int16;
+
+ case LOCAL_GL_UNSIGNED_SHORT:
+ 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:
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+ return jsType == js::Scalar::Type::Uint16;
+
+ case LOCAL_GL_INT:
+ return jsType == js::Scalar::Type::Int32;
+
+ case LOCAL_GL_UNSIGNED_INT:
+ case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+ case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+ case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
+ case LOCAL_GL_UNSIGNED_INT_24_8:
+ return jsType == js::Scalar::Type::Uint32;
+
+ case LOCAL_GL_FLOAT:
+ return jsType == js::Scalar::Type::Float32;
+
+ default:
+ return false;
+ }
+}
+
+static bool
+ValidateUnpackArrayType(WebGLContext* webgl, const char* funcName, GLenum unpackType,
+ js::Scalar::Type jsType)
+{
+ if (DoesJSTypeMatchUnpackType(unpackType, jsType))
+ return true;
+
+ webgl->ErrorInvalidOperation("%s: `pixels` be compatible with unpack `type`.",
+ funcName);
+ return false;
+}
+
+static UniquePtr<webgl::TexUnpackBlob>
+UnpackBlobFromMaybeView(WebGLContext* webgl, const char* funcName, GLsizei width,
+ GLsizei height, GLsizei depth, GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
+{
+ size_t dataSize;
+ const void* data;
+ if (maybeView.IsNull()) {
+ dataSize = 0;
+ data = nullptr;
+ } else {
+ const auto& view = maybeView.Value();
+ void* mutData;
+ js::Scalar::Type jsType;
+ ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
+ data = mutData;
+
+ if (!ValidateUnpackArrayType(webgl, funcName, unpackType, jsType))
+ return nullptr;
+ }
+
+ UniquePtr<webgl::TexUnpackBlob> ret;
+ ret.reset(new webgl::TexUnpackBytes(width, height, depth, dataSize, data));
+ return Move(ret);
+}
+
+void
+WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border, GLenum unpackFormat,
+ GLenum unpackType,
+ const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView)
+{
+ UniquePtr<webgl::TexUnpackBlob> blob;
+ blob = UnpackBlobFromMaybeView(mContext, funcName, width, height, depth, unpackType,
+ maybeView);
+ if (!blob)
+ return;
+
+ TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
+ zOffset, border, unpackFormat, unpackType, blob.get());
+}
+
+////////////////////////////////////////
+// ImageData
+
+static UniquePtr<webgl::TexUnpackBlob>
+UnpackBlobFromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
+ dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
+{
+ if (!imageData) {
+ // Spec says to generate an INVALID_VALUE error
+ webgl->ErrorInvalidValue("%s: null ImageData", funcName);
+ return nullptr;
+ }
+
+ DebugOnly<bool> inited = scopedArr->Init(imageData->GetDataObject());
+ MOZ_ASSERT(inited);
+
+ scopedArr->ComputeLengthAndData();
+ const DebugOnly<size_t> dataSize = scopedArr->Length();
+ const void* const data = scopedArr->Data();
+
+ const gfx::IntSize size(imageData->Width(), imageData->Height());
+ const size_t stride = size.width * 4;
+ const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
+ const bool ownsData = false;
+
+ MOZ_ASSERT(dataSize == stride * size.height);
+
+ const RefPtr<gfx::SourceSurfaceRawData> surf = new gfx::SourceSurfaceRawData;
+
+ uint8_t* wrappableData = (uint8_t*)data;
+ surf->InitWrappingData(wrappableData, size, stride, surfFormat, ownsData);
+
+ // WhatWG "HTML Living Standard" (30 October 2015):
+ // "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
+ // non-premultiplied alpha values."
+ const bool surfIsAlphaPremult = false;
+
+ UniquePtr<webgl::TexUnpackBlob> ret;
+ ret.reset(new webgl::TexUnpackSurface(surf, surfIsAlphaPremult));
+ return Move(ret);
+}
+
+void
+WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum unpackFormat,
+ GLenum unpackType, dom::ImageData* imageData)
+{
+ dom::Uint8ClampedArray scopedArr;
+
+ UniquePtr<webgl::TexUnpackBlob> blob;
+ blob = UnpackBlobFromImageData(mContext, funcName, unpackType, imageData, &scopedArr);
+ if (!blob)
+ return;
+
+ const GLint border = 0;
+ TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
+ zOffset, border, unpackFormat, unpackType, blob.get());
+}
+
+////////////////////////////////////////
+// dom::Element
+
+void
+WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLenum unpackFormat,
+ GLenum unpackType, dom::Element* elem,
+ ErrorResult* const out_error)
+{
+ auto sfer = mContext->SurfaceFromElement(elem);
+ if (!sfer.mSourceSurface) {
+ mContext->ErrorInvalidOperation("%s: Failed to get data from DOM element.",
+ funcName);
+ return;
+ }
+
+ if (sfer.mIsWriteOnly) {
+ mContext->GenerateWarning("%s: Element is write-only.", funcName);
+ out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ if (!sfer.mCORSUsed) {
+ auto& srcPrincipal = sfer.mPrincipal;
+ nsIPrincipal* dstPrincipal = mContext->GetCanvas()->NodePrincipal();
+
+ if (!dstPrincipal->Subsumes(srcPrincipal)) {
+ mContext->GenerateWarning("%s: Cross-origin elements require CORS.",
+ funcName);
+ out_error->Throw(NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+ }
+
+ auto& srcSurf = sfer.mSourceSurface;
+
+ UniquePtr<webgl::TexUnpackBlob> blob;
+ blob.reset(new webgl::TexUnpackSurface(srcSurf, sfer.mIsPremultiplied));
+
+ const GLint border = 0;
+ TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset, yOffset,
+ zOffset, border, unpackFormat, unpackType, blob.get());
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void
+WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
+ GLint level, GLenum internalFormat, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLint border,
+ GLenum unpackFormat, GLenum unpackType,
+ webgl::TexUnpackBlob* blob)
+{
+ if (isSubImage) {
+ TexSubImage(funcName, target, level, xOffset, yOffset, zOffset, unpackFormat,
+ unpackType, blob);
+ } else {
+ TexImage(funcName, target, level, internalFormat, border, unpackFormat,
+ unpackType, blob);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+
+/* This needs to be done (but cached) per texture per draw call.
+
// Map R to A
static const GLenum kLegacyAlphaSwizzle[4] = {
LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_RED
};
// Map R to RGB
static const GLenum kLegacyLuminanceSwizzle[4] = {
LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_ONE
};
@@ -35,17 +339,17 @@ static const GLenum kLegacyLuminanceAlph
};
static void
SetLegacyTextureSwizzle(gl::GLContext* gl, GLenum target, GLenum internalformat)
{
if (!gl->IsCoreProfile())
return;
- /* Only support swizzling on core profiles. */
+ // Only support swizzling on core profiles.
// Bug 1159117: Fix this.
// MOZ_RELEASE_ASSERT(gl->IsSupported(gl::GLFeature::texture_swizzle));
switch (internalformat) {
case LOCAL_GL_ALPHA:
gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
(GLint*) kLegacyAlphaSwizzle);
break;
@@ -56,1472 +360,1405 @@ SetLegacyTextureSwizzle(gl::GLContext* g
break;
case LOCAL_GL_LUMINANCE_ALPHA:
gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
(GLint*) kLegacyLuminanceAlphaSwizzle);
break;
}
}
+*/
+//////////////////////////////////////////////////////////////////////////////////////////
+// Utils
+
+static bool
+ValidateTexImage(WebGLContext* webgl, WebGLTexture* texture, const char* funcName,
+ TexImageTarget target, GLint level,
+ WebGLTexture::ImageInfo** const out_imageInfo)
+{
+ // Check level
+ if (level < 0) {
+ webgl->ErrorInvalidValue("%s: `level` must be >= 0.", funcName);
+ return false;
+ }
+
+ if (level > 31) {
+ // Right-shift is only defined for bits-1, so 31 for GLsizei.
+ webgl->ErrorInvalidValue("%s: `level` is too large.", funcName);
+ return false;
+ }
+
+ WebGLTexture::ImageInfo& imageInfo = texture->ImageInfoAt(target, level);
+
+ *out_imageInfo = &imageInfo;
+ return true;
+}
+
+
+// For *TexImage*
+bool
+WebGLTexture::ValidateTexImageSpecification(const char* funcName, TexImageTarget target,
+ GLint level, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ WebGLTexture::ImageInfo** const out_imageInfo)
+{
+ if (mImmutable) {
+ mContext->ErrorInvalidOperation("%s: Specified texture is immutable.", funcName);
+ return false;
+ }
+
+ // Check border
+ if (border != 0) {
+ mContext->ErrorInvalidValue("%s: `border` must be 0.", funcName);
+ return false;
+ }
+
+ if (level < 0 || width < 0 || height < 0 || depth < 0) {
+ /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
+ * "If wt and ht are the specified image width and height,
+ * and if either wt or ht are less than zero, then the error
+ * INVALID_VALUE is generated."
+ */
+ mContext->ErrorInvalidValue("%s: `level`/`width`/`height`/`depth` must be >= 0.",
+ funcName);
+ return false;
+ }
+
+ /* GLES 3.0.4, p133-134:
+ * GL_MAX_TEXTURE_SIZE is *not* the max allowed texture size. Rather, it is the
+ * max (width/height) size guaranteed not to generate an INVALID_VALUE for too-large
+ * dimensions. Sizes larger than GL_MAX_TEXTURE_SIZE *may or may not* result in an
+ * INVALID_VALUE, or possibly GL_OOM.
+ *
+ * However, we have needed to set our maximums lower in the past to prevent resource
+ * corruption. Therefore we have mImplMaxTextureSize, which is neither necessarily
+ * lower nor higher than MAX_TEXTURE_SIZE.
+ *
+ * Note that mImplMaxTextureSize must be >= than the advertized MAX_TEXTURE_SIZE.
+ * For simplicity, we advertize MAX_TEXTURE_SIZE as mImplMaxTextureSize.
+ */
+
+ uint32_t maxWidthHeight = 0;
+ uint32_t maxDepth = 0;
+
+ if (level <= 31) {
+ switch (target.get()) {
+ case LOCAL_GL_TEXTURE_2D:
+ maxWidthHeight = mContext->mImplMaxTextureSize >> level;
+ maxDepth = 1;
+ break;
+
+ case LOCAL_GL_TEXTURE_3D:
+ maxWidthHeight = mContext->mImplMax3DTextureSize >> level;
+ maxDepth = maxWidthHeight;
+ break;
+
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ maxWidthHeight = mContext->mImplMaxTextureSize >> level;
+ // "The maximum number of layers for two-dimensional array textures (depth)
+ // must be at least MAX_ARRAY_TEXTURE_LAYERS for all levels."
+ maxDepth = mContext->mImplMaxArrayTextureLayers;
+ break;
+
+ default: // cube maps
+ MOZ_ASSERT(IsCubeMap());
+ maxWidthHeight = mContext->mImplMaxCubeMapTextureSize >> level;
+ maxDepth = 1;
+ break;
+ }
+ }
+
+ if (uint32_t(width) > maxWidthHeight ||
+ uint32_t(height) > maxWidthHeight ||
+ uint32_t(depth) > maxDepth)
+ {
+ mContext->ErrorInvalidValue("%s: Requested size at this level is unsupported.",
+ funcName);
+ return false;
+ }
+
+ {
+ /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
+ * "If level is greater than zero, and either width or
+ * height is not a power-of-two, the error INVALID_VALUE is
+ * generated."
+ *
+ * This restriction does not apply to GL ES Version 3.0+.
+ */
+ bool requirePOT = (!mContext->IsWebGL2() && level != 0);
+
+ if (requirePOT) {
+ if (!IsPowerOfTwo(uint32_t(width)) || !IsPowerOfTwo(uint32_t(height))) {
+ mContext->ErrorInvalidValue("%s: For level > 0, width and height must be"
+ " powers of two.",
+ funcName);
+ return false;
+ }
+ }
+ }
+
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImage(mContext, this, funcName, target, level, &imageInfo))
+ return false;
+
+ *out_imageInfo = imageInfo;
+ return true;
+}
+
+// For *TexSubImage*
bool
-DoesTargetMatchDimensions(WebGLContext* webgl, TexImageTarget target, uint8_t funcDims,
- const char* funcName)
+WebGLTexture::ValidateTexImageSelection(const char* funcName, TexImageTarget target,
+ GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth,
+ WebGLTexture::ImageInfo** const out_imageInfo)
+{
+ if (mImmutable) {
+ mContext->ErrorInvalidOperation("%s: Specified texture is immutable.", funcName);
+ return false;
+ }
+
+ // The conformance test wants bad arg checks before imageInfo checks.
+ if (xOffset < 0 || yOffset < 0 || zOffset < 0 ||
+ width < 0 || height < 0 || depth < 0)
+ {
+ mContext->ErrorInvalidValue("%s: Offsets and dimensions must be >=0.", funcName);
+ return false;
+ }
+
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImage(mContext, this, funcName, target, level, &imageInfo))
+ return false;
+
+ if (!imageInfo->IsDefined()) {
+ mContext->ErrorInvalidOperation("%s: The specified TexImage has not yet been"
+ " specified.",
+ funcName);
+ return false;
+ }
+
+ const auto totalX = CheckedUint32(xOffset) + width;
+ const auto totalY = CheckedUint32(yOffset) + height;
+ const auto totalZ = CheckedUint32(zOffset) + depth;
+
+ if (!totalX.isValid() || totalX.value() > imageInfo->mWidth ||
+ !totalY.isValid() || totalY.value() > imageInfo->mHeight ||
+ !totalZ.isValid() || totalZ.value() > imageInfo->mDepth)
+ {
+ mContext->ErrorInvalidValue("%s: Offset+size must be <= the size of the existing"
+ " specified image.",
+ funcName);
+ return false;
+ }
+
+ *out_imageInfo = imageInfo;
+ return true;
+}
+
+static bool
+ValidateCompressedTexUnpack(WebGLContext* webgl, const char* funcName, GLsizei width,
+ GLsizei height, GLsizei depth,
+ const webgl::FormatInfo* format, size_t dataSize)
+{
+ auto compression = format->compression;
+
+ auto bytesPerBlock = compression->bytesPerBlock;
+ auto blockWidth = compression->blockWidth;
+ auto blockHeight = compression->blockHeight;
+
+ CheckedUint32 widthInBlocks = (width % blockWidth) ? width / blockWidth + 1
+ : width / blockWidth;
+ CheckedUint32 heightInBlocks = (height % blockHeight) ? height / blockHeight + 1
+ : height / blockHeight;
+ CheckedUint32 blocksPerImage = widthInBlocks * heightInBlocks;
+ CheckedUint32 bytesPerImage = bytesPerBlock * blocksPerImage;
+ CheckedUint32 bytesNeeded = bytesPerImage * depth;
+
+ if (!bytesNeeded.isValid()) {
+ webgl->ErrorOutOfMemory("%s: Overflow while computing the needed buffer size.",
+ funcName);
+ return false;
+ }
+
+ if (dataSize != bytesNeeded.value()) {
+ webgl->ErrorInvalidValue("%s: Provided buffer's size must match expected size."
+ " (needs %u, has %u)",
+ funcName, bytesNeeded.value(), dataSize);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+DoChannelsMatchForCopyTexImage(const webgl::FormatInfo* srcFormat,
+ const webgl::FormatInfo* dstFormat)
{
- uint8_t targetDims;
+ // GLES 3.0.4 p140 Table 3.16 "Valid CopyTexImage source framebuffer/destination
+ // texture base internal format combinations."
+
+ switch (srcFormat->unsizedFormat) {
+ case webgl::UnsizedFormat::RGBA:
+ switch (dstFormat->unsizedFormat) {
+ case webgl::UnsizedFormat::A:
+ case webgl::UnsizedFormat::L:
+ case webgl::UnsizedFormat::LA:
+ case webgl::UnsizedFormat::R:
+ case webgl::UnsizedFormat::RG:
+ case webgl::UnsizedFormat::RGB:
+ case webgl::UnsizedFormat::RGBA:
+ return true;
+ default:
+ return false;
+ }
+
+ case webgl::UnsizedFormat::RGB:
+ switch (dstFormat->unsizedFormat) {
+ case webgl::UnsizedFormat::L:
+ case webgl::UnsizedFormat::R:
+ case webgl::UnsizedFormat::RG:
+ case webgl::UnsizedFormat::RGB:
+ return true;
+ default:
+ return false;
+ }
+
+ case webgl::UnsizedFormat::RG:
+ switch (dstFormat->unsizedFormat) {
+ case webgl::UnsizedFormat::L:
+ case webgl::UnsizedFormat::R:
+ case webgl::UnsizedFormat::RG:
+ return true;
+ default:
+ return false;
+ }
+
+ case webgl::UnsizedFormat::R:
+ switch (dstFormat->unsizedFormat) {
+ case webgl::UnsizedFormat::L:
+ case webgl::UnsizedFormat::R:
+ return true;
+ default:
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+static bool
+EnsureImageDataInitializedForUpload(WebGLTexture* tex, const char* funcName,
+ TexImageTarget target, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth,
+ WebGLTexture::ImageInfo* imageInfo,
+ bool* const out_uploadWillInitialize)
+{
+ *out_uploadWillInitialize = false;
+
+ if (!imageInfo->IsDataInitialized()) {
+ const bool isFullUpload = (!xOffset && !yOffset && !zOffset &&
+ width == imageInfo->mWidth &&
+ height == imageInfo->mHeight &&
+ depth == imageInfo->mDepth);
+ if (isFullUpload) {
+ *out_uploadWillInitialize = true;
+ } else {
+ WebGLContext* webgl = tex->mContext;
+ webgl->GenerateWarning("%s: Texture has not been initialized prior to a"
+ " partial upload, forcing the browser to clear it."
+ " This may be slow.",
+ funcName);
+ if (!tex->InitializeImageData(funcName, target, level)) {
+ MOZ_ASSERT(false, "Unexpected failure to init image data.");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+// Actual calls
+
+static inline GLenum
+DoTexStorage(gl::GLContext* gl, TexTarget target, GLsizei levels, GLenum sizedFormat,
+ GLsizei width, GLsizei height, GLsizei depth)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ switch (target.get()) {
+ case LOCAL_GL_TEXTURE_2D:
+ case LOCAL_GL_TEXTURE_CUBE_MAP:
+ MOZ_ASSERT(depth == 1);
+ gl->fTexStorage2D(target.get(), levels, sizedFormat, width, height);
+ break;
+
+ case LOCAL_GL_TEXTURE_3D:
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ gl->fTexStorage3D(target.get(), levels, sizedFormat, width, height, depth);
+ break;
+
+ default:
+ MOZ_CRASH("bad target");
+ }
+
+ return errorScope.GetError();
+}
+
+static bool
+Is3D(TexImageTarget target)
+{
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- targetDims = 2;
+ return false;
+
+ case LOCAL_GL_TEXTURE_3D:
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ return true;
+
+ default:
+ MOZ_CRASH("bad target");
+ }
+}
+
+GLenum
+DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLenum internalFormat,
+ GLsizei width, GLsizei height, GLsizei depth, GLenum unpackFormat,
+ GLenum unpackType, const void* data)
+{
+ const GLint border = 0;
+
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ if (Is3D(target)) {
+ gl->fTexImage3D(target.get(), level, internalFormat, width, height, depth,
+ border, unpackFormat, unpackType, data);
+ } else {
+ MOZ_ASSERT(depth == 1);
+ gl->fTexImage2D(target.get(), level, internalFormat, width, height, border,
+ unpackFormat, unpackType, data);
+ }
+
+ return errorScope.GetError();
+}
+
+GLenum
+DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
+ GLenum unpackFormat, GLenum unpackType, const void* data)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ if (Is3D(target)) {
+ gl->fTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, width, height,
+ depth, unpackFormat, unpackType, data);
+ } else {
+ MOZ_ASSERT(zOffset == 0);
+ MOZ_ASSERT(depth == 1);
+ gl->fTexSubImage2D(target.get(), level, xOffset, yOffset, width, height,
+ unpackFormat, unpackType, data);
+ }
+
+ return errorScope.GetError();
+}
+
+static inline GLenum
+DoCompressedTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLsizei dataSize, const void* data)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ if (Is3D(target)) {
+ gl->fCompressedTexImage3D(target.get(), level, internalFormat, width, height,
+ depth, border, dataSize, data);
+ } else {
+ MOZ_ASSERT(depth == 1);
+ gl->fCompressedTexImage2D(target.get(), level, internalFormat, width, height,
+ border, dataSize, data);
+ }
+
+ return errorScope.GetError();
+}
+
+GLenum
+DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLsizei width,
+ GLsizei height, GLsizei depth, GLenum sizedUnpackFormat,
+ GLsizei dataSize, const void* data)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ if (Is3D(target)) {
+ gl->fCompressedTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset,
+ width, height, depth, sizedUnpackFormat, dataSize,
+ data);
+ } else {
+ MOZ_ASSERT(zOffset == 0);
+ MOZ_ASSERT(depth == 1);
+ gl->fCompressedTexSubImage2D(target.get(), level, xOffset, yOffset, width,
+ height, sizedUnpackFormat, dataSize, data);
+ }
+
+ return errorScope.GetError();
+}
+
+static inline GLenum
+DoCopyTexImage2D(gl::GLContext* gl, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ MOZ_ASSERT(!Is3D(target));
+ gl->fCopyTexImage2D(target.get(), level, internalFormat, x, y, width, height,
+ border);
+
+ return errorScope.GetError();
+}
+
+static inline GLenum
+DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
+ GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei width,
+ GLsizei height)
+{
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+
+ if (Is3D(target)) {
+ gl->fCopyTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, x, y,
+ width, height);
+ } else {
+ MOZ_ASSERT(zOffset == 0);
+ gl->fCopyTexSubImage2D(target.get(), level, xOffset, yOffset, x, y, width,
+ height);
+ }
+
+ return errorScope.GetError();
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+// Actual (mostly generic) function implementations
+
+static bool
+ValidateCompressedTexImageRestrictions(const char* funcName, WebGLContext* webgl,
+ TexImageTarget target, uint32_t level,
+ const webgl::FormatInfo* format, uint32_t width,
+ uint32_t height, uint32_t depth)
+{
+ const auto fnIsDimValid_S3TC = [level](uint32_t size, uint32_t blockSize) {
+ if (size % blockSize == 0)
+ return true;
+
+ if (level == 0)
+ return false;
+
+ return (size == 0 || size == 1 || size == 2);
+ };
+
+ bool supports2DArray = false;
+ switch (format->compression->family) {
+ case webgl::CompressionFamily::PVRTC:
+ if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height)) {
+ webgl->ErrorInvalidValue("%s: %s requires power-of-two width and height.",
+ funcName, format->name);
+ return false;
+ }
+
break;
+ // Block-aligned:
+ case webgl::CompressionFamily::ES3:
+ supports2DArray = true;
+ break;
+
+ case webgl::CompressionFamily::S3TC:
+ supports2DArray = true;
+
+ if (!fnIsDimValid_S3TC(width, format->compression->blockWidth) ||
+ !fnIsDimValid_S3TC(height, format->compression->blockHeight))
+ {
+ webgl->ErrorInvalidOperation("%s: %s requires that width and height are"
+ " block-aligned, or, if level>0, equal to 0, 1,"
+ " or 2.",
+ funcName, format->name);
+ return false;
+ }
+
+ break;
+
+ // Default: There are no restrictions on CompressedTexImage.
+ default: // ATC, ETC1
+ break;
+ }
+
+ bool targetSupported = true;
+ switch (target.get()) {
case LOCAL_GL_TEXTURE_3D:
- targetDims = 3;
+ targetSupported = false;
+ break;
+
+ case LOCAL_GL_TEXTURE_2D_ARRAY:
+ targetSupported = supports2DArray;
+ break;
+ }
+
+ if (!targetSupported) {
+ webgl->ErrorInvalidOperation("%s: This target is not supported by this %s.",
+ funcName, format->name);
+ return false;
+ }
+
+ return true;
+}
+
+void
+WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
+ GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth)
+{
+ // Check levels
+ if (levels < 1) {
+ mContext->ErrorInvalidValue("%s: `levels` must be >= 1.", funcName);
+ return;
+ }
+
+ if (levels > 31) {
+ // Right-shift is only defined for bits-1, so 31 for GLsizei.
+ // Besides,
+ mContext->ErrorInvalidValue("%s: `level` is too large.", funcName);
+ return;
+ }
+
+ const TexImageTarget testTarget = IsCubeMap() ? LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ : target.get();
+ const GLint testLevel = 0;
+ const GLint border = 0;
+
+ WebGLTexture::ImageInfo* testImageInfo;
+ if (!ValidateTexImageSpecification(funcName, testTarget, testLevel, width, height,
+ depth, border, &testImageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(testImageInfo);
+ mozilla::unused << testImageInfo;
+
+ auto dstUsage = mContext->mFormatUsage->GetSizedTexUsage(sizedFormat);
+ if (!dstUsage) {
+ mContext->ErrorInvalidEnum("%s: Invalid internalformat: 0x%04x", funcName,
+ sizedFormat);
+ return;
+ }
+ auto dstFormat = dstUsage->format;
+
+ if (dstFormat->compression) {
+ if (!ValidateCompressedTexImageRestrictions(funcName, mContext, testTarget,
+ testLevel, dstFormat, width, height,
+ depth))
+ {
+ return;
+ }
+ }
+
+ ////////////////////////////////////
+ // Do the thing!
+
+ mContext->gl->MakeCurrent();
+
+ GLenum error = DoTexStorage(mContext->gl, target.get(), levels, sizedFormat, width,
+ height, depth);
+
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Ran out of memory during texture allocation.",
+ funcName);
+ return;
+ }
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
+ mContext->ErrorInvalidOperation("%s: Unexpected error during texture allocation.",
+ funcName);
+ return;
+ }
+
+ ////////////////////////////////////
+ // Update our specification data.
+
+ const bool isDataInitialized = false;
+ const WebGLTexture::ImageInfo newInfo(dstUsage, width, height, depth,
+ isDataInitialized);
+ SetImageInfosAtLevel(0, newInfo);
+
+ PopulateMipChain(0, levels-1);
+}
+
+////////////////////////////////////////
+// Tex(Sub)Image
+
+static bool
+ValidateUnpackEnums(const webgl::PackingInfo& pi, WebGLContext* webgl,
+ const char* funcName)
+{
+ switch (pi.format) {
+ case LOCAL_GL_RED:
+ case LOCAL_GL_RED_INTEGER:
+ case LOCAL_GL_DEPTH_COMPONENT:
+ case LOCAL_GL_LUMINANCE:
+ case LOCAL_GL_ALPHA:
+
+ case LOCAL_GL_RG:
+ case LOCAL_GL_RG_INTEGER:
+ case LOCAL_GL_LUMINANCE_ALPHA:
+ case LOCAL_GL_DEPTH_STENCIL:
+
+ case LOCAL_GL_RGB:
+ case LOCAL_GL_RGB_INTEGER:
+
+ case LOCAL_GL_RGBA:
+ case LOCAL_GL_RGBA_INTEGER:
break;
default:
- MOZ_CRASH("Unhandled texImageTarget.");
+ webgl->ErrorInvalidEnum("%s: Invalid format enum: 0x%04x",
+ funcName, pi.format);
+ return false;
}
- if (targetDims != funcDims) {
- webgl->ErrorInvalidEnum("%s: `target` must match function dimensions.", funcName);
+ switch (pi.type) {
+ case LOCAL_GL_UNSIGNED_BYTE:
+ case LOCAL_GL_UNSIGNED_SHORT:
+ case LOCAL_GL_UNSIGNED_INT:
+ case LOCAL_GL_BYTE:
+ case LOCAL_GL_SHORT:
+ case LOCAL_GL_INT:
+ case LOCAL_GL_FLOAT:
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+
+ case LOCAL_GL_UNSIGNED_INT_24_8:
+ case LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+
+ case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+ case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+ case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
+
+ case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+ case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+ case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+ break;
+
+ default:
+ webgl->ErrorInvalidEnum("%s: Invalid type enum: 0x%04x",
+ funcName, pi.type);
return false;
}
return true;
}
void
-WebGLTexture::SpecifyTexStorage(GLsizei levels, TexInternalFormat internalFormat,
- GLsizei width, GLsizei height, GLsizei depth)
+WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLint border, GLenum unpackFormat,
+ GLenum unpackType, webgl::TexUnpackBlob* blob)
{
- mImmutable = true;
- mImmutableLevelCount = levels;
- ClampLevelBaseAndMax();
-
- // GLES 3.0.4, p136:
- // "* Any existing levels that are not replaced are reset to their
- // initial state."
- for (auto& cur : mImageInfoArr) {
- cur.Clear();
- }
-
- const bool isDataInitialized = false;
- const ImageInfo baseImageInfo(internalFormat, width, height, depth,
- isDataInitialized);
-
- SetImageInfoAtFace(0, 0, baseImageInfo);
- PopulateMipChain(0, mImmutableLevelCount);
-}
+ ////////////////////////////////////
+ // Get dest info
-void
-WebGLTexture::CompressedTexImage2D(TexImageTarget texImageTarget,
- GLint level,
- GLenum internalFormat,
- GLsizei width, GLsizei height, GLint border,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view)
-{
- const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
-
- const char funcName[] = "compressedTexImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
-
- if (!mContext->ValidateTexImage(texImageTarget.get(), level, internalFormat,
- 0, 0, 0, width, height, 0,
- border, LOCAL_GL_NONE,
- LOCAL_GL_NONE,
- func, dims))
- {
- return;
- }
-
- size_t byteLength;
- void* data;
- js::Scalar::Type dataType;
- ComputeLengthAndData(view, &data, &byteLength, &dataType);
-
- if (!mContext->ValidateCompTexImageDataSize(level, internalFormat, width, height, byteLength, func, dims)) {
- return;
- }
-
- if (!mContext->ValidateCompTexImageSize(level, internalFormat, 0, 0, width, height, width, height, func, dims))
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSpecification(funcName, target, level, blob->mWidth,
+ blob->mHeight, blob->mDepth, border, &imageInfo))
{
return;
}
-
- if (mImmutable) {
- return mContext->ErrorInvalidOperation(
- "compressedTexImage2D: disallowed because the texture bound to "
- "this target has already been made immutable by texStorage2D");
- }
-
- mContext->MakeContextCurrent();
- gl::GLContext* gl = mContext->gl;
- gl->fCompressedTexImage2D(texImageTarget.get(), level, internalFormat, width, height, border, byteLength, data);
-
- const uint32_t depth = 1;
- const bool isDataInitialized = true;
- const ImageInfo imageInfo(internalFormat, width, height, depth, isDataInitialized);
+ MOZ_ASSERT(imageInfo);
- SetImageInfoAt(texImageTarget, level, imageInfo);
-}
-
-void
-WebGLTexture::CompressedTexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLsizei width, GLsizei height,
- GLenum internalFormat,
- const dom::ArrayBufferViewOrSharedArrayBufferView& view)
-{
- const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
-
- const char funcName[] = "compressedTexSubImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
+ const webgl::PackingInfo srcPacking = { unpackFormat, unpackType };
+ if (!ValidateUnpackEnums(srcPacking, mContext, funcName))
return;
- if (!mContext->ValidateTexImage(texImageTarget.get(),
- level, internalFormat,
- xOffset, yOffset, 0,
- width, height, 0,
- 0, LOCAL_GL_NONE, LOCAL_GL_NONE,
- func, dims))
- {
- return;
+ auto dstUsage = mContext->mFormatUsage->GetSizedTexUsage(internalFormat);
+ if (!dstUsage) {
+ if (internalFormat != unpackFormat) {
+ mContext->ErrorInvalidOperation("%s: Unsized internalFormat must match"
+ " unpack format.",
+ funcName);
+ return;
+ }
+
+ dstUsage = mContext->mFormatUsage->GetUnsizedTexUsage(srcPacking);
}
- ImageInfo& levelInfo = ImageInfoAt(texImageTarget, level);
-
- if (internalFormat != levelInfo.mFormat) {
- return mContext->ErrorInvalidOperation("compressedTexImage2D: internalFormat does not match the existing image");
- }
-
- size_t byteLength;
- void* data;
- js::Scalar::Type dataType;
- ComputeLengthAndData(view, &data, &byteLength, &dataType);
-
- if (!mContext->ValidateCompTexImageDataSize(level, internalFormat, width, height, byteLength, func, dims))
- return;
-
- if (!mContext->ValidateCompTexImageSize(level, internalFormat,
- xOffset, yOffset,
- width, height,
- levelInfo.mWidth, levelInfo.mHeight,
- func, dims))
- {
+ if (!dstUsage) {
+ mContext->ErrorInvalidOperation("%s: Invalid internalformat/format/type:"
+ " 0x%04x/0x%04x/0x%04x",
+ funcName, internalFormat, unpackFormat,
+ unpackType);
return;
}
- if (!levelInfo.IsDataInitialized()) {
- bool coversWholeImage = xOffset == 0 &&
- yOffset == 0 &&
- uint32_t(width) == levelInfo.mWidth &&
- uint32_t(height) == levelInfo.mHeight;
- if (coversWholeImage) {
- levelInfo.SetIsDataInitialized(true, this);
- } else {
- if (!EnsureInitializedImageData(texImageTarget, level))
- return;
- }
- }
-
- mContext->MakeContextCurrent();
- gl::GLContext* gl = mContext->gl;
- gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xOffset, yOffset, width, height, internalFormat, byteLength, data);
-}
-
-void
-WebGLTexture::CopyTexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
- GLenum rawInternalFormat,
- GLint xOffset, GLint yOffset, GLint x,
- GLint y, GLsizei width, GLsizei height, GLint border,
- bool sub)
-{
- WebGLTexImageFunc func = sub
- ? WebGLTexImageFunc::CopyTexSubImage
- : WebGLTexImageFunc::CopyTexImage;
- WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
- const char* info = InfoFrom(func, dims);
-
- // TODO: This changes with color_buffer_float. Reassess when the
- // patch lands.
- if (!mContext->ValidateTexImage(texImageTarget, level, rawInternalFormat,
- xOffset, yOffset, 0,
- width, height, 0,
- border,
- LOCAL_GL_NONE, LOCAL_GL_NONE,
- func, dims))
- {
- return;
- }
-
- TexInternalFormat internalFormat = rawInternalFormat;
-
- if (!mContext->mBoundReadFramebuffer)
- mContext->ClearBackbufferIfNeeded();
-
- mContext->MakeContextCurrent();
- gl::GLContext* gl = mContext->gl;
-
- if (mImmutable) {
- if (!sub) {
- return mContext->ErrorInvalidOperation("copyTexImage2D: disallowed because the texture bound to this target has already been made immutable by texStorage2D");
- }
- }
-
- TexInternalFormat srcFormat;
- uint32_t srcWidth;
- uint32_t srcHeight;
- if (!mContext->ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
- return;
-
- if (!mContext->ValidateCopyTexImage(srcFormat, internalFormat, func, dims))
+ ////////////////////////////////////
+ // Get source info
+ const bool isFunc3D = Is3D(target);
+ if (!blob->ValidateUnpack(mContext, funcName, isFunc3D, srcPacking))
return;
- TexFormat intermediateFormat;
- TexType intermediateType;
- CopyTexImageIntermediateFormatAndType(srcFormat, &intermediateFormat,
- &intermediateType);
-
- TexInternalFormat destEffectiveFormat =
- EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalFormat, intermediateType);
-
- // this should never fail, validation happened earlier.
- MOZ_ASSERT(destEffectiveFormat != LOCAL_GL_NONE);
-
- const bool widthOrHeightIsZero = (width == 0 || height == 0);
- if (gl->WorkAroundDriverBugs() &&
- sub && widthOrHeightIsZero)
- {
- // NV driver on Linux complains that CopyTexSubImage2D(level=0,
- // xOffset=0, yOffset=2, x=0, y=0, width=0, height=0) from a 300x150 FB
- // to a 0x2 texture. This a useless thing to do, but technically legal.
- // NV331.38 generates INVALID_VALUE.
- return mContext->DummyFramebufferOperation(info);
- }
-
- // check if the memory size of this texture may change with this call
- bool sizeMayChange = !sub;
- const WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- if (!sub && imageInfo.IsDefined()) {
- const uint32_t depth = 1;
- sizeMayChange = uint32_t(width) != imageInfo.mWidth ||
- uint32_t(height) != imageInfo.mHeight ||
- depth != imageInfo.mDepth ||
- destEffectiveFormat != imageInfo.mFormat;
- }
-
- if (sizeMayChange)
- mContext->GetAndFlushUnderlyingGLErrors();
-
- if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, srcWidth, srcHeight)) {
- if (sub)
- gl->fCopyTexSubImage2D(texImageTarget.get(), level, xOffset, yOffset, x, y, width, height);
- else
- gl->fCopyTexImage2D(texImageTarget.get(), level, internalFormat.get(), x, y, width, height, 0);
- } else {
- // the rect doesn't fit in the framebuffer
-
- // first, we initialize the texture as black
- if (!sub) {
- mContext->GenerateWarning("%s: Source rect reaches outside the bounds of the"
- " source framebuffer. WebGL requires clearing this"
- " out-of-bounds data to zeros, which is slow.",
- info);
-
- // We use CopyTexImage to initialize to ensure we get the right internal
- // format in the driver.
- // We don't need to pass x and y, since we only need to width and height to be
- // right for the TexImage. In cases where x or y is 'tricky' (INT32_MIN), the
- // driver may have issues. (Seen on Win32 Try runs)
- gl->fCopyTexImage2D(texImageTarget.get(), level, internalFormat.get(), 0, 0,
- width, height, 0);
-
- // In GLES, read pixels outside the FB bounds are undefined, so we'll need to
- // clear them outselves.
- const uint32_t depth = 1;
- const bool isDataInitialized = false;
- const ImageInfo imageInfo(destEffectiveFormat, width, height, depth,
- isDataInitialized);
+ ////////////////////////////////////
+ // Check that source and dest info are compatible
+ auto dstFormat = dstUsage->format;
- SetImageInfoAt(texImageTarget, level, imageInfo);
-
- if (!EnsureInitializedImageData(texImageTarget, level))
- return;
- }
-
- // if we are completely outside of the framebuffer, we can exit now with our black texture
- if ( x >= int32_t(srcWidth)
- || x+width <= 0
- || y >= int32_t(srcHeight)
- || y+height <= 0)
+ if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
+ if (target != LOCAL_GL_TEXTURE_2D ||
+ blob->mHasData ||
+ level != 0)
{
- // we are completely outside of range, can exit now with buffer filled with zeros
- return mContext->DummyFramebufferOperation(info);
- }
-
- GLint trimmedXOffset = xOffset;
- GLint trimmedYOffset = yOffset;
- GLint trimmedX = x;
- GLint trimmedY = y;
- GLsizei trimmedWidth = width;
- GLsizei trimmedHeight = height;
-
- if (x < 0) {
- GLint diff = 0 - x;
- MOZ_ASSERT(diff > 0);
- trimmedX += diff;
- trimmedXOffset += diff;
- trimmedWidth -= diff;
- }
-
- if (y < 0) {
- GLint diff = 0 - y;
- MOZ_ASSERT(diff > 0);
- trimmedY += diff;
- trimmedYOffset += diff;
- trimmedHeight -= diff;
- }
-
- if (x + width > GLint(srcWidth)) {
- GLint diff = x + width - GLint(srcWidth);
- MOZ_ASSERT(diff > 0);
- trimmedWidth -= diff;
- }
-
- if (y + height > GLint(srcHeight)) {
- GLint diff = y + height - GLint(srcHeight);
- MOZ_ASSERT(diff > 0);
- trimmedHeight -= diff;
- }
-
- MOZ_ASSERT(trimmedX >= 0);
- MOZ_ASSERT(trimmedY >= 0);
- MOZ_ASSERT(trimmedWidth >= 0);
- MOZ_ASSERT(trimmedHeight >= 0);
-
- gl->fCopyTexSubImage2D(texImageTarget.get(), level, trimmedXOffset,
- trimmedYOffset, trimmedX, trimmedY, trimmedWidth,
- trimmedHeight);
- }
-
- if (sizeMayChange) {
- GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
- if (error) {
- mContext->GenerateWarning("copyTexImage2D generated error %s", mContext->ErrorName(error));
+ mContext->ErrorInvalidOperation("%s: With format %s, this function may only"
+ " be called with target=TEXTURE_2D,"
+ " data=null, and level=0.",
+ funcName, dstFormat->name);
return;
}
}
- if (!sub) {
- const uint32_t depth = 1;
- const bool isDataInitialized = true;
- const ImageInfo imageInfo(destEffectiveFormat, width, height, depth,
- isDataInitialized);
+ const webgl::DriverUnpackInfo* driverUnpackInfo;
+ if (!dstUsage->IsUnpackValid(srcPacking, &driverUnpackInfo)) {
+ mContext->ErrorInvalidOperation("%s: Mismatched internalFormat and format/type:"
+ " 0x%04x and 0x%04x/0x%04x",
+ funcName, internalFormat, unpackFormat,
+ unpackType);
+ return;
+ }
- SetImageInfoAt(texImageTarget, level, imageInfo);
- }
-}
+ ////////////////////////////////////
+ // Do the thing!
+
+ mContext->gl->MakeCurrent();
+
+ // It's tempting to do allocation first, and TexSubImage second, but this is generally
+ // slower.
+
+ const bool isSubImage = false;
+ const GLint xOffset = 0;
+ const GLint yOffset = 0;
+ const GLint zOffset = 0;
-void
-WebGLTexture::CopyTexImage2D(TexImageTarget texImageTarget,
- GLint level,
- GLenum internalFormat,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height,
- GLint border)
-{
- const char funcName[] = "copyTexImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
+ GLenum glError;
+ blob->TexOrSubImage(isSubImage, funcName, this, target, level, driverUnpackInfo,
+ xOffset, yOffset, zOffset, &glError);
+
+ if (glError == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
+ funcName);
return;
+ }
- CopyTexSubImage2D_base(texImageTarget, level, internalFormat, 0, 0, x, y, width,
- height, border, false);
+ if (glError) {
+ mContext->ErrorInvalidOperation("%s: Unexpected error during upload: 0x04x",
+ funcName, glError);
+ MOZ_ASSERT(false, "Unexpected GL error.");
+ return;
+ }
+
+ ////////////////////////////////////
+ // Update our specification data.
+
+ const ImageInfo newImageInfo(dstUsage, blob->mWidth, blob->mHeight, blob->mDepth,
+ blob->mHasData);
+ SetImageInfo(imageInfo, newImageInfo);
}
void
-WebGLTexture::CopyTexSubImage2D(TexImageTarget texImageTarget,
- GLint level,
- GLint xOffset,
- GLint yOffset,
- GLint x,
- GLint y,
- GLsizei width,
- GLsizei height)
+WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset,
+ GLenum unpackFormat, GLenum unpackType,
+ webgl::TexUnpackBlob* blob)
{
- switch (texImageTarget.get()) {
- case LOCAL_GL_TEXTURE_2D:
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
- case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
- case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
- break;
- default:
- return mContext->ErrorInvalidEnumInfo("copyTexSubImage2D: target", texImageTarget.get());
- }
-
- if (level < 0)
- return mContext->ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
-
- GLsizei maxTextureSize = mContext->MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget));
- if (!(maxTextureSize >> level))
- return mContext->ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
+ ////////////////////////////////////
+ // Get dest info
- if (width < 0 || height < 0)
- return mContext->ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
-
- if (xOffset < 0 || yOffset < 0)
- return mContext->ErrorInvalidValue("copyTexSubImage2D: xOffset and yOffset may not be negative");
-
- WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- if (!imageInfo.IsDefined())
- return mContext->ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
-
- GLsizei texWidth = imageInfo.mWidth;
- GLsizei texHeight = imageInfo.mHeight;
-
- if (xOffset + width > texWidth || xOffset + width < 0)
- return mContext->ErrorInvalidValue("copyTexSubImage2D: xOffset+width is too large");
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
+ blob->mWidth, blob->mHeight, blob->mDepth, &imageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(imageInfo);
- if (yOffset + height > texHeight || yOffset + height < 0)
- return mContext->ErrorInvalidValue("copyTexSubImage2D: yOffset+height is too large");
-
- if (!mContext->mBoundReadFramebuffer)
- mContext->ClearBackbufferIfNeeded();
+ auto dstUsage = imageInfo->mFormat;
+ auto dstFormat = dstUsage->format;
- if (!imageInfo.IsDataInitialized()) {
- bool coversWholeImage = xOffset == 0 &&
- yOffset == 0 &&
- width == texWidth &&
- height == texHeight;
- if (coversWholeImage) {
- imageInfo.SetIsDataInitialized(true, this);
- } else {
- if (!EnsureInitializedImageData(texImageTarget, level))
- return;
- }
+ if (dstFormat->compression) {
+ mContext->ErrorInvalidEnum("%s: Specified TexImage must not be compressed.",
+ funcName);
+ return;
}
- TexInternalFormat unsizedInternalFormat;
- TexType type;
- UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(imageInfo.mFormat,
- &unsizedInternalFormat,
- &type);
- const GLint border = 0;
- CopyTexSubImage2D_base(texImageTarget, level, unsizedInternalFormat.get(), xOffset,
- yOffset, x, y, width, height, border, true);
-}
-
-
-GLenum
-WebGLTexture::CheckedTexImage2D(TexImageTarget texImageTarget,
- GLint level,
- TexInternalFormat internalFormat,
- GLsizei width,
- GLsizei height,
- GLint border,
- TexFormat unpackFormat,
- TexType unpackType,
- const GLvoid* data)
-{
- TexInternalFormat effectiveInternalFormat =
- EffectiveInternalFormatFromInternalFormatAndType(internalFormat, unpackType);
- bool sizeMayChange = true;
-
- const WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- if (imageInfo.IsDefined()) {
- sizeMayChange = uint32_t(width) != imageInfo.mWidth ||
- uint32_t(height) != imageInfo.mHeight ||
- effectiveInternalFormat != imageInfo.mFormat;
+ if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
+ mContext->ErrorInvalidOperation("%s: Function may not be called on a texture of"
+ " format %s.",
+ funcName, dstFormat->name);
+ return;
}
- gl::GLContext* gl = mContext->gl;
+ ////////////////////////////////////
+ // Get source info
+
+ const webgl::PackingInfo srcPacking = { unpackFormat, unpackType };
+ if (!ValidateUnpackEnums(srcPacking, mContext, funcName))
+ return;
- // Convert to format and type required by OpenGL 'driver'.
- GLenum driverType = LOCAL_GL_NONE;
- GLenum driverInternalFormat = LOCAL_GL_NONE;
- GLenum driverFormat = LOCAL_GL_NONE;
- DriverFormatsFromEffectiveInternalFormat(gl,
- effectiveInternalFormat,
- &driverInternalFormat,
- &driverFormat,
- &driverType);
-
- if (sizeMayChange) {
- mContext->GetAndFlushUnderlyingGLErrors();
- }
-
- if (driverFormat == LOCAL_GL_ALPHA) {
- MOZ_ASSERT(true);
+ const webgl::DriverUnpackInfo* driverUnpackInfo;
+ if (!dstUsage->IsUnpackValid(srcPacking, &driverUnpackInfo)) {
+ mContext->ErrorInvalidOperation("%s: Mismatched internalFormat and format/type:"
+ " %s and 0x%04x/0x%04x",
+ funcName, dstFormat->name, unpackFormat,
+ unpackType);
+ return;
}
- gl->fTexImage2D(texImageTarget.get(), level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
-
- SetLegacyTextureSwizzle(gl, texImageTarget.get(), internalFormat.get());
+ const bool isFunc3D = Is3D(target);
+ if (!blob->ValidateUnpack(mContext, funcName, isFunc3D, srcPacking))
+ return;
- GLenum error = LOCAL_GL_NO_ERROR;
- if (sizeMayChange) {
- error = mContext->GetAndFlushUnderlyingGLErrors();
- }
-
- return error;
-}
+ ////////////////////////////////////
+ // Do the thing!
-void
-WebGLTexture::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
- GLint border,
- GLenum unpackFormat,
- GLenum unpackType,
- void* data, uint32_t byteLength,
- js::Scalar::Type jsArrayType,
- WebGLTexelFormat srcFormat, bool srcPremultiplied)
-{
- const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+ mContext->gl->MakeCurrent();
- if (unpackType == LOCAL_GL_HALF_FLOAT_OES) {
- unpackType = LOCAL_GL_HALF_FLOAT;
- }
-
- if (!mContext->ValidateTexImage(texImageTarget, level, internalFormat,
- 0, 0, 0,
- width, height, 0,
- border, unpackFormat, unpackType, func, dims))
+ bool uploadWillInitialize;
+ if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
+ yOffset, zOffset, blob->mWidth,
+ blob->mHeight, blob->mDepth, imageInfo,
+ &uploadWillInitialize))
{
return;
}
- const bool isDepthTexture = unpackFormat == LOCAL_GL_DEPTH_COMPONENT ||
- unpackFormat == LOCAL_GL_DEPTH_STENCIL;
-
- if (isDepthTexture && !mContext->IsWebGL2()) {
- if (data != nullptr || level != 0)
- return mContext->ErrorInvalidOperation("texImage2D: "
- "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
- "data must be nullptr, "
- "level must be zero");
- }
-
- if (!mContext->ValidateTexInputData(unpackType, jsArrayType, func, dims))
- return;
-
- TexInternalFormat effectiveInternalFormat =
- EffectiveInternalFormatFromInternalFormatAndType(internalFormat, unpackType);
+ const bool isSubImage = true;
- if (effectiveInternalFormat == LOCAL_GL_NONE) {
- return mContext->ErrorInvalidOperation("texImage2D: bad combination of internalFormat and type");
- }
+ GLenum glError;
+ blob->TexOrSubImage(isSubImage, funcName, this, target, level, driverUnpackInfo,
+ xOffset, yOffset, zOffset, &glError);
- size_t srcTexelSize = size_t(-1);
- if (srcFormat == WebGLTexelFormat::Auto) {
- // we need to find the exact sized format of the source data. Slightly abusing
- // EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
- // is the same thing as an unsized internalFormat.
- TexInternalFormat effectiveSourceFormat =
- EffectiveInternalFormatFromInternalFormatAndType(unpackFormat, unpackType);
- MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated format/type combo earlier
- const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
- MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
- srcTexelSize = srcbitsPerTexel / 8;
- } else {
- srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(srcFormat);
+ if (glError == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
+ funcName);
+ return;
}
- CheckedUint32 checked_neededByteLength =
- mContext->GetImageSize(height, width, 1, srcTexelSize, mContext->mPixelStoreUnpackAlignment);
-
- CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
- CheckedUint32 checked_alignedRowSize =
- RoundedToNextMultipleOf(checked_plainRowSize.value(), mContext->mPixelStoreUnpackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return mContext->ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
-
- uint32_t bytesNeeded = checked_neededByteLength.value();
-
- if (byteLength && byteLength < bytesNeeded)
- return mContext->ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
- bytesNeeded, byteLength);
-
- if (mImmutable) {
- return mContext->ErrorInvalidOperation(
- "texImage2D: disallowed because the texture "
- "bound to this target has already been made immutable by texStorage2D");
- }
- mContext->MakeContextCurrent();
-
- nsAutoArrayPtr<uint8_t> convertedData;
- void* pixels = nullptr;
- bool isDataInitialized = false;
-
- WebGLTexelFormat dstFormat = GetWebGLTexelFormat(effectiveInternalFormat);
- WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
-
- if (byteLength) {
- size_t bitsPerTexel = GetBitsPerTexel(effectiveInternalFormat);
- MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
- size_t dstTexelSize = bitsPerTexel / 8;
- size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
- size_t dstPlainRowSize = dstTexelSize * width;
- size_t unpackAlignment = mContext->mPixelStoreUnpackAlignment;
- size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
-
- if (actualSrcFormat == dstFormat &&
- srcPremultiplied == mContext->mPixelStorePremultiplyAlpha &&
- srcStride == dstStride &&
- !mContext->mPixelStoreFlipY)
- {
- // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
- pixels = data;
- } else {
- size_t convertedDataSize = height * dstStride;
- convertedData = new (fallible) uint8_t[convertedDataSize];
- if (!convertedData) {
- mContext->ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
- " a buffer for doing format conversion.");
- return;
- }
- if (!mContext->ConvertImage(width, height, srcStride, dstStride,
- static_cast<uint8_t*>(data), convertedData,
- actualSrcFormat, srcPremultiplied,
- dstFormat, mContext->mPixelStorePremultiplyAlpha, dstTexelSize))
- {
- return mContext->ErrorInvalidOperation("texImage2D: Unsupported texture format conversion");
- }
- pixels = reinterpret_cast<void*>(convertedData.get());
- }
- isDataInitialized = true;
- }
-
- GLenum error = CheckedTexImage2D(texImageTarget, level, internalFormat, width,
- height, border, unpackFormat, unpackType, pixels);
-
- if (error) {
- mContext->GenerateWarning("texImage2D generated error %s", mContext->ErrorName(error));
+ if (glError) {
+ mContext->ErrorInvalidOperation("%s: Unexpected error during upload: 0x04x",
+ funcName, glError);
+ MOZ_ASSERT(false, "Unexpected GL error.");
return;
}
- const uint32_t depth = 1;
- const ImageInfo imageInfo(effectiveInternalFormat, width, height, depth,
- isDataInitialized);
- SetImageInfoAt(texImageTarget, level, imageInfo);
+ ////////////////////////////////////
+ // Update our specification data?
+
+ if (uploadWillInitialize) {
+ imageInfo->SetIsDataInitialized(true, this);
+ }
}
-void
-WebGLTexture::TexImage2D(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLsizei width,
- GLsizei height, GLint border, GLenum unpackFormat,
- GLenum unpackType, const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv)
-{
- void* data;
- size_t length;
- js::Scalar::Type jsArrayType;
- if (maybeView.IsNull()) {
- data = nullptr;
- length = 0;
- jsArrayType = js::Scalar::MaxTypedArrayViewType;
- } else {
- const auto& view = maybeView.Value();
- ComputeLengthAndData(view, &data, &length, &jsArrayType);
- }
-
- const char funcName[] = "texImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
-
- return TexImage2D_base(texImageTarget, level, internalFormat, width, height, 0, border, unpackFormat, unpackType,
- data, length, jsArrayType,
- WebGLTexelFormat::Auto, false);
-}
+////////////////////////////////////////
+// CompressedTex(Sub)Image
void
-WebGLTexture::TexImage2D(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLenum unpackFormat,
- GLenum unpackType, dom::ImageData* imageData, ErrorResult* const out_rv)
+WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GLint level,
+ GLenum internalFormat, GLsizei width, GLsizei height,
+ GLsizei depth, GLint border,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
- if (!imageData) {
- // Spec says to generate an INVALID_VALUE error
- return mContext->ErrorInvalidValue("texImage2D: null ImageData");
- }
-
- dom::Uint8ClampedArray arr;
- DebugOnly<bool> inited = arr.Init(imageData->GetDataObject());
- MOZ_ASSERT(inited);
- arr.ComputeLengthAndData();
-
- void* pixelData = arr.Data();
- const uint32_t pixelDataLength = arr.Length();
-
- const char funcName[] = "texImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
+ ////////////////////////////////////
+ // Get dest info
- return TexImage2D_base(texImageTarget, level, internalFormat, imageData->Width(),
- imageData->Height(), 4*imageData->Width(), 0,
- unpackFormat, unpackType, pixelData, pixelDataLength, js::Scalar::MaxTypedArrayViewType,
- WebGLTexelFormat::RGBA8, false);
-}
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSpecification(funcName, target, level, width, height, depth,
+ border, &imageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(imageInfo);
-void
-WebGLTexture::TexImage2D(TexImageTarget texImageTarget, GLint level,
- GLenum internalFormat, GLenum unpackFormat, GLenum unpackType,
- dom::Element* elem, ErrorResult* out_rv)
-{
- const char funcName[] = "texImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
-
- if (level < 0)
- return mContext->ErrorInvalidValue("texImage2D: level is negative");
-
- const int32_t maxLevel = mContext->MaxTextureLevelForTexImageTarget(texImageTarget);
- if (level > maxLevel) {
- mContext->ErrorInvalidValue("texImage2D: level %d is too large, max is %d",
- level, maxLevel);
+ auto usage = mContext->mFormatUsage->GetSizedTexUsage(internalFormat);
+ if (!usage) {
+ mContext->ErrorInvalidEnum("%s: Invalid internalFormat: 0x%04x", funcName,
+ internalFormat);
return;
}
- // Trying to handle the video by GPU directly first
- if (TexImageFromVideoElement(texImageTarget, level, internalFormat,
- unpackFormat, unpackType, elem))
+ auto format = usage->format;
+ if (!format->compression) {
+ mContext->ErrorInvalidEnum("%s: Specified internalFormat must be compressed.",
+ funcName);
+ return;
+ }
+
+ ////////////////////////////////////
+ // Get source info
+
+ void* mutData;
+ size_t dataSize;
+ js::Scalar::Type jsType;
+ ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
+ const void* data = mutData;
+
+ if (!ValidateCompressedTexUnpack(mContext, funcName, width, height, depth, format,
+ dataSize))
{
return;
}
- RefPtr<gfx::DataSourceSurface> data;
- WebGLTexelFormat srcFormat;
- nsLayoutUtils::SurfaceFromElementResult res = mContext->SurfaceFromElement(elem);
- *out_rv = mContext->SurfaceFromElementResultToImageSurface(res, data, &srcFormat);
- if (out_rv->Failed() || !data)
- return;
-
- gfx::IntSize size = data->GetSize();
- uint32_t byteLength = data->Stride() * size.height;
- return TexImage2D_base(texImageTarget, level, internalFormat,
- size.width, size.height, data->Stride(), 0,
- unpackFormat, unpackType, data->GetData(), byteLength,
- js::Scalar::MaxTypedArrayViewType, srcFormat,
- res.mIsPremultiplied);
-}
-
+ ////////////////////////////////////
+ // Check that source is compatible with dest
-void
-WebGLTexture::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset,
- GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
- GLenum unpackFormat, GLenum unpackType,
- void* data, uint32_t byteLength,
- js::Scalar::Type jsArrayType,
- WebGLTexelFormat srcFormat, bool srcPremultiplied)
-{
- const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
-
- if (unpackType == LOCAL_GL_HALF_FLOAT_OES)
- unpackType = LOCAL_GL_HALF_FLOAT;
-
- const char funcName[] = "texSubImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
-
- WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- if (!imageInfo.IsDefined())
- return mContext->ErrorInvalidOperation("texSubImage2D: no previously defined texture image");
-
- const TexInternalFormat existingEffectiveInternalFormat = imageInfo.mFormat;
-
- if (!mContext->ValidateTexImage(texImageTarget, level,
- existingEffectiveInternalFormat.get(),
- xOffset, yOffset, 0,
- width, height, 0,
- 0, unpackFormat, unpackType, func, dims))
+ if (!ValidateCompressedTexImageRestrictions(funcName, mContext, target, level, format,
+ width, height, depth))
{
return;
}
- if (!mContext->ValidateTexInputData(unpackType, jsArrayType, func, dims))
- return;
+ ////////////////////////////////////
+ // Do the thing!
- if (unpackType != TypeFromInternalFormat(existingEffectiveInternalFormat)) {
- return mContext->ErrorInvalidOperation("texSubImage2D: type differs from that of the existing image");
- }
+ mContext->gl->MakeCurrent();
- size_t srcTexelSize = size_t(-1);
- if (srcFormat == WebGLTexelFormat::Auto) {
- const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
- MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
- srcTexelSize = bitsPerTexel / 8;
- } else {
- srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(srcFormat);
+ GLenum error = DoCompressedTexImage(mContext->gl, target, level, internalFormat,
+ width, height, depth, border, dataSize, data);
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
+ return;
+ }
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
+ mContext->GenerateWarning("%s: Unexpected error during texture upload. Context"
+ " lost.",
+ funcName);
+ mContext->ForceLoseContext();
+ return;
}
- if (width == 0 || height == 0)
- return; // ES 2.0 says it has no effect, we better return right now
-
- CheckedUint32 checked_neededByteLength =
- mContext->GetImageSize(height, width, 1, srcTexelSize, mContext->mPixelStoreUnpackAlignment);
-
- CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
-
- CheckedUint32 checked_alignedRowSize =
- RoundedToNextMultipleOf(checked_plainRowSize.value(), mContext->mPixelStoreUnpackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return mContext->ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
-
- uint32_t bytesNeeded = checked_neededByteLength.value();
-
- if (byteLength < bytesNeeded)
- return mContext->ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
-
- if (!imageInfo.IsDataInitialized()) {
- bool coversWholeImage = xOffset == 0 &&
- yOffset == 0 &&
- uint32_t(width) == imageInfo.mWidth &&
- uint32_t(height) == imageInfo.mHeight;
- if (coversWholeImage) {
- imageInfo.SetIsDataInitialized(true, this);
- } else {
- if (!EnsureInitializedImageData(texImageTarget, level))
- return;
- }
- }
- mContext->MakeContextCurrent();
- gl::GLContext* gl = mContext->gl;
-
- size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
- uint32_t dstTexelSize = GetBitsPerTexel(existingEffectiveInternalFormat) / 8;
- size_t dstPlainRowSize = dstTexelSize * width;
- // There are checks above to ensure that this won't overflow.
- size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mContext->mPixelStoreUnpackAlignment).value();
+ ////////////////////////////////////
+ // Update our specification data.
- void* pixels = data;
- nsAutoArrayPtr<uint8_t> convertedData;
-
- WebGLTexelFormat dstFormat = GetWebGLTexelFormat(existingEffectiveInternalFormat);
- WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
-
- // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
- bool noConversion = (actualSrcFormat == dstFormat &&
- srcPremultiplied == mContext->mPixelStorePremultiplyAlpha &&
- srcStride == dstStride &&
- !mContext->mPixelStoreFlipY);
-
- if (!noConversion) {
- size_t convertedDataSize = height * dstStride;
- convertedData = new (fallible) uint8_t[convertedDataSize];
- if (!convertedData) {
- mContext->ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
- " a buffer for doing format conversion.");
- return;
- }
- if (!mContext->ConvertImage(width, height, srcStride, dstStride,
- static_cast<const uint8_t*>(data), convertedData,
- actualSrcFormat, srcPremultiplied,
- dstFormat, mContext->mPixelStorePremultiplyAlpha, dstTexelSize))
- {
- return mContext->ErrorInvalidOperation("texSubImage2D: Unsupported texture format conversion");
- }
- pixels = reinterpret_cast<void*>(convertedData.get());
- }
-
- GLenum driverType = LOCAL_GL_NONE;
- GLenum driverInternalFormat = LOCAL_GL_NONE;
- GLenum driverFormat = LOCAL_GL_NONE;
- DriverFormatsFromEffectiveInternalFormat(gl,
- existingEffectiveInternalFormat,
- &driverInternalFormat,
- &driverFormat,
- &driverType);
-
- gl->fTexSubImage2D(texImageTarget.get(), level, xOffset, yOffset, width, height, driverFormat, driverType, pixels);
+ const bool isDataInitialized = true;
+ const ImageInfo newImageInfo(usage, width, height, depth, isDataInitialized);
+ SetImageInfo(imageInfo, newImageInfo);
}
-void
-WebGLTexture::TexSubImage2D(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset,
- GLsizei width, GLsizei height,
- GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv)
-{
- if (maybeView.IsNull())
- return mContext->ErrorInvalidValue("texSubImage2D: pixels must not be null!");
-
- const auto& view = maybeView.Value();
- size_t length;
- void* data;
- js::Scalar::Type jsArrayType;
- ComputeLengthAndData(view, &data, &length, &jsArrayType);
-
- const char funcName[] = "texSubImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
-
- return TexSubImage2D_base(texImageTarget, level, xOffset, yOffset,
- width, height, 0, unpackFormat, unpackType,
- data, length, jsArrayType,
- WebGLTexelFormat::Auto, false);
-}
-
-void
-WebGLTexture::TexSubImage2D(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset,
- GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
- ErrorResult* const out_rv)
+static inline bool
+IsSubImageBlockAligned(const webgl::CompressedFormatInfo* compression,
+ const WebGLTexture::ImageInfo* imageInfo, GLint xOffset,
+ GLint yOffset, GLsizei width, GLsizei height)
{
- if (!imageData)
- return mContext->ErrorInvalidValue("texSubImage2D: pixels must not be null!");
-
- dom::Uint8ClampedArray arr;
- DebugOnly<bool> inited = arr.Init(imageData->GetDataObject());
- MOZ_ASSERT(inited);
- arr.ComputeLengthAndData();
-
- return TexSubImage2D_base(texImageTarget, level, xOffset, yOffset,
- imageData->Width(), imageData->Height(),
- 4*imageData->Width(), unpackFormat, unpackType,
- arr.Data(), arr.Length(),
- js::Scalar::MaxTypedArrayViewType,
- WebGLTexelFormat::RGBA8, false);
-}
-
-
-
-bool
-WebGLTexture::TexImageFromVideoElement(TexImageTarget texImageTarget,
- GLint level, GLenum internalFormat,
- GLenum unpackFormat, GLenum unpackType,
- mozilla::dom::Element* elem)
-{
- if (unpackType == LOCAL_GL_HALF_FLOAT_OES &&
- !mContext->gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float))
- {
- unpackType = LOCAL_GL_HALF_FLOAT;
- }
-
- if (!mContext->ValidateTexImageFormatAndType(unpackFormat, unpackType,
- WebGLTexImageFunc::TexImage,
- WebGLTexDimensions::Tex2D))
+ if (xOffset % compression->blockWidth != 0 ||
+ yOffset % compression->blockHeight != 0)
{
return false;
}
- dom::HTMLVideoElement* video = dom::HTMLVideoElement::FromContentOrNull(elem);
- if (!video)
- return false;
-
- uint16_t readyState;
- if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
- readyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)
- {
- //No frame inside, just return
- return false;
- }
-
- // If it doesn't have a principal, just bail
- nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
- if (!principal)
- return false;
-
- mozilla::layers::ImageContainer* container = video->GetImageContainer();
- if (!container)
+ if (width % compression->blockWidth != 0 && xOffset + width != imageInfo->mWidth)
return false;
- if (video->GetCORSMode() == CORS_NONE) {
- bool subsumes;
- nsresult rv = mContext->mCanvasElement->NodePrincipal()->Subsumes(principal, &subsumes);
- if (NS_FAILED(rv) || !subsumes) {
- mContext->GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
- "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
- return false;
- }
- }
-
- layers::AutoLockImage lockedImage(container);
- layers::Image* srcImage = lockedImage.GetImage();
- if (!srcImage) {
- return false;
- }
-
- const uint32_t width = srcImage->GetSize().width;
- const uint32_t height = srcImage->GetSize().height;
-
- gl::GLContext* gl = mContext->gl;
- gl->MakeCurrent();
-
- MOZ_ASSERT(level == 0);
- const WebGLTexture::ImageInfo& info = ImageInfoAt(texImageTarget, 0);
- bool dimensionsMatch = (info.mWidth == width &&
- info.mHeight == height &&
- info.mDepth == 1);
- if (!dimensionsMatch) {
- // we need to allocation
- gl->fTexImage2D(texImageTarget.get(), level, internalFormat,
- width, height,
- 0, unpackFormat, unpackType, nullptr);
- }
-
- const gl::OriginPos destOrigin = mContext->mPixelStoreFlipY ? gl::OriginPos::BottomLeft
- : gl::OriginPos::TopLeft;
- bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage,
- srcImage->GetSize(),
- mGLName,
- texImageTarget.get(),
- destOrigin);
- if (!ok)
+ if (height % compression->blockHeight != 0 && yOffset + height != imageInfo->mHeight)
return false;
- TexInternalFormat effectiveInternalFormat =
- EffectiveInternalFormatFromInternalFormatAndType(internalFormat,
- unpackType);
- MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE);
-
- const uint32_t depth = 1;
- const bool isDataInitialized = true;
- const ImageInfo imageInfo(effectiveInternalFormat, width, height, depth,
- isDataInitialized);
- SetImageInfoAt(texImageTarget, level, imageInfo);
-
return true;
}
void
-WebGLTexture::TexSubImage2D(TexImageTarget texImageTarget, GLint level, GLint xOffset,
- GLint yOffset, GLenum unpackFormat, GLenum unpackType,
- dom::Element* elem, ErrorResult* const out_rv)
+WebGLTexture::CompressedTexSubImage(const char* funcName, TexImageTarget target,
+ GLint level, GLint xOffset, GLint yOffset,
+ GLint zOffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum sizedUnpackFormat,
+ const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
- const char funcName[] = "texSubImage2D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 2, funcName))
- return;
+ ////////////////////////////////////
+ // Get dest info
- if (level < 0)
- return mContext->ErrorInvalidValue("texSubImage2D: level is negative");
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
+ width, height, depth, &imageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(imageInfo);
+
+ auto dstUsage = imageInfo->mFormat;
+ auto dstFormat = dstUsage->format;
- const int32_t maxLevel = mContext->MaxTextureLevelForTexImageTarget(texImageTarget);
- if (level > maxLevel) {
- mContext->ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d",
- level, maxLevel);
+ ////////////////////////////////////
+ // Get source info
+
+ void* mutData;
+ size_t dataSize;
+ js::Scalar::Type jsType;
+ ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
+ const void* data = mutData;
+
+ auto srcUsage = mContext->mFormatUsage->GetSizedTexUsage(sizedUnpackFormat);
+ if (!srcUsage->format->compression) {
+ mContext->ErrorInvalidEnum("%s: Specified format must be compressed.", funcName);
return;
}
- const WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- const TexInternalFormat internalFormat = imageInfo.mFormat;
+ if (srcUsage != dstUsage) {
+ mContext->ErrorInvalidOperation("%s: `format` must match the format of the"
+ " existing texture image.",
+ funcName);
+ return;
+ }
- // Trying to handle the video by GPU directly first
- if (TexImageFromVideoElement(texImageTarget, level, internalFormat.get(), unpackFormat, unpackType, elem))
+ auto format = srcUsage->format;
+ MOZ_ASSERT(format == dstFormat);
+ if (!ValidateCompressedTexUnpack(mContext, funcName, width, height, depth, format,
+ dataSize))
{
return;
}
- RefPtr<gfx::DataSourceSurface> data;
- WebGLTexelFormat srcFormat;
- nsLayoutUtils::SurfaceFromElementResult res = mContext->SurfaceFromElement(elem);
- *out_rv = mContext->SurfaceFromElementResultToImageSurface(res, data, &srcFormat);
- if (out_rv->Failed() || !data)
+ ////////////////////////////////////
+ // Check that source is compatible with dest
+
+ switch (format->compression->family) {
+ // Forbidden:
+ case webgl::CompressionFamily::ETC1:
+ case webgl::CompressionFamily::ATC:
+ mContext->ErrorInvalidOperation("%s: Format does not allow sub-image"
+ " updates.", funcName);
return;
- gfx::IntSize size = data->GetSize();
- uint32_t byteLength = data->Stride() * size.height;
- TexSubImage2D_base(texImageTarget, level, xOffset, yOffset, size.width,
- size.height, data->Stride(), unpackFormat, unpackType, data->GetData(),
- byteLength, js::Scalar::MaxTypedArrayViewType, srcFormat,
- res.mIsPremultiplied);
+ // Block-aligned:
+ case webgl::CompressionFamily::ES3: // Yes, the ES3 formats don't match the ES3
+ case webgl::CompressionFamily::S3TC: // default behavior.
+ if (!IsSubImageBlockAligned(dstFormat->compression, imageInfo, xOffset, yOffset,
+ width, height))
+ {
+ mContext->ErrorInvalidOperation("%s: Format requires block-aligned sub-image"
+ " updates.",
+ funcName);
+ return;
+ }
+ break;
+
+ // Full-only: (The ES3 default)
+ default: // PVRTC
+ if (xOffset || yOffset ||
+ width != imageInfo->mWidth ||
+ height != imageInfo->mHeight)
+ {
+ mContext->ErrorInvalidOperation("%s: Format does not allow partial sub-image"
+ " updates.",
+ funcName);
+ return;
+ }
+ break;
+ }
+
+ ////////////////////////////////////
+ // Do the thing!
+
+ mContext->gl->MakeCurrent();
+
+ bool uploadWillInitialize;
+ if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
+ yOffset, zOffset, width, height, depth,
+ imageInfo, &uploadWillInitialize))
+ {
+ return;
+ }
+
+ GLenum error = DoCompressedTexSubImage(mContext->gl, target, level, xOffset, yOffset,
+ zOffset, width, height, depth,
+ sizedUnpackFormat, dataSize, data);
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName);
+ return;
+ }
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
+ mContext->GenerateWarning("%s: Unexpected error during texture upload. Context"
+ " lost.",
+ funcName);
+ mContext->ForceLoseContext();
+ return;
+ }
+
+ ////////////////////////////////////
+ // Update our specification data?
+
+ if (uploadWillInitialize) {
+ imageInfo->SetIsDataInitialized(true, this);
+ }
}
-bool
-WebGLTexture::ValidateSizedInternalFormat(GLenum internalFormat, const char* info)
+////////////////////////////////////////
+// CopyTex(Sub)Image
+
+static bool
+ValidateCopyTexImageFormats(WebGLContext* webgl, const char* funcName,
+ const webgl::FormatInfo* srcFormat,
+ const webgl::FormatInfo* dstFormat)
{
- switch (internalFormat) {
- // Sized Internal Formats
- // https://www.khronos.org/opengles/sdk/docs/man3/html/glTexStorage2D.xhtml
- case LOCAL_GL_R8:
- case LOCAL_GL_R8_SNORM:
- case LOCAL_GL_R16F:
- case LOCAL_GL_R32F:
- case LOCAL_GL_R8UI:
- case LOCAL_GL_R8I:
- case LOCAL_GL_R16UI:
- case LOCAL_GL_R16I:
- case LOCAL_GL_R32UI:
- case LOCAL_GL_R32I:
- case LOCAL_GL_RG8:
- case LOCAL_GL_RG8_SNORM:
- case LOCAL_GL_RG16F:
- case LOCAL_GL_RG32F:
- case LOCAL_GL_RG8UI:
- case LOCAL_GL_RG8I:
- case LOCAL_GL_RG16UI:
- case LOCAL_GL_RG16I:
- case LOCAL_GL_RG32UI:
- case LOCAL_GL_RG32I:
- case LOCAL_GL_RGB8:
- case LOCAL_GL_SRGB8:
- case LOCAL_GL_RGB565:
- case LOCAL_GL_RGB8_SNORM:
- case LOCAL_GL_R11F_G11F_B10F:
- case LOCAL_GL_RGB9_E5:
- case LOCAL_GL_RGB16F:
- case LOCAL_GL_RGB32F:
- case LOCAL_GL_RGB8UI:
- case LOCAL_GL_RGB8I:
- case LOCAL_GL_RGB16UI:
- case LOCAL_GL_RGB16I:
- case LOCAL_GL_RGB32UI:
- case LOCAL_GL_RGB32I:
- case LOCAL_GL_RGBA8:
- case LOCAL_GL_SRGB8_ALPHA8:
- case LOCAL_GL_RGBA8_SNORM:
- case LOCAL_GL_RGB5_A1:
- case LOCAL_GL_RGBA4:
- case LOCAL_GL_RGB10_A2:
- case LOCAL_GL_RGBA16F:
- case LOCAL_GL_RGBA32F:
- case LOCAL_GL_RGBA8UI:
- case LOCAL_GL_RGBA8I:
- case LOCAL_GL_RGB10_A2UI:
- case LOCAL_GL_RGBA16UI:
- case LOCAL_GL_RGBA16I:
- case LOCAL_GL_RGBA32I:
- case LOCAL_GL_RGBA32UI:
- case LOCAL_GL_DEPTH_COMPONENT16:
- case LOCAL_GL_DEPTH_COMPONENT24:
- case LOCAL_GL_DEPTH_COMPONENT32F:
- case LOCAL_GL_DEPTH24_STENCIL8:
- case LOCAL_GL_DEPTH32F_STENCIL8:
- return true;
- }
-
- if (IsCompressedTextureFormat(internalFormat))
- return true;
-
- nsCString name;
- mContext->EnumName(internalFormat, &name);
- mContext->ErrorInvalidEnum("%s: invalid internal format %s", info, name.get());
-
- return false;
-}
-
-bool
-WebGLTexture::ValidateTexStorage(TexTarget texTarget, GLsizei levels,
- GLenum internalFormat, GLsizei width, GLsizei height,
- GLsizei depth, const char* funcName)
-{
- // INVALID_OPERATION is generated if the texture object currently bound to target
- // already has TEXTURE_IMMUTABLE_FORMAT set to TRUE.
- // While there isn't an explicit reference to this, it seems to fall out of GLES
- // 3.0.4:
- // p138: "Using [TexImage*] with the same texture will result in an
- // INVALID_OPERATION error being generated, even if it does not affect the"
- // dimensions or unpackFormat[.]"
- // p136: "* If executing the pseudo-code would result in any other error, the error is
- // generated and the command will have no effect."
- // p137-138: The pseudo-code uses TexImage*.
- //
- if (mImmutable) {
- mContext->ErrorInvalidOperation("%s: Texture is already immutable.", funcName);
+ MOZ_ASSERT(!srcFormat->compression);
+ if (dstFormat->compression) {
+ webgl->ErrorInvalidEnum("%s: Specified destination must not have a compressed"
+ " format.",
+ funcName);
return false;
}
- // INVALID_ENUM is generated if internalformat is not a valid sized internal unpackFormat.
- if (!ValidateSizedInternalFormat(internalFormat, funcName))
- return false;
-
- // INVALID_VALUE is generated if width, height or levels are less than 1.
- if (width < 1 || height < 1 || depth < 1 || levels < 1) {
- mContext->ErrorInvalidValue("%s: Width, height, depth, and levels must be >= 1.",
- funcName);
+ if (dstFormat->effectiveFormat == webgl::EffectiveFormat::RGB9_E5) {
+ webgl->ErrorInvalidOperation("%s: RGB9_E5 is an invalid destination for"
+ " CopyTex(Sub)Image. (GLES 3.0.4 p145)",
+ funcName);
return false;
}
- // INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
- GLsizei largest = std::max(std::max(width, height), depth);
- GLsizei maxLevels = FloorLog2(largest) + 1;
- if (levels > maxLevels) {
- mContext->ErrorInvalidOperation("%s: Too many levels for given texture dimensions.",
- funcName);
+ if (!DoChannelsMatchForCopyTexImage(srcFormat, dstFormat)) {
+ webgl->ErrorInvalidOperation("%s: Destination channels must be compatible with"
+ " source channels. (GLES 3.0.4 p140 Table 3.16)",
+ funcName);
return false;
}
return true;
}
+// There is no CopyTexImage3D.
void
-WebGLTexture::TexStorage2D(TexTarget texTarget, GLsizei levels, GLenum rawInternalFormat,
- GLsizei width, GLsizei height)
+WebGLTexture::CopyTexImage2D(TexImageTarget target, GLint level, GLenum internalFormat,
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLint border)
{
- if (texTarget != LOCAL_GL_TEXTURE_2D && texTarget != LOCAL_GL_TEXTURE_CUBE_MAP) {
- mContext->ErrorInvalidEnum("texStorage2D: target must be TEXTURE_2D or"
- " TEXTURE_CUBE_MAP.");
+ const char funcName[] = "CopyTexImage2D";
+
+ const uint8_t depth = 1;
+
+ ////////////////////////////////////
+ // Get dest info
+
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSpecification(funcName, target, level, width, height, depth,
+ border, &imageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(imageInfo);
+
+ ////////////////////////////////////
+ // Get source info
+
+ const webgl::FormatUsageInfo* srcUsage;
+ uint32_t srcWidth;
+ uint32_t srcHeight;
+ if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
+ return;
+ auto srcFormat = srcUsage->format;
+
+ ////////////////////////////////////
+ // Check that source and dest info are compatible
+
+ const auto& fua = mContext->mFormatUsage;
+
+ auto dstUsage = fua->GetSizedTexUsage(internalFormat);
+ if (!dstUsage) {
+ // It must be an unsized format then...
+ webgl::PackingInfo pi = {internalFormat, 0};
+
+ switch (srcFormat->componentType) {
+ case webgl::ComponentType::NormUInt:
+ pi.type = LOCAL_GL_UNSIGNED_BYTE;
+ break;
+
+ case webgl::ComponentType::Float:
+ pi.type = LOCAL_GL_FLOAT;
+ break;
+ }
+
+ dstUsage = fua->GetUnsizedTexUsage(pi);
+ }
+
+ if (!dstUsage) {
+ mContext->ErrorInvalidEnum("%s: Invalid internalFormat 0x%04x for FB format %s.",
+ funcName, internalFormat, srcFormat->name);
+ return;
+ }
+ auto dstFormat = dstUsage->format;
+
+ if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
+ mContext->ErrorInvalidOperation("%s: Function may not be called with format %s.",
+ funcName, dstFormat->name);
return;
}
- const GLsizei depth = 1;
- if (!ValidateTexStorage(texTarget, levels, rawInternalFormat, width, height, depth,
- "texStorage2D"))
- {
+ if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
return;
- }
- TexInternalFormat internalFormat(rawInternalFormat);
+ ////////////////////////////////////
+ // Do the thing!
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
- mContext->GetAndFlushUnderlyingGLErrors();
- gl->fTexStorage2D(texTarget.get(), levels, internalFormat.get(), width, height);
- GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
- if (error) {
- mContext->GenerateWarning("texStorage2D generated error %s",
- mContext->ErrorName(error));
- return;
+ uint32_t readX, readY;
+ uint32_t writeX, writeY;
+ uint32_t rwWidth, rwHeight;
+ Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+ Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
+
+ GLenum error;
+ if (rwWidth == width && rwHeight == height) {
+ error = DoCopyTexImage2D(gl, target, level, internalFormat, x, y, width, height,
+ border);
+ } else {
+ // 1. Zero the texture data.
+ // 2. CopyTexSubImage the subrect.
+
+ const bool respecifyTexture = true;
+ const uint8_t zOffset = 0;
+ if (!ZeroTextureData(mContext, funcName, respecifyTexture, target, level,
+ dstUsage, 0, 0, zOffset, width, height, depth))
+ {
+ mContext->ErrorOutOfMemory("%s: Failed to zero texture data.", funcName);
+ MOZ_ASSERT(false, "Failed to zero texture data.");
+ return;
+ }
+
+ if (!rwWidth || !rwHeight) {
+ // There aren't any, so we're 'done'.
+ mContext->DummyFramebufferOperation(funcName);
+ return;
+ }
+
+ error = DoCopyTexSubImage(gl, target, level, writeX, writeY, zOffset, readX,
+ readY, rwWidth, rwHeight);
}
- SpecifyTexStorage(levels, internalFormat, width, height, depth);
-}
-
-void
-WebGLTexture::TexStorage3D(TexTarget texTarget, GLsizei levels, GLenum rawInternalFormat,
- GLsizei width, GLsizei height, GLsizei depth)
-{
- if (texTarget != LOCAL_GL_TEXTURE_3D)
- return mContext->ErrorInvalidEnum("texStorage3D: target must be TEXTURE_3D.");
-
- if (!ValidateTexStorage(texTarget, levels, rawInternalFormat, width, height, depth,
- "texStorage3D"))
- {
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
+ funcName);
+ return;
+ }
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
+ mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
+ " lost.",
+ funcName);
+ mContext->ForceLoseContext();
return;
}
- TexInternalFormat internalFormat(rawInternalFormat);
-
- gl::GLContext* gl = mContext->gl;
- gl->MakeCurrent();
+ ////////////////////////////////////
+ // Update our specification data.
- mContext->GetAndFlushUnderlyingGLErrors();
- gl->fTexStorage3D(texTarget.get(), levels, internalFormat.get(), width, height, depth);
- GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
- if (error) {
- mContext->GenerateWarning("texStorage3D generated error %s",
- mContext->ErrorName(error));
- return;
- }
-
- SpecifyTexStorage(levels, internalFormat, width, height, depth);
+ const bool isDataInitialized = true;
+ const ImageInfo newImageInfo(dstUsage, width, height, depth, isDataInitialized);
+ SetImageInfo(imageInfo, newImageInfo);
}
void
-WebGLTexture::TexImage3D(TexImageTarget texImageTarget, GLint level, GLenum internalFormat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv)
+WebGLTexture::CopyTexSubImage(const char* funcName, TexImageTarget target, GLint level,
+ GLint xOffset, GLint yOffset, GLint zOffset, GLint x,
+ GLint y, GLsizei width, GLsizei height)
{
- void* data;
- size_t dataLength;
- js::Scalar::Type jsArrayType;
- if (maybeView.IsNull()) {
- data = nullptr;
- dataLength = 0;
- jsArrayType = js::Scalar::MaxTypedArrayViewType;
- } else {
- const auto& view = maybeView.Value();
- ComputeLengthAndData(view, &data, &dataLength, &jsArrayType);
+ const GLsizei depth = 1;
+
+ ////////////////////////////////////
+ // Get dest info
+
+ WebGLTexture::ImageInfo* imageInfo;
+ if (!ValidateTexImageSelection(funcName, target, level, xOffset, yOffset, zOffset,
+ width, height, depth, &imageInfo))
+ {
+ return;
+ }
+ MOZ_ASSERT(imageInfo);
+
+ auto dstUsage = imageInfo->mFormat;
+ MOZ_ASSERT(dstUsage);
+ auto dstFormat = dstUsage->format;
+
+ if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
+ mContext->ErrorInvalidOperation("%s: Function may not be called on a texture of"
+ " format %s.",
+ funcName, dstFormat->name);
+ return;
}
- const char funcName[] = "texImage3D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 3, funcName))
+ ////////////////////////////////////
+ // Get source info
+
+ const webgl::FormatUsageInfo* srcUsage;
+ uint32_t srcWidth;
+ uint32_t srcHeight;
+ if (!mContext->ValidateCurFBForRead(funcName, &srcUsage, &srcWidth, &srcHeight))
+ return;
+ auto srcFormat = srcUsage->format;
+
+ ////////////////////////////////////
+ // Check that source and dest info are compatible
+
+ if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
return;
- const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
+ ////////////////////////////////////
+ // Do the thing!
+
+ mContext->gl->MakeCurrent();
+
+ uint32_t readX, readY;
+ uint32_t writeX, writeY;
+ uint32_t rwWidth, rwHeight;
+ Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+ Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
- if (!mContext->ValidateTexImage(texImageTarget, level, internalFormat,
- 0, 0, 0,
- width, height, depth,
- border, unpackFormat, unpackType, func, dims))
+ if (!rwWidth || !rwHeight) {
+ // There aren't any, so we're 'done'.
+ mContext->DummyFramebufferOperation(funcName);
+ return;
+ }
+
+ bool uploadWillInitialize;
+ if (!EnsureImageDataInitializedForUpload(this, funcName, target, level, xOffset,
+ yOffset, zOffset, width, height, depth,
+ imageInfo, &uploadWillInitialize))
{
return;
}
- if (!mContext->ValidateTexInputData(unpackType, jsArrayType, func, dims))
- return;
-
- TexInternalFormat effectiveInternalFormat =
- EffectiveInternalFormatFromInternalFormatAndType(internalFormat, unpackType);
-
- if (effectiveInternalFormat == LOCAL_GL_NONE) {
- return mContext->ErrorInvalidOperation("texImage3D: bad combination of internalFormat and unpackType");
- }
-
- // we need to find the exact sized format of the source data. Slightly abusing
- // EffectiveInternalFormatFromInternalFormatAndType for that purpose. Really, an unsized source format
- // is the same thing as an unsized internalFormat.
- TexInternalFormat effectiveSourceFormat =
- EffectiveInternalFormatFromInternalFormatAndType(unpackFormat, unpackType);
- MOZ_ASSERT(effectiveSourceFormat != LOCAL_GL_NONE); // should have validated unpack format/type combo earlier
- const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
- MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
- size_t srcTexelSize = srcbitsPerTexel / 8;
-
- CheckedUint32 checked_neededByteLength =
- mContext->GetImageSize(height, width, depth, srcTexelSize, mContext->mPixelStoreUnpackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return mContext->ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
-
- uint32_t bytesNeeded = checked_neededByteLength.value();
-
- if (dataLength && dataLength < bytesNeeded)
- return mContext->ErrorInvalidOperation("texImage3D: not enough data for operation (need %d, have %d)",
- bytesNeeded, dataLength);
-
- if (mImmutable) {
- return mContext->ErrorInvalidOperation(
- "texImage3D: disallowed because the texture "
- "bound to this target has already been made immutable by texStorage3D");
- }
-
- gl::GLContext* gl = mContext->gl;
- gl->MakeCurrent();
-
- GLenum driverUnpackType = LOCAL_GL_NONE;
- GLenum driverInternalFormat = LOCAL_GL_NONE;
- GLenum driverUnpackFormat = LOCAL_GL_NONE;
- DriverFormatsFromEffectiveInternalFormat(gl,
- effectiveInternalFormat,
- &driverInternalFormat,
- &driverUnpackFormat,
- &driverUnpackType);
+ GLenum error = DoCopyTexSubImage(mContext->gl, target, level, xOffset + writeX,
+ yOffset + writeY, zOffset, readX, readY, rwWidth,
+ rwHeight);
- mContext->GetAndFlushUnderlyingGLErrors();
- gl->fTexImage3D(texImageTarget.get(), level,
- driverInternalFormat,
- width, height, depth,
- 0, driverUnpackFormat, driverUnpackType,
- data);
- GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
- if (error) {
- return mContext->GenerateWarning("texImage3D generated error %s", mContext->ErrorName(error));
+ if (error == LOCAL_GL_OUT_OF_MEMORY) {
+ mContext->ErrorOutOfMemory("%s: Ran out of memory during texture copy.",
+ funcName);
+ return;
}
-
- const bool isDataInitialized = bool(data);
- const ImageInfo imageInfo(effectiveInternalFormat, width, height, depth,
- isDataInitialized);
- SetImageInfoAt(texImageTarget, level, imageInfo);
-}
-
-void
-WebGLTexture::TexSubImage3D(TexImageTarget texImageTarget, GLint level,
- GLint xOffset, GLint yOffset, GLint zOffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum unpackFormat, GLenum unpackType,
- const dom::Nullable<dom::ArrayBufferViewOrSharedArrayBufferView>& maybeView,
- ErrorResult* const out_rv)
-{
- if (maybeView.IsNull())
- return mContext->ErrorInvalidValue("texSubImage3D: pixels must not be null!");
-
- const auto& view = maybeView.Value();
- void* data;
- size_t dataLength;
- js::Scalar::Type jsArrayType;
- ComputeLengthAndData(view, &data, &dataLength, &jsArrayType);
-
- const char funcName[] = "texSubImage3D";
- if (!DoesTargetMatchDimensions(mContext, texImageTarget, 3, funcName))
- return;
-
- const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
- const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
-
- WebGLTexture::ImageInfo& imageInfo = ImageInfoAt(texImageTarget, level);
- if (!imageInfo.IsDefined()) {
- return mContext->ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
- }
-
- const TexInternalFormat existingEffectiveInternalFormat = imageInfo.mFormat;
- TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
- TexType existingType = LOCAL_GL_NONE;
- UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
- &existingUnsizedInternalFormat,
- &existingType);
-
- if (!mContext->ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
- xOffset, yOffset, zOffset,
- width, height, depth,
- 0, unpackFormat, unpackType, func, dims))
- {
+ if (error) {
+ MOZ_RELEASE_ASSERT(false, "We should have caught all other errors.");
+ mContext->GenerateWarning("%s: Unexpected error during texture copy. Context"
+ " lost.",
+ funcName);
+ mContext->ForceLoseContext();
return;
}
- if (unpackType != existingType) {
- return mContext->ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
- }
-
- if (!mContext->ValidateTexInputData(unpackType, 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 =
- mContext->GetImageSize(height, width, depth, srcTexelSize, mContext->mPixelStoreUnpackAlignment);
-
- if (!checked_neededByteLength.isValid())
- return mContext->ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
-
- uint32_t bytesNeeded = checked_neededByteLength.value();
-
- if (dataLength < bytesNeeded)
- return mContext->ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
+ ////////////////////////////////////
+ // Update our specification data?
- if (!imageInfo.IsDataInitialized()) {
- bool coversWholeImage = xOffset == 0 &&
- yOffset == 0 &&
- zOffset == 0 &&
- uint32_t(width) == imageInfo.mWidth &&
- uint32_t(height) == imageInfo.mHeight &&
- uint32_t(depth) == imageInfo.mDepth;
- if (coversWholeImage) {
- imageInfo.SetIsDataInitialized(true, this);
- } else {
- if (!EnsureInitializedImageData(texImageTarget, level))
- return;
- }
+ if (uploadWillInitialize) {
+ imageInfo->SetIsDataInitialized(true, this);
}
-
- GLenum driverUnpackType = LOCAL_GL_NONE;
- GLenum driverInternalFormat = LOCAL_GL_NONE;
- GLenum driverUnpackFormat = LOCAL_GL_NONE;
- DriverFormatsFromEffectiveInternalFormat(mContext->gl,
- existingEffectiveInternalFormat,
- &driverInternalFormat,
- &driverUnpackFormat,
- &driverUnpackType);
-
- mContext->MakeContextCurrent();
- mContext->gl->fTexSubImage3D(texImageTarget.get(), level,
- xOffset, yOffset, zOffset,
- width, height, depth,
- driverUnpackFormat, driverUnpackType, data);
}
-
} // namespace mozilla
--- a/dom/canvas/WebGLTimerQuery.cpp
+++ b/dom/canvas/WebGLTimerQuery.cpp
@@ -45,17 +45,17 @@ WebGLTimerQuery::Delete()
{
mContext->MakeContextCurrent();
mContext->gl->fDeleteQueries(1, &mGLName);
}
WebGLContext*
WebGLTimerQuery::GetParentObject() const
{
- return Context();
+ return mContext;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTimerQuery)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTimerQuery, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTimerQuery, Release)
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -36,17 +36,17 @@ WebGLTransformFeedback::Delete()
mContext->MakeContextCurrent();
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
removeFrom(mContext->mTransformFeedbacks);
}
WebGLContext*
WebGLTransformFeedback::GetParentObject() const
{
- return Context();
+ return mContext;
}
JSObject*
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLTransformFeedbackBinding::Wrap(cx, this, givenProto);
}
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -98,16 +98,17 @@ enum class WebGLTexelFormat : uint8_t {
R32F, // OES_texture_float
A32F, // OES_texture_float
// 2-channel formats
RA8,
RA16F, // OES_texture_half_float
RA32F, // OES_texture_float
// 3-channel formats
RGB8,
+ RGBX8, // used for DOM elements. Source format only.
BGRX8, // used for DOM elements. Source format only.
RGB565,
RGB16F, // OES_texture_half_float
RGB32F, // OES_texture_float
// 4-channel formats
RGBA8,
BGRA8, // used for DOM elements
RGBA5551,
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -42,17 +42,17 @@ public:
return HasAttrib(index) && mAttribs[index].enabled;
}
// Implement parent classes:
void Delete();
bool IsVertexArray();
WebGLContext* GetParentObject() const {
- return Context();
+ return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLVertexArray)
GLuint GLName() const { return mGLName; }
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -48,18 +48,18 @@ UNIFIED_SOURCES += [
'DocumentRendererParent.cpp',
'ImageBitmap.cpp',
'ImageData.cpp',
'OffscreenCanvas.cpp',
]
# WebGL Sources
UNIFIED_SOURCES += [
- 'ElementTexSource.cpp',
'MurmurHash3.cpp',
+ 'TexUnpackBlob.cpp',
'WebGL1Context.cpp',
'WebGL1ContextBuffers.cpp',
'WebGL1ContextUniforms.cpp',
'WebGL2Context.cpp',
'WebGL2ContextBuffers.cpp',
'WebGL2ContextDraw.cpp',
'WebGL2ContextFramebuffers.cpp',
'WebGL2ContextMRTs.cpp',
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -339,40 +339,50 @@ interface WebGL2RenderingContext : WebGL
[Throws]
any getInternalformatParameter(GLenum target, GLenum internalformat, GLenum pname);
void renderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
/* Texture objects */
void texStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
void texStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height,
GLsizei depth);
- [Throws]
- void texImage3D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLenum format,
+
+ void texImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLsizei depth, GLint border, GLenum format,
GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
- [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
- (ArrayBufferView or SharedArrayBufferView)? pixels);
- [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, ImageData? data);
- [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, HTMLImageElement image);
- [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, HTMLCanvasElement canvas);
- [Throws] void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLenum format, GLenum type, HTMLVideoElement video);
- void copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLint x, GLint y, GLsizei width, GLsizei height);
+ [Throws] // Can't actually throw.
+ void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type,
+ (ArrayBufferView or SharedArrayBufferView)? pixels);
+ [Throws] // Can't actually throw.
+ void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLenum format, GLenum type, ImageData? data);
+ [Throws]
+ void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLenum format, GLenum type, HTMLImageElement image);
+ [Throws]
+ void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLenum format, GLenum type,
+ HTMLCanvasElement canvas);
+ [Throws]
+ void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLenum format, GLenum type, HTMLVideoElement video);
+
+ void copyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLint x, GLint y, GLsizei width,
+ GLsizei height);
+
void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLsizei depth,
- GLint border, GLsizei imageSize, (ArrayBufferView or SharedArrayBufferView) data);
- void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height, GLsizei depth,
- GLenum format, GLsizei imageSize, (ArrayBufferView or SharedArrayBufferView) data);
+ GLsizei width, GLsizei height, GLsizei depth, GLint border,
+ (ArrayBufferView or SharedArrayBufferView) data);
+ void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint zoffset, GLsizei width, GLsizei height,
+ GLsizei depth, GLenum format,
+ (ArrayBufferView or SharedArrayBufferView) data);
/* Programs and shaders */
[WebGLHandlesContextLoss] GLint getFragDataLocation(WebGLProgram? program, DOMString name);
/* Uniforms and attributes */
void uniform1ui(WebGLUniformLocation? location, GLuint v0);
void uniform2ui(WebGLUniformLocation? location, GLuint v0, GLuint v1);
void uniform3ui(WebGLUniformLocation? location, GLuint v0, GLuint v1, GLuint v2);
--- a/dom/webidl/WebGLRenderingContext.webidl
+++ b/dom/webidl/WebGLRenderingContext.webidl
@@ -689,41 +689,42 @@ interface WebGLRenderingContext {
void stencilFunc(GLenum func, GLint ref, GLuint mask);
void stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
void stencilMask(GLuint mask);
void stencilMaskSeparate(GLenum face, GLuint mask);
void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
void stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
- [Throws]
+ // Overloads must share [Throws].
+ [Throws] // Can't actually throw.
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLsizei width, GLsizei height, GLint border, GLenum format,
GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
- [Throws]
+ [Throws] // Can't actually throw.
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, ImageData? pixels);
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, HTMLImageElement image); // May throw DOMException
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, HTMLCanvasElement canvas); // May throw DOMException
[Throws]
void texImage2D(GLenum target, GLint level, GLenum internalformat,
GLenum format, GLenum type, HTMLVideoElement video); // May throw DOMException
void texParameterf(GLenum target, GLenum pname, GLfloat param);
void texParameteri(GLenum target, GLenum pname, GLint param);
- [Throws]
+ [Throws] // Can't actually throw.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
- GLsizei width, GLsizei height,
- GLenum format, GLenum type, (ArrayBufferView or SharedArrayBufferView)? pixels);
- [Throws]
+ GLsizei width, GLsizei height, GLenum format, GLenum type,
+ (ArrayBufferView or SharedArrayBufferView)? pixels);
+ [Throws] // Can't actually throw.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, ImageData? pixels);
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, HTMLImageElement image); // May throw DOMException
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, HTMLCanvasElement canvas); // May throw DOMException
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -84,17 +84,17 @@ struct DrawOptions {
, mCompositionOp(aCompositionOp)
, mAntialiasMode(aAntialiasMode)
{}
Float mAlpha; /**< Alpha value by which the mask generated by this
operation is multiplied. */
CompositionOp mCompositionOp; /**< The operator that indicates how the source and
destination patterns are blended. */
- AntialiasMode mAntialiasMode; /**< The AntiAlias mode used for this drawing
+ AntialiasMode mAntialiasMode; /**< The AntiAlias mode used for this drawing
operation. */
};
/**
* This structure is used to send stroke options that are used in stroking
* operations.
*/
struct StrokeOptions {
@@ -410,35 +410,35 @@ public:
virtual ~ScopedMap()
{
if (mIsMapped) {
mSurface->Unmap();
}
}
- uint8_t* GetData()
+ uint8_t* GetData() const
{
MOZ_ASSERT(mIsMapped);
return mMap.mData;
}
- int32_t GetStride()
+ int32_t GetStride() const
{
MOZ_ASSERT(mIsMapped);
return mMap.mStride;
}
- MappedSurface* GetMappedSurface()
+ const MappedSurface* GetMappedSurface() const
{
MOZ_ASSERT(mIsMapped);
return &mMap;
}
- bool IsMapped() { return mIsMapped; }
+ bool IsMapped() const { return mIsMapped; }
private:
RefPtr<DataSourceSurface> mSurface;
MappedSurface mMap;
bool mIsMapped;
};
virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
@@ -522,17 +522,17 @@ class FlattenedPath;
/** The path class is used to create (sets of) figures of any shape that can be
* filled or stroked to a DrawTarget
*/
class Path : public RefCounted<Path>
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(Path)
virtual ~Path();
-
+
virtual BackendType GetBackendType() const = 0;
/** This returns a PathBuilder object that contains a copy of the contents of
* this path and is still writable.
*/
virtual already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const = 0;
virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(const Matrix &aTransform,
FillRule aFillRule = FillRule::FILL_WINDING) const = 0;
@@ -798,17 +798,17 @@ public:
* @param aDest Destination point to copy the surface to
*/
virtual void CopySurface(SourceSurface *aSurface,
const IntRect &aSourceRect,
const IntPoint &aDestination) = 0;
/** @see CopySurface
* Same as CopySurface, except uses itself as the source.
- *
+ *
* Some backends may be able to optimize this better
* than just taking a snapshot and using CopySurface.
*/
virtual void CopyRect(const IntRect &aSourceRect,
const IntPoint &aDestination)
{
RefPtr<SourceSurface> source = Snapshot();
CopySurface(source, aSourceRect, aDestination);
@@ -858,17 +858,17 @@ public:
* @param aPattern Pattern that should be used for the stroke
* @param aStrokeOptions Stroke options used for this operation
* @param aOptions Draw options used for this operation
*/
virtual void Stroke(const Path *aPath,
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions = StrokeOptions(),
const DrawOptions &aOptions = DrawOptions()) = 0;
-
+
/**
* Fill a path on the draw target with a certain source pattern.
*
* @param aPath Path that is to be filled
* @param aPattern Pattern that should be used for the fill
* @param aOptions Draw options used for this operation
*/
virtual void Fill(const Path *aPath,
@@ -963,17 +963,17 @@ public:
*/
virtual already_AddRefed<DrawTarget>
CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0;
/**
* Create a DrawTarget that captures the drawing commands and can be replayed
* onto a compatible DrawTarget afterwards.
*
- * @param aSize Size of the area this DT will capture.
+ * @param aSize Size of the area this DT will capture.
*/
virtual already_AddRefed<DrawTargetCapture> CreateCaptureDT(const IntSize& aSize);
/**
* Create a draw target optimized for drawing a shadow.
*
* Note that aSigma is the blur radius that must be used when we draw the
* shadow. Also note that this doesn't affect the size of the allocated
@@ -1165,17 +1165,17 @@ public:
static already_AddRefed<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
static already_AddRefed<DrawTarget>
CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
static already_AddRefed<DrawTarget>
CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT);
-
+
static already_AddRefed<DrawTarget>
CreateDrawTargetForData(BackendType aBackend, unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
static already_AddRefed<ScaledFont>
CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize);
/**
* This creates a ScaledFont from TrueType data.
--- a/gfx/2d/DataSurfaceHelpers.cpp
+++ b/gfx/2d/DataSurfaceHelpers.cpp
@@ -12,17 +12,17 @@
#include "mozilla/PodOperations.h"
#include "Tools.h"
namespace mozilla {
namespace gfx {
uint8_t*
DataAtOffset(DataSourceSurface* aSurface,
- DataSourceSurface::MappedSurface* aMap,
+ const DataSourceSurface::MappedSurface* aMap,
IntPoint aPoint)
{
if (!SurfaceContainsPoint(aSurface, aPoint)) {
MOZ_CRASH("sample position needs to be inside surface!");
}
MOZ_ASSERT(Factory::CheckSurfaceSize(aSurface->GetSize()),
"surface size overflows - this should have been prevented when the surface was created");
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -869,21 +869,18 @@ Factory::CreateWrappingDataSourceSurface
{
MOZ_ASSERT(aData);
if (aSize.width <= 0 || aSize.height <= 0) {
return nullptr;
}
RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
- if (newSurf->InitWrappingData(aData, aSize, aStride, aFormat, false)) {
- return newSurf.forget();
- }
-
- return nullptr;
+ newSurf->InitWrappingData(aData, aSize, aStride, aFormat, false);
+ return newSurf.forget();
}
already_AddRefed<DataSourceSurface>
Factory::CreateDataSourceSurface(const IntSize &aSize,
SurfaceFormat aFormat,
bool aZero)
{
if (!AllowedSurfaceSize(aSize)) {
--- a/gfx/2d/SourceSurfaceRawData.cpp
+++ b/gfx/2d/SourceSurfaceRawData.cpp
@@ -7,30 +7,28 @@
#include "DataSurfaceHelpers.h"
#include "Logging.h"
#include "mozilla/Types.h" // for decltype
namespace mozilla {
namespace gfx {
-bool
+void
SourceSurfaceRawData::InitWrappingData(uint8_t *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat,
bool aOwnData)
{
mRawData = aData;
mSize = aSize;
mStride = aStride;
mFormat = aFormat;
mOwnData = aOwnData;
-
- return true;
}
void
SourceSurfaceRawData::GuaranteePersistance()
{
if (mOwnData) {
return;
}
--- a/gfx/2d/SourceSurfaceRawData.h
+++ b/gfx/2d/SourceSurfaceRawData.h
@@ -28,17 +28,17 @@ public:
virtual uint8_t *GetData() override { return mRawData; }
virtual int32_t Stride() override { return mStride; }
virtual SurfaceType GetType() const override { return SurfaceType::DATA; }
virtual IntSize GetSize() const override { return mSize; }
virtual SurfaceFormat GetFormat() const override { return mFormat; }
- bool InitWrappingData(unsigned char *aData,
+ void InitWrappingData(unsigned char *aData,
const IntSize &aSize,
int32_t aStride,
SurfaceFormat aFormat,
bool aOwnData);
virtual void GuaranteePersistance() override;
// Althought Map (and Moz2D in general) isn't normally threadsafe,
--- a/gfx/2d/moz.build
+++ b/gfx/2d/moz.build
@@ -37,16 +37,17 @@ EXPORTS.mozilla.gfx += [
'PatternHelpers.h',
'Point.h',
'Quaternion.h',
'Rect.h',
'Scale.h',
'ScaleFactor.h',
'ScaleFactors2D.h',
'SourceSurfaceCairo.h',
+ 'SourceSurfaceRawData.h',
'StackArray.h',
'Tools.h',
'Types.h',
'UserData.h',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
EXPORTS.mozilla.gfx += [
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -519,10 +519,41 @@ ScopedPackAlignment::UnwrapImpl() {
// Check that we're not falling out of scope after the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
if (mOldVal) {
mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mOldVal);
}
}
+////////////////////////////////////////////////////////////////////////
+// ScopedUnpackAlignment
+
+ScopedUnpackAlignment::ScopedUnpackAlignment(GLContext* gl, GLint scopedVal)
+ : ScopedGLWrapper<ScopedUnpackAlignment>(gl)
+{
+ MOZ_ASSERT(scopedVal == 1 ||
+ scopedVal == 2 ||
+ scopedVal == 4 ||
+ scopedVal == 8);
+
+ gl->fGetIntegerv(LOCAL_GL_UNPACK_ALIGNMENT, &mOldVal);
+
+ if (scopedVal != mOldVal) {
+ gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, scopedVal);
+ } else {
+ // Don't try to re-set it during unwrap.
+ mOldVal = 0;
+ }
+}
+
+void
+ScopedUnpackAlignment::UnwrapImpl() {
+ // Check that we're not falling out of scope after the current context changed.
+ MOZ_ASSERT(mGL->IsCurrent());
+
+ if (mOldVal) {
+ mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, mOldVal);
+ }
+}
+
} /* namespace gl */
} /* namespace mozilla */
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -353,12 +353,29 @@ protected:
GLint mOldVal;
public:
ScopedPackAlignment(GLContext* aGL, GLint scopedVal);
protected:
void UnwrapImpl();
};
+
+
+struct ScopedUnpackAlignment
+ : public ScopedGLWrapper<ScopedUnpackAlignment>
+{
+ friend struct ScopedGLWrapper<ScopedUnpackAlignment>;
+
+protected:
+ GLint mOldVal;
+
+public:
+ ScopedUnpackAlignment(GLContext* gl, GLint scopedVal);
+
+protected:
+ void UnwrapImpl();
+};
+
} /* namespace gl */
} /* namespace mozilla */
#endif /* SCOPEDGLHELPERS_H_ */