Bug 1221822 - Finish the WebGL texture refactor. r=kamidphish,mattwoodrow,bz

This commit is contained in:
Jeff Gilbert 2015-11-23 19:27:13 -08:00
parent 66bbe5bc72
commit 87397c265b
101 changed files with 8226 additions and 7668 deletions

View File

@ -983,7 +983,7 @@ nsDOMWindowUtils::SendKeyEvent(const nsAString& aType,
{
// get the widget to send the event to
nsCOMPtr<nsIWidget> widget = GetWidget();
return nsContentUtils::SendKeyEvent(widget, aType, aKeyCode, aCharCode,
aModifiers, aAdditionalFlags,
aDefaultActionTaken);
@ -1312,7 +1312,7 @@ nsDOMWindowUtils::NodesFromRect(float aX, float aY,
nsCOMPtr<nsIDocument> doc = GetDocument();
NS_ENSURE_STATE(doc);
return doc->NodesFromRectHelper(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
return doc->NodesFromRectHelper(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize,
aIgnoreRootScrollFrame, aFlushLayout, aReturn);
}
@ -1408,7 +1408,9 @@ CanvasToDataSourceSurface(nsIDOMHTMLCanvasElement* aCanvas)
"be an element.");
nsLayoutUtils::SurfaceFromElementResult result =
nsLayoutUtils::SurfaceFromElement(node->AsElement());
return result.mSourceSurface->GetDataSurface();
MOZ_ASSERT(result.GetSourceSurface());
return result.GetSourceSurface()->GetDataSurface();
}
NS_IMETHODIMP
@ -1749,7 +1751,7 @@ nsDOMWindowUtils::GetFullZoom(float* aFullZoom)
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::DispatchDOMEventViaPresShell(nsIDOMNode* aTarget,
nsIDOMEvent* aEvent,
@ -2452,7 +2454,7 @@ nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
return presShell->RenderDocument(aRect, aFlags, aBackgroundColor, aThebesContext);
}
NS_IMETHODIMP
NS_IMETHODIMP
nsDOMWindowUtils::GetCursorType(int16_t *aCursor)
{
NS_ENSURE_ARG_POINTER(aCursor);

View File

@ -1209,8 +1209,8 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->MakeCurrent();
gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext()->fDeleteTextures(1, &mVideoTexture);
}
mCurrentVideoSize.width = 0;
mCurrentVideoSize.height = 0;
mCurrentVideoSize.width = 0;
mCurrentVideoSize.height = 0;
}
#endif
@ -2113,15 +2113,14 @@ CanvasRenderingContext2D::CreatePattern(const CanvasImageSource& source,
nsLayoutUtils::SurfaceFromElement(htmlElement,
nsLayoutUtils::SFE_WANT_FIRST_FRAME, mTarget);
if (!res.mSourceSurface) {
if (!res.GetSourceSurface()) {
error.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
RefPtr<CanvasPattern> pat =
new CanvasPattern(this, res.mSourceSurface, repeatMode, res.mPrincipal,
res.mIsWriteOnly, res.mCORSUsed);
RefPtr<CanvasPattern> pat = new CanvasPattern(this, res.GetSourceSurface(), repeatMode,
res.mPrincipal, res.mIsWriteOnly,
res.mCORSUsed);
return pat.forget();
}
@ -5407,9 +5406,9 @@ CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w
uint8_t* srcLine = aArray->Data() + copyY * (w * 4) + copyX * 4;
#if 0
printf("PutImageData_explicit: dirty x=%d y=%d w=%d h=%d copy x=%d y=%d w=%d h=%d ext x=%d y=%d w=%d h=%d\n",
dirtyRect.x, dirtyRect.y, copyWidth, copyHeight,
copyX, copyY, copyWidth, copyHeight,
x, y, w, h);
dirtyRect.x, dirtyRect.y, copyWidth, copyHeight,
copyX, copyY, copyWidth, copyHeight,
x, y, w, h);
#endif
for (uint32_t j = 0; j < copyHeight; j++) {
uint8_t *src = srcLine;

View File

@ -355,12 +355,13 @@ GetSurfaceFromElement(nsIGlobalObject* aGlobal, HTMLElementType& aElement, Error
return nullptr;
}
if (NS_WARN_IF(!res.mSourceSurface)) {
RefPtr<SourceSurface> surface = res.GetSourceSurface();
if (NS_WARN_IF(!surface)) {
aRv.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
}
RefPtr<SourceSurface> surface(res.mSourceSurface);
return surface.forget();
}

View File

@ -0,0 +1,773 @@
/* -*- 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 "mozilla/RefPtr.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)
{
if (isSubImage) {
return DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
depth, dui->ToPacking(), data);
} else {
return DoTexImage(gl, target, level, dui, width, height, depth, data);
}
}
/*static*/ void
TexUnpackBlob::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;
}
//////////////////////////////////////////////////////////////////////////////////////////
// TexUnpackBytes
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 bytesNeeded = webgl->GetUnpackSize(isFunc3D, mWidth, mHeight, mDepth,
bytesPerPixel);
if (!bytesNeeded.isValid()) {
webgl->ErrorInvalidOperation("%s: Overflow while computing the needed buffer"
" size.",
funcName);
return false;
}
if (mByteCount < bytesNeeded.value()) {
webgl->ErrorInvalidOperation("%s: Provided buffer is too small. (needs %u, has"
" %u)",
funcName, bytesNeeded.value(), 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, bool needsRespec, 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();
} while (false);
GLenum error = DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
zOffset, mWidth, mHeight, mDepth, uploadBytes);
*out_glError = error;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TexUnpackImage
TexUnpackImage::TexUnpackImage(const RefPtr<layers::Image>& image, bool isAlphaPremult)
: TexUnpackBlob(image->GetSize().width, image->GetSize().height, 1, true)
, mImage(image)
, mIsAlphaPremult(isAlphaPremult)
{ }
TexUnpackImage::~TexUnpackImage()
{ }
void
TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum* const out_glError)
{
MOZ_ASSERT_IF(needsRespec, !isSubImage);
*out_glError = 0;
WebGLContext* webgl = tex->mContext;
gl::GLContext* gl = webgl->GL();
gl->MakeCurrent();
if (needsRespec) {
GLenum error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset,
yOffset, zOffset, mWidth, mHeight, mDepth,
nullptr);
if (error) {
MOZ_ASSERT(!error);
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
return;
}
}
do {
if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA)
break;
if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE)
break;
gl::ScopedFramebuffer scopedFB(gl);
gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB());
{
gl::GLContext::LocalErrorScope errorScope(*gl);
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
target.get(), tex->mGLName, level);
if (errorScope.GetError())
break;
}
const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
break;
gl::OriginPos srcOrigin, dstOrigin;
OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
const gfx::IntSize destSize(mWidth, mHeight);
if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(),
dstOrigin))
{
break;
}
return; // Blitting was successful, so we're done!
} while (false);
TexUnpackSurface surfBlob(mImage->GetAsSourceSurface(), mIsAlphaPremult);
surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui,
xOffset, yOffset, zOffset, out_glError);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// TexUnpackSurface
static bool
GuessAlignment(const void* data, size_t bytesPerRow, size_t stride, size_t maxAlignment,
size_t* const out_alignment)
{
size_t alignmentGuess = maxAlignment;
while (alignmentGuess) {
size_t guessStride = RoundUpToMultipleOf(bytesPerRow, 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*/ 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)
{
gl::GLContext* gl = webgl->GL();
MOZ_ASSERT(gl->IsCurrent());
*out_glError = 0;
if (isSurfAlphaPremult != webgl->mPixelStore_PremultiplyAlpha)
return false;
gl::OriginPos srcOrigin, dstOrigin;
OriginsForDOM(webgl, &srcOrigin, &dstOrigin);
if (srcOrigin != dstOrigin)
return false;
// 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 (SupportsBGRA(gl) &&
dui->internalFormat == LOCAL_GL_RGBA &&
dui->unpackFormat == LOCAL_GL_RGBA &&
dui->unpackType == LOCAL_GL_UNSIGNED_BYTE)
{
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;
default:
break;
}
if (!chosenDUI)
return false;
gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::MapType::READ);
if (!map.IsMapped())
return false;
const webgl::PackingInfo pi = {chosenDUI->unpackFormat, chosenDUI->unpackType};
const auto bytesPerPixel = webgl::BytesPerPixel(pi);
const size_t bytesPerRow = width * bytesPerPixel;
const GLint kMaxUnpackAlignment = 8;
size_t unpackAlignment;
if (!GuessAlignment(map.GetData(), bytesPerRow, map.GetStride(), kMaxUnpackAlignment,
&unpackAlignment))
{
return false;
// TODO: Consider using UNPACK_ settings to set the stride based on the too-large
// alignment used for some SourceSurfaces. (D2D allegedy likes alignment=16)
}
MOZ_ALWAYS_TRUE( webgl->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;
default:
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;
}
break;
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
switch (packingFormat) {
case LOCAL_GL_RGB:
*out_texelFormat = WebGLTexelFormat::RGB565;
return true;
default:
break;
}
break;
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
switch (packingFormat) {
case LOCAL_GL_RGBA:
*out_texelFormat = WebGLTexelFormat::RGBA5551;
return true;
default:
break;
}
break;
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
switch (packingFormat) {
case LOCAL_GL_RGBA:
*out_texelFormat = WebGLTexelFormat::RGBA4444;
return true;
default:
break;
}
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;
}
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;
}
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:
// After we call this, on OSX, our GLContext will no longer be current.
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)
{ }
TexUnpackSurface::~TexUnpackSurface()
{ }
void
TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, 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;
WebGLContext* webgl = tex->mContext;
// MakeCurrent is a big mess in here, because mapping (and presumably unmapping) on
// OSX can lose our MakeCurrent. Therefore it's easiest to MakeCurrent just before we
// call into GL, instead of trying to keep MakeCurrent-ed.
RefPtr<gfx::DataSourceSurface> dataSurf = mSurf->GetDataSurface();
MOZ_ASSERT(dataSurf);
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 {
NS_ERROR("Failed to convert surface.");
*out_glError = LOCAL_GL_OUT_OF_MEMORY;
}
return;
}
MOZ_ALWAYS_TRUE( webgl->gl->MakeCurrent() );
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

162
dom/canvas/TexUnpackBlob.h Normal file
View File

@ -0,0 +1,162 @@
/* -*- 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 "GLTypes.h"
#include "WebGLStrongTypes.h"
template <class T>
class RefPtr;
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 ~TexUnpackBlob() {}
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
const webgl::PackingInfo& pi) = 0;
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
WebGLTexture* tex, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLint xOffset,
GLint yOffset, GLint zOffset,
GLenum* const out_glError) = 0;
static void OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
gl::OriginPos* const out_dst);
};
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, bool needsRespec, 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 TexUnpackImage : public TexUnpackBlob
{
public:
const RefPtr<layers::Image> mImage;
const bool mIsAlphaPremult;
TexUnpackImage(const RefPtr<layers::Image>& image, bool isAlphaPremult);
virtual ~TexUnpackImage() override;
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
const webgl::PackingInfo& pi) override
{
return true;
}
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, 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 ~TexUnpackSurface() override;
virtual bool ValidateUnpack(WebGLContext* webgl, const char* funcName, bool isFunc3D,
const webgl::PackingInfo& pi) override
{
return true;
}
virtual void TexOrSubImage(bool isSubImage, bool needsRespec, 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);
};
} // namespace webgl
} // namespace mozilla
#endif // TEX_UNPACK_BLOB_H_

View File

@ -27,9 +27,9 @@ WebGL1Context::~WebGL1Context()
}
UniquePtr<webgl::FormatUsageAuthority>
WebGL1Context::CreateFormatUsage() const
WebGL1Context::CreateFormatUsage(gl::GLContext* gl) const
{
return webgl::FormatUsageAuthority::CreateForWebGL1();
return webgl::FormatUsageAuthority::CreateForWebGL1(gl);
}
JSObject*

View File

@ -18,7 +18,9 @@ public:
private:
WebGL1Context();
virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage() const override;
virtual UniquePtr<webgl::FormatUsageAuthority>
CreateFormatUsage(gl::GLContext* gl) const override;
public:
virtual ~WebGL1Context();

View File

@ -29,9 +29,9 @@ 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
@ -55,20 +55,6 @@ WebGL2Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
////////////////////////////////////////////////////////////////////////////////
// WebGL 2 initialisation
// These WebGL 1 extensions are natively supported by WebGL 2.
static const WebGLExtensionID kNativelySupportedExtensions[] = {
WebGLExtensionID::ANGLE_instanced_arrays,
WebGLExtensionID::EXT_blend_minmax,
WebGLExtensionID::EXT_sRGB,
WebGLExtensionID::OES_element_index_uint,
WebGLExtensionID::OES_standard_derivatives,
WebGLExtensionID::OES_texture_float_linear,
WebGLExtensionID::OES_texture_half_float_linear,
WebGLExtensionID::OES_vertex_array_object,
WebGLExtensionID::WEBGL_depth_texture,
WebGLExtensionID::WEBGL_draw_buffers
};
static const gl::GLFeature kRequiredFeatures[] = {
gl::GLFeature::blend_minmax,
gl::GLFeature::clear_buffers,
@ -151,35 +137,25 @@ WebGLContext::InitWebGL2()
return false;
}
// ok WebGL 2 is compatible, we can enable natively supported extensions.
for (size_t i = 0; i < ArrayLength(kNativelySupportedExtensions); i++) {
EnableExtension(kNativelySupportedExtensions[i]);
MOZ_ASSERT(IsExtensionEnabled(kNativelySupportedExtensions[i]));
}
// 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;
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);
}
return true;
}

View File

@ -8,12 +8,6 @@
#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;
@ -96,37 +90,47 @@ public:
// -------------------------------------------------------------------------
// 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);
// -------------------------------------------------------------------------
@ -383,7 +387,8 @@ public:
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;

View File

@ -13,107 +13,12 @@
namespace mozilla {
using gl::GLContext;
using gl::GLFormats;
using webgl::EffectiveFormat;
using webgl::FormatInfo;
using webgl::ComponentType;
// Returns one of FLOAT, INT, UNSIGNED_INT.
// Fixed-points (normalized ints) are considered FLOAT.
static GLenum
ValueTypeForFormat(GLenum internalFormat)
{
switch (internalFormat) {
// Fixed-point
case LOCAL_GL_R8:
case LOCAL_GL_RG8:
case LOCAL_GL_RGB565:
case LOCAL_GL_RGB8:
case LOCAL_GL_RGBA4:
case LOCAL_GL_RGB5_A1:
case LOCAL_GL_RGBA8:
case LOCAL_GL_RGB10_A2:
case LOCAL_GL_ALPHA8:
case LOCAL_GL_LUMINANCE8:
case LOCAL_GL_LUMINANCE8_ALPHA8:
case LOCAL_GL_SRGB8:
case LOCAL_GL_SRGB8_ALPHA8:
case LOCAL_GL_R8_SNORM:
case LOCAL_GL_RG8_SNORM:
case LOCAL_GL_RGB8_SNORM:
case LOCAL_GL_RGBA8_SNORM:
// Floating-point
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:
case LOCAL_GL_R11F_G11F_B10F:
case LOCAL_GL_RGB9_E5:
return LOCAL_GL_FLOAT;
// Int
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:
return LOCAL_GL_INT;
// Unsigned int
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:
return LOCAL_GL_UNSIGNED_INT;
default:
MOZ_CRASH("Bad `internalFormat`.");
}
}
// -------------------------------------------------------------------------
// Framebuffer objects
static bool
GetFBInfoForBlit(const WebGLFramebuffer* fb, WebGLContext* webgl,
const char* const fbInfo, GLsizei* const out_samples,
GLenum* const out_colorFormat, GLenum* const out_depthFormat,
GLenum* const out_stencilFormat)
const webgl::FormatInfo** const out_colorFormat,
const webgl::FormatInfo** const out_depthFormat,
const webgl::FormatInfo** const out_stencilFormat)
{
auto status = fb->PrecheckFramebufferStatus();
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
@ -123,36 +28,58 @@ GetFBInfoForBlit(const WebGLFramebuffer* fb, WebGLContext* webgl,
}
*out_samples = 1; // TODO
*out_colorFormat = nullptr;
*out_depthFormat = nullptr;
*out_stencilFormat = nullptr;
if (fb->ColorAttachment(0).IsDefined()) {
const auto& attachement = fb->ColorAttachment(0);
*out_colorFormat = attachement.EffectiveInternalFormat().get();
} else {
*out_colorFormat = 0;
const auto& attachment = fb->ColorAttachment(0);
*out_colorFormat = attachment.Format()->format;
}
if (fb->DepthStencilAttachment().IsDefined()) {
const auto& attachement = fb->DepthStencilAttachment();
*out_depthFormat = attachement.EffectiveInternalFormat().get();
const auto& attachment = fb->DepthStencilAttachment();
*out_depthFormat = attachment.Format()->format;
*out_stencilFormat = *out_depthFormat;
} else {
if (fb->DepthAttachment().IsDefined()) {
const auto& attachement = fb->DepthAttachment();
*out_depthFormat = attachement.EffectiveInternalFormat().get();
} else {
*out_depthFormat = 0;
const auto& attachment = fb->DepthAttachment();
*out_depthFormat = attachment.Format()->format;
}
if (fb->StencilAttachment().IsDefined()) {
const auto& attachement = fb->StencilAttachment();
*out_stencilFormat = attachement.EffectiveInternalFormat().get();
} else {
*out_stencilFormat = 0;
const auto& attachment = fb->StencilAttachment();
*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,
@ -196,9 +123,9 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
}
GLsizei srcSamples;
GLenum srcColorFormat = 0;
GLenum srcDepthFormat = 0;
GLenum srcStencilFormat = 0;
const webgl::FormatInfo* srcColorFormat = nullptr;
const webgl::FormatInfo* srcDepthFormat = nullptr;
const webgl::FormatInfo* srcStencilFormat = nullptr;
if (mBoundReadFramebuffer) {
if (!GetFBInfoForBlit(mBoundReadFramebuffer, this, "READ_FRAMEBUFFER",
@ -210,26 +137,14 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
} 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",
@ -241,36 +156,39 @@ WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY
} 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 GLenum srcColorType = srcColorFormat ? ValueTypeForFormat(srcColorFormat)
: 0;
const GLenum dstColorType = dstColorFormat ? ValueTypeForFormat(dstColorFormat)
: 0;
if (dstColorType != srcColorType) {
ErrorInvalidOperation("blitFramebuffer: Color buffer value type"
const auto fnSignlessType = [](const webgl::FormatInfo* format)
-> webgl::ComponentType
{
if (!format)
return webgl::ComponentType::None;
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.");
@ -378,16 +296,16 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
if (level < 0)
return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
switch (texture->Target()) {
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");
}
@ -397,9 +315,6 @@ WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
} else {
return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
"existing 3D texture, or a 2D texture array.");
}
WebGLFramebuffer* fb;
@ -430,96 +345,10 @@ 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."
if (!ValidateFramebufferTarget(target, "getFramebufferAttachmentParameter"))
return JS::NullValue();
// FRAMEBUFFER is equivalent to DRAW_FRAMEBUFFER.
if (target == LOCAL_GL_FRAMEBUFFER)
target = LOCAL_GL_DRAW_FRAMEBUFFER;
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);
}
// 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. */
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;
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:
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(effectiveFormat, pname));
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT &&
pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE)
{
ErrorInvalidOperation("getFramebufferAttachmentParameter: Querying "
"FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE against "
"DEPTH_STENCIL_ATTACHMENT is an error.");
return JS::NullValue();
}
return JS::Int32Value(webgl::GetComponentType(effectiveFormat));
case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
return JS::Int32Value(webgl::GetColorEncoding(effectiveFormat));
}
/* Any combinations of framebuffer type and pname not described above will generate an
INVALID_ENUM error. */
ErrorInvalidEnum("getFramebufferAttachmentParameter: Invalid combination of ");
return JS::NullValue();
return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
out_error);
}
// Map attachments intended for the default buffer, to attachments for a non-
@ -557,12 +386,14 @@ WebGL2Context::InvalidateFramebuffer(GLenum target,
const dom::Sequence<GLenum>& attachments,
ErrorResult& rv)
{
const char funcName[] = "invalidateSubFramebuffer";
if (IsContextLost())
return;
MakeContextCurrent();
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
const WebGLFramebuffer* fb;
@ -583,9 +414,10 @@ WebGL2Context::InvalidateFramebuffer(GLenum target,
MOZ_CRASH("Bad target.");
}
const bool badColorAttachmentIsInvalidOp = true;
for (size_t i = 0; i < attachments.Length(); i++) {
if (!ValidateFramebufferAttachment(fb, attachments[i],
"invalidateFramebuffer"))
if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
badColorAttachmentIsInvalidOp))
{
return;
}
@ -594,8 +426,7 @@ WebGL2Context::InvalidateFramebuffer(GLenum target,
// InvalidateFramebuffer is a hint to the driver. Should be OK to
// skip calls if not supported, for example by OSX 10.9 GL
// drivers.
static bool invalidateFBSupported = gl->IsSupported(gl::GLFeature::invalidate_framebuffer);
if (!invalidateFBSupported)
if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
return;
if (!fb && !isDefaultFB) {
@ -605,7 +436,8 @@ WebGL2Context::InvalidateFramebuffer(GLenum target,
return;
}
gl->fInvalidateFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements());
gl->fInvalidateFramebuffer(target, tmpAttachments.Length(),
tmpAttachments.Elements());
} else {
gl->fInvalidateFramebuffer(target, attachments.Length(), attachments.Elements());
}
@ -616,14 +448,21 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
GLint x, GLint y, GLsizei width, GLsizei height,
ErrorResult& rv)
{
const char funcName[] = "invalidateSubFramebuffer";
if (IsContextLost())
return;
MakeContextCurrent();
if (!ValidateFramebufferTarget(target, "framebufferRenderbuffer"))
if (!ValidateFramebufferTarget(target, funcName))
return;
if (width < 0 || height < 0) {
ErrorInvalidValue("%s: width and height must be >= 0.", funcName);
return;
}
const WebGLFramebuffer* fb;
bool isDefaultFB;
switch (target) {
@ -642,9 +481,10 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
MOZ_CRASH("Bad target.");
}
const bool badColorAttachmentIsInvalidOp = true;
for (size_t i = 0; i < attachments.Length(); i++) {
if (!ValidateFramebufferAttachment(fb, attachments[i],
"invalidateSubFramebuffer"))
if (!ValidateFramebufferAttachment(fb, attachments[i], funcName,
badColorAttachmentIsInvalidOp))
{
return;
}
@ -653,8 +493,7 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
// InvalidateFramebuffer is a hint to the driver. Should be OK to
// skip calls if not supported, for example by OSX 10.9 GL
// drivers.
static bool invalidateFBSupported = gl->IsSupported(gl::GLFeature::invalidate_framebuffer);
if (!invalidateFBSupported)
if (!gl->IsSupported(gl::GLFeature::invalidate_framebuffer))
return;
if (!fb && !isDefaultFB) {
@ -664,11 +503,11 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
return;
}
gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(), tmpAttachments.Elements(),
x, y, width, height);
gl->fInvalidateSubFramebuffer(target, tmpAttachments.Length(),
tmpAttachments.Elements(), x, y, width, height);
} else {
gl->fInvalidateSubFramebuffer(target, attachments.Length(), attachments.Elements(),
x, y, width, height);
gl->fInvalidateSubFramebuffer(target, attachments.Length(),
attachments.Elements(), x, y, width, height);
}
}
@ -679,7 +518,7 @@ WebGL2Context::ReadBuffer(GLenum mode)
return;
const bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mode <= LastColorAttachment());
mode <= LastColorAttachmentEnum());
if (mode != LOCAL_GL_NONE && mode != LOCAL_GL_BACK && !isColorAttachment) {
ErrorInvalidEnum("readBuffer: `mode` must be one of NONE, BACK, or "

View File

@ -59,8 +59,6 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
/* 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:
@ -89,6 +87,12 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
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
@ -151,9 +155,7 @@ WebGL2Context::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
return WebGLObjectAsJSValue(cx, mBoundSamplers[mActiveTexture].get(), rv);
case LOCAL_GL_TEXTURE_BINDING_2D_ARRAY:
// TODO: Implement gl.TEXTURE_2D_ARRAY
// return WebGLObjectAsJSValue(cx, mBound2DTextureArrays[mActiveTexture].get(), rv);
return JS::NullValue();
return WebGLObjectAsJSValue(cx, mBound2DArrayTextures[mActiveTexture].get(), rv);
case LOCAL_GL_TEXTURE_BINDING_3D:
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);

View File

@ -11,15 +11,19 @@
namespace mozilla {
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;
const uint8_t funcDims = 2;
TexTarget target;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &target, &tex))
return;
tex->TexStorage2D(texTarget, levels, internalFormat, width, height);
const GLsizei depth = 1;
tex->TexStorage(funcName, target, levels, internalFormat, width, height, depth);
}
void
@ -27,88 +31,178 @@ WebGL2Context::TexStorage3D(GLenum rawTexTarget, GLsizei levels, GLenum internal
GLsizei width, GLsizei height, GLsizei depth)
{
const char funcName[] = "texStorage3D";
TexTarget texTarget;
const uint8_t funcDims = 3;
TexTarget target;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, funcName, &texTarget, &tex))
if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &target, &tex))
return;
tex->TexStorage3D(texTarget, levels, internalFormat, width, height, depth);
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;
}
tex->TexImage3D(texImageTarget, level, internalFormat, width, height, depth, border,
unpackFormat, unpackType, maybeView, &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, 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,
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)
ErrorResult& /*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;
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 target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
GLenum unpackFormat, GLenum unpackType, dom::ImageData* imageData,
ErrorResult& out_rv)
WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum unpackFormat,
GLenum unpackType, dom::ImageData* imageData,
ErrorResult& /*out_rv*/)
{
GenerateWarning("texSubImage3D: Not implemented.");
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;
tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
yOffset, zOffset, unpackFormat, unpackType, imageData);
}
void
WebGL2Context::CopyTexSubImage3D(GLenum target, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
GLint x, GLint y, GLsizei width, GLsizei height)
WebGL2Context::TexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLenum unpackFormat,
GLenum unpackType, dom::Element* elem,
ErrorResult* const out_rv)
{
GenerateWarning("copyTexSubImage3D: Not implemented.");
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;
tex->TexOrSubImage(isSubImage, funcName, target, level, internalFormat, xOffset,
yOffset, zOffset, unpackFormat, unpackType, elem, out_rv);
}
void
WebGL2Context::CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei depth,
GLint border, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
WebGL2Context::CompressedTexImage3D(GLenum rawTexImageTarget, GLint level,
GLenum internalFormat, GLsizei width, GLsizei height,
GLsizei depth, GLint border,
const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
GenerateWarning("compressedTexImage3D: 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::CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset,
WebGL2Context::CompressedTexSubImage3D(GLenum rawTexImageTarget, GLint level,
GLint xOffset, GLint yOffset, GLint zOffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum unpackFormat, GLsizei imageSize, const dom::ArrayBufferViewOrSharedArrayBufferView& view)
GLenum sizedUnpackFormat,
const dom::ArrayBufferViewOrSharedArrayBufferView& view)
{
GenerateWarning("compressedTexSubImage3D: 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);
}
bool
void
WebGL2Context::CopyTexSubImage3D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLint x, GLint y,
GLsizei width, GLsizei height)
{
const char funcName[] = "copyTexSubImage3D";
const uint8_t funcDims = 3;
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);
}
/*virtual*/ bool
WebGL2Context::IsTexParamValid(GLenum pname) const
{
switch (pname) {

View File

@ -55,7 +55,7 @@ public:
bool IsElementArrayUsedWithMultipleTypes() const;
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;

View File

@ -95,6 +95,10 @@ WebGLContextOptions::WebGLContextOptions()
alpha = false;
}
/*static*/ const uint32_t WebGLContext::kMinMaxColorAttachments = 4;
/*static*/ const uint32_t WebGLContext::kMinMaxDrawBuffers = 4;
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
, mBypassShaderValidation(false)
@ -111,11 +115,6 @@ WebGLContext::WebGLContext()
mOptionsFrozen = false;
mActiveTexture = 0;
mPixelStoreFlipY = false;
mPixelStorePremultiplyAlpha = false;
mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
mVertexAttrib0Vector[0] = 0;
mVertexAttrib0Vector[1] = 0;
@ -140,31 +139,6 @@ WebGLContext::WebGLContext()
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);
@ -224,6 +198,7 @@ WebGLContext::DestroyResourcesAndContext()
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
mBound2DArrayTextures.Clear();
mBoundSamplers.Clear();
mBoundArrayBuffer = nullptr;
mBoundCopyReadBuffer = nullptr;
@ -267,10 +242,14 @@ WebGLContext::DestroyResourcesAndContext()
while (!mTransformFeedbacks.isEmpty())
mTransformFeedbacks.getLast()->DeleteOnce();
mBlackOpaqueTexture2D = nullptr;
mBlackOpaqueTextureCubeMap = nullptr;
mBlackTransparentTexture2D = nullptr;
mBlackTransparentTextureCubeMap = nullptr;
mFakeBlack_2D_0000 = nullptr;
mFakeBlack_2D_0001 = nullptr;
mFakeBlack_CubeMap_0000 = nullptr;
mFakeBlack_CubeMap_0001 = nullptr;
mFakeBlack_3D_0000 = nullptr;
mFakeBlack_3D_0001 = nullptr;
mFakeBlack_2D_Array_0000 = nullptr;
mFakeBlack_2D_Array_0001 = nullptr;
if (mFakeVertexAttrib0BufferObject)
gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
@ -1298,37 +1277,37 @@ WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval)
void
WebGLContext::ClearScreen()
{
bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false};
MakeContextCurrent();
ScopedBindFramebuffer autoFB(gl, 0);
GLbitfield clearMask = LOCAL_GL_COLOR_BUFFER_BIT;
const bool changeDrawBuffers = (mDefaultFB_DrawBuffer0 != LOCAL_GL_BACK);
if (changeDrawBuffers) {
const GLenum back = LOCAL_GL_BACK;
gl->fDrawBuffers(1, &back);
}
GLbitfield bufferBits = LOCAL_GL_COLOR_BUFFER_BIT;
if (mOptions.depth)
clearMask |= LOCAL_GL_DEPTH_BUFFER_BIT;
bufferBits |= LOCAL_GL_DEPTH_BUFFER_BIT;
if (mOptions.stencil)
clearMask |= LOCAL_GL_STENCIL_BUFFER_BIT;
bufferBits |= LOCAL_GL_STENCIL_BUFFER_BIT;
colorAttachmentsMask[0] = true;
ForceClearFramebufferWithDefaultValues(bufferBits, mNeedsFakeNoAlpha);
ForceClearFramebufferWithDefaultValues(mNeedsFakeNoAlpha, clearMask,
colorAttachmentsMask);
if (changeDrawBuffers) {
gl->fDrawBuffers(1, &mDefaultFB_DrawBuffer0);
}
}
void
WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfield mask,
const bool colorAttachmentsMask[kMaxColorAttachments])
WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield clearBits,
bool fakeNoAlpha)
{
MakeContextCurrent();
bool initializeColorBuffer = 0 != (mask & LOCAL_GL_COLOR_BUFFER_BIT);
bool initializeDepthBuffer = 0 != (mask & LOCAL_GL_DEPTH_BUFFER_BIT);
bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT);
bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers);
bool shouldOverrideDrawBuffers = false;
bool usingDefaultFrameBuffer = !mBoundDrawFramebuffer;
GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments];
const bool initializeColorBuffer = bool(clearBits & LOCAL_GL_COLOR_BUFFER_BIT);
const bool initializeDepthBuffer = bool(clearBits & LOCAL_GL_DEPTH_BUFFER_BIT);
const bool initializeStencilBuffer = bool(clearBits & LOCAL_GL_STENCIL_BUFFER_BIT);
// Fun GL fact: No need to worry about the viewport here, glViewport is just
// setting up a coordinates transformation, it doesn't affect glClear at all.
@ -1339,38 +1318,6 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
gl->fDisable(LOCAL_GL_SCISSOR_TEST);
if (initializeColorBuffer) {
if (drawBuffersIsEnabled) {
GLenum drawBuffersCommand[WebGLContext::kMaxColorAttachments] = { LOCAL_GL_NONE };
for (int32_t i = 0; i < mGLMaxDrawBuffers; i++) {
GLint temp;
gl->fGetIntegerv(LOCAL_GL_DRAW_BUFFER0 + i, &temp);
currentDrawBuffers[i] = temp;
if (colorAttachmentsMask[i]) {
drawBuffersCommand[i] = LOCAL_GL_COLOR_ATTACHMENT0 + i;
}
if (currentDrawBuffers[i] != drawBuffersCommand[i])
shouldOverrideDrawBuffers = true;
}
// When clearing the default framebuffer, we must be clearing only
// GL_BACK, and nothing else, or else gl may return an error. We will
// only use the first element of currentDrawBuffers in this case.
if (usingDefaultFrameBuffer) {
gl->Screen()->SetDrawBuffer(LOCAL_GL_BACK);
if (currentDrawBuffers[0] == LOCAL_GL_COLOR_ATTACHMENT0)
currentDrawBuffers[0] = LOCAL_GL_BACK;
shouldOverrideDrawBuffers = false;
}
// calling draw buffers can cause resolves on adreno drivers so
// we try to avoid calling it
if (shouldOverrideDrawBuffers)
gl->fDrawBuffers(mGLMaxDrawBuffers, drawBuffersCommand);
}
gl->fColorMask(1, 1, 1, 1);
if (fakeNoAlpha) {
@ -1398,7 +1345,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
}
// Do the clear!
gl->fClear(mask);
gl->fClear(clearBits);
// And reset!
if (mScissorTestEnabled)
@ -1410,15 +1357,6 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfiel
// Restore GL state after clearing.
if (initializeColorBuffer) {
if (drawBuffersIsEnabled) {
if (usingDefaultFrameBuffer) {
gl->Screen()->SetDrawBuffer(currentDrawBuffers[0]);
} else if (shouldOverrideDrawBuffers) {
gl->fDrawBuffers(mGLMaxDrawBuffers, currentDrawBuffers);
}
}
gl->fColorMask(mColorWriteMask[0],
mColorWriteMask[1],
mColorWriteMask[2],
@ -1818,17 +1756,30 @@ WebGLContext::DidRefresh()
}
}
size_t
RoundUpToMultipleOf(size_t value, size_t multiple)
bool
WebGLContext::ValidateCurFBForRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height)
{
size_t overshoot = value + multiple - 1;
return overshoot - (overshoot % multiple);
}
if (!mBoundReadFramebuffer) {
ClearBackbufferIfNeeded();
CheckedUint32
RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y)
{
return ((x + y - 1) / y) * y;
// 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);
}
////////////////////////////////////////////////////////////////////////////////
@ -1869,6 +1820,215 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
}
}
////////////////////////////////////////
ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
: ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
, mWebGL(webgl)
{
if (mWebGL->mPixelStore_UnpackAlignment != 4) mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
if (mWebGL->IsWebGL2()) {
if (mWebGL->mPixelStore_UnpackRowLength != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , 0);
if (mWebGL->mPixelStore_UnpackImageHeight != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, 0);
if (mWebGL->mPixelStore_UnpackSkipPixels != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_PIXELS , 0);
if (mWebGL->mPixelStore_UnpackSkipRows != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_ROWS , 0);
if (mWebGL->mPixelStore_UnpackSkipImages != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_SKIP_IMAGES , 0);
if (mWebGL->mBoundPixelUnpackBuffer) mGL->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
}
}
void
ScopedUnpackReset::UnwrapImpl()
{
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);
}
}
////////////////////////////////////////
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 webgl::PackingInfo packing = driverUnpackInfo->ToPacking();
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);
error = DoTexImage(gl, target, level, driverUnpackInfo, width, height, depth,
zeros.get());
} else {
error = DoTexSubImage(gl, target, level, xOffset, yOffset, zOffset, width, height,
depth, packing, zeros.get());
}
if (error)
return false;
return true;
}
////////////////////////////////////////////////////////////////////////////////
CheckedUint32
WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
uint32_t depth, uint8_t bytesPerPixel)
{
if (!width || !height || !depth)
return 0;
////////////////
const auto& maybeRowLength = mPixelStore_UnpackRowLength;
const auto& maybeImageHeight = mPixelStore_UnpackImageHeight;
const auto usedPixelsPerRow = CheckedUint32(mPixelStore_UnpackSkipPixels) + width;
const auto stridePixelsPerRow = (maybeRowLength ? CheckedUint32(maybeRowLength)
: usedPixelsPerRow);
const auto usedRowsPerImage = CheckedUint32(mPixelStore_UnpackSkipRows) + height;
const auto strideRowsPerImage = (maybeImageHeight ? CheckedUint32(maybeImageHeight)
: usedRowsPerImage);
const uint32_t skipImages = (isFunc3D ? mPixelStore_UnpackSkipImages
: 0);
const CheckedUint32 usedImages = CheckedUint32(skipImages) + depth;
////////////////
CheckedUint32 strideBytesPerRow = bytesPerPixel * stridePixelsPerRow;
strideBytesPerRow = RoundUpToMultipleOf(strideBytesPerRow,
mPixelStore_UnpackAlignment);
const CheckedUint32 strideBytesPerImage = strideBytesPerRow * strideRowsPerImage;
////////////////
CheckedUint32 usedBytesPerRow = bytesPerPixel * usedPixelsPerRow;
// Don't round this to the alignment, since alignment here is really just used for
// establishing stride, particularly in WebGL 1, where you can't set ROW_LENGTH.
CheckedUint32 totalBytes = strideBytesPerImage * (usedImages - 1);
totalBytes += strideBytesPerRow * (usedRowsPerImage - 1);
totalBytes += usedBytesPerRow;
return totalBytes;
}
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
@ -1882,6 +2042,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mBound2DTextures,
mBoundCubeMapTextures,
mBound3DTextures,
mBound2DArrayTextures,
mBoundSamplers,
mBoundArrayBuffer,
mBoundCopyReadBuffer,

View File

@ -26,6 +26,8 @@
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "SurfaceTypes.h"
#include "ScopedGLHelpers.h"
#include "TexUnpackBlob.h"
#ifdef XP_MACOSX
#include "ForceDiscreteGPUHelperCGL.h"
@ -36,6 +38,7 @@
#include "WebGLFormats.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
#include "WebGLTexture.h"
// Generated
#include "nsIDOMEventListener.h"
@ -67,6 +70,12 @@ class nsIDocShell;
#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
*/
@ -78,7 +87,9 @@ class nsIDocShell;
#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241
namespace mozilla {
class ScopedCopyTexImageSource;
class ScopedResolveTexturesForDraw;
class ScopedUnpackReset;
class WebGLActiveInfo;
class WebGLContextLossHandler;
class WebGLBuffer;
@ -111,6 +122,7 @@ class SourceSurface;
namespace webgl {
struct LinkedProgramInfo;
class ShaderValidator;
class TexUnpackBlob;
} // namespace webgl
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
@ -200,6 +212,9 @@ class WebGLContext
UNMASKED_RENDERER_WEBGL = 0x9246
};
static const uint32_t kMinMaxColorAttachments;
static const uint32_t kMinMaxDrawBuffers;
public:
WebGLContext();
@ -300,6 +315,8 @@ public:
return mBoundCubeMapTextures[mActiveTexture];
case LOCAL_GL_TEXTURE_3D:
return mBound3DTextures[mActiveTexture];
case LOCAL_GL_TEXTURE_2D_ARRAY:
return mBound2DArrayTextures[mActiveTexture];
default:
MOZ_CRASH("bad target");
}
@ -340,18 +357,11 @@ public:
// all context resources to be lost.
uint32_t Generation() { return mGeneration.value(); }
// Returns null if the current bound FB is not likely complete.
const WebGLRectangleObject* CurValidDrawFBRectObject() const;
const WebGLRectangleObject* CurValidReadFBRectObject() const;
static const size_t kMaxColorAttachments = 16;
// This is similar to GLContext::ClearSafely, but tries to minimize the
// amount of work it does.
// It only clears the buffers we specify, and can reset its state without
// first having to query anything, as WebGL knows its state at all times.
void ForceClearFramebufferWithDefaultValues(bool fakeNoAlpha, GLbitfield mask,
const bool colorAttachmentsMask[kMaxColorAttachments]);
void ForceClearFramebufferWithDefaultValues(GLbitfield bufferBits, bool fakeNoAlpha);
// Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'.
void ClearScreen();
@ -434,8 +444,9 @@ public:
GLint level);
// Framebuffer validation
bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb,
GLenum attachment, const char* funcName);
bool ValidateFramebufferAttachment(const WebGLFramebuffer* fb, GLenum attachment,
const char* funcName,
bool badColorAttachmentIsInvalidOp = false);
void FrontFace(GLenum mode);
already_AddRefed<WebGLActiveInfo> GetActiveAttrib(WebGLProgram* prog,
@ -527,6 +538,11 @@ public:
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,
@ -889,46 +905,62 @@ public:
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:
@ -1011,7 +1043,7 @@ private:
GLsizei primcount, const char* info,
GLuint* out_upperBound);
bool DrawInstanced_check(const char* info);
void Draw_cleanup();
void Draw_cleanup(const char* funcName);
void VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
@ -1028,24 +1060,10 @@ private:
// -----------------------------------------------------------------------------
// PROTECTED
protected:
void SetFakeBlackStatus(WebGLContextFakeBlackStatus x) {
mFakeBlackStatus = x;
}
// Returns the current fake-black-status, except if it was Unknown,
// in which case this function resolves it first, so it never returns Unknown.
WebGLContextFakeBlackStatus ResolvedFakeBlackStatus();
void BindFakeBlackTextures();
void UnbindFakeBlackTextures();
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;
@ -1076,6 +1094,7 @@ protected:
void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
GLuint mActiveTexture;
GLenum mDefaultFB_DrawBuffer0;
// glGetError sources:
bool mEmitContextLostErrorOnce;
@ -1090,23 +1109,36 @@ protected:
// 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;
// What is supported:
uint32_t mGLMaxColorAttachments;
uint32_t mGLMaxDrawBuffers;
// What we're allowing:
uint32_t mImplMaxColorAttachments;
uint32_t mImplMaxDrawBuffers;
public:
GLenum LastColorAttachmentEnum() const {
return LOCAL_GL_COLOR_ATTACHMENT0 + mImplMaxColorAttachments - 1;
}
protected:
// 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 {
@ -1117,8 +1149,7 @@ public:
return mGLMaxTextureUnits;
}
bool IsFormatValidForFB(GLenum sizedFormat) const;
bool IsFormatValidForFB(TexInternalFormat format) const;
protected:
// Represents current status of the context with respect to context loss.
@ -1155,9 +1186,11 @@ protected:
WebGLExtensionBase* EnableSupportedExtension(JSContext* js,
WebGLExtensionID ext);
public:
// returns true if the extension has been enabled by calling getExtension.
bool IsExtensionEnabled(WebGLExtensionID ext) const;
protected:
// returns true if the extension is supported for this JSContext (this decides what getSupportedExtensions exposes)
bool IsExtensionSupported(JSContext* cx, WebGLExtensionID ext) const;
bool IsExtensionSupported(WebGLExtensionID ext) const;
@ -1207,8 +1240,8 @@ protected:
WebGLintptr byteOffset, const char* info);
bool ValidateStencilParamsForDrawCall();
bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func,
WebGLTexDimensions dims);
bool ValidateCopyTexImage(TexInternalFormat srcFormat, TexInternalFormat dstformat,
WebGLTexImageFunc func, WebGLTexDimensions dims);
bool ValidateSamplerParameterName(GLenum pname, const char* info);
bool ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info);
@ -1255,6 +1288,10 @@ protected:
WebGLProgram* program,
const char* funcName);
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();
@ -1268,31 +1305,23 @@ protected:
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;
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);
gfx::DrawTarget* idealDrawTarget = nullptr; // Don't care for now.
return nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
}
template<class ElementType>
nsLayoutUtils::SurfaceFromElementResult
SurfaceFromElement(ElementType& element) {
return SurfaceFromElement(&element);
}
nsresult
SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
RefPtr<gfx::DataSourceSurface>& imageOut,
WebGLTexelFormat* format);
protected:
// Returns false if `object` is null or not valid.
template<class ObjectType>
bool ValidateObject(const char* info, ObjectType* object);
@ -1331,30 +1360,22 @@ private:
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<WebGLTexture> > mBound2DArrayTextures;
nsTArray<WebGLRefPtr<WebGLSampler> > mBoundSamplers;
void ResolveTexturesForDraw() const;
@ -1362,10 +1383,6 @@ protected:
WebGLRefPtr<WebGLProgram> mCurrentProgram;
RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
GLenum LastColorAttachment() const {
return LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments - 1;
}
bool ValidateFramebufferTarget(GLenum target, const char* const info);
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
@ -1391,34 +1408,50 @@ protected:
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;
WebGLContextFakeBlackStatus mFakeBlackStatus;
CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
uint32_t depth, uint8_t bytesPerPixel);
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;
////////////////////////////////////
class FakeBlackTexture {
gl::GLContext* const mGL;
GLuint mGLName;
public:
FakeBlackTexture(gl::GLContext* gl, TexTarget target, GLenum format);
gl::GLContext* const mGL;
const GLuint mGLName;
FakeBlackTexture(gl::GLContext* gl, TexTarget target, FakeBlackType type);
~FakeBlackTexture();
GLuint GLName() const { return mGLName; }
};
UniquePtr<FakeBlackTexture> mBlackOpaqueTexture2D;
UniquePtr<FakeBlackTexture> mBlackOpaqueTextureCubeMap;
UniquePtr<FakeBlackTexture> mBlackTransparentTexture2D;
UniquePtr<FakeBlackTexture> mBlackTransparentTextureCubeMap;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_0000;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_0001;
UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_0000;
UniquePtr<FakeBlackTexture> mFakeBlack_CubeMap_0001;
UniquePtr<FakeBlackTexture> mFakeBlack_3D_0000;
UniquePtr<FakeBlackTexture> mFakeBlack_3D_0001;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0000;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0001;
void
BindFakeBlackTexturesHelper(GLenum target,
const nsTArray<WebGLRefPtr<WebGLTexture> >& boundTexturesArray,
UniquePtr<FakeBlackTexture>& opaqueTextureScopedPtr,
UniquePtr<FakeBlackTexture>& transparentTextureScopedPtr);
void BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack);
////////////////////////////////////
// Generic Vertex Attributes
UniquePtr<GLenum[]> mVertexAttribType;
@ -1534,10 +1567,19 @@ public:
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 ScopedCopyTexImageSource;
friend class ScopedResolveTexturesForDraw;
friend class ScopedUnpackReset;
friend class webgl::TexUnpackBlob;
friend class webgl::TexUnpackBytes;
friend class webgl::TexUnpackSurface;
friend class WebGLTexture;
friend class WebGLFBAttachPoint;
friend class WebGLFramebuffer;
friend class WebGLRenderbuffer;
friend class WebGLProgram;
@ -1631,24 +1673,99 @@ WebGLContext::ValidateObject(const char* info, ObjectType* object)
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,
TexTarget* const out_texTarget, WebGLTexture** const out_tex);
ValidateTexTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
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);
class UniqueBuffer
{
// Like UniquePtr<>, but for void* and malloc/calloc/free.
void* mBuffer;
public:
UniqueBuffer()
: mBuffer(nullptr)
{ }
MOZ_IMPLICIT UniqueBuffer(void* buffer)
: mBuffer(buffer)
{ }
~UniqueBuffer() {
free(mBuffer);
}
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

View File

@ -23,13 +23,134 @@ namespace mozilla {
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
////////////////////////////////////////
class ScopedResolveTexturesForDraw
{
struct TexRebindRequest
{
uint32_t texUnit;
WebGLTexture* tex;
};
WebGLContext* const mWebGL;
std::vector<TexRebindRequest> mRebindRequests;
public:
ScopedResolveTexturesForDraw(WebGLContext* webgl, const char* funcName,
bool* const out_error);
~ScopedResolveTexturesForDraw();
};
ScopedResolveTexturesForDraw::ScopedResolveTexturesForDraw(WebGLContext* webgl,
const char* funcName,
bool* const out_error)
: mWebGL(webgl)
{
//typedef nsTArray<WebGLRefPtr<WebGLTexture>> TexturesT;
typedef decltype(WebGLContext::mBound2DTextures) TexturesT;
const auto fnResolveAll = [this, funcName, out_error](const TexturesT& textures)
{
const auto len = textures.Length();
for (uint32_t texUnit = 0; texUnit < len; ++texUnit) {
WebGLTexture* tex = textures[texUnit];
if (!tex)
continue;
FakeBlackType fakeBlack;
*out_error |= !tex->ResolveForDraw(funcName, texUnit, &fakeBlack);
if (fakeBlack == FakeBlackType::None)
continue;
mWebGL->BindFakeBlack(texUnit, tex->Target(), fakeBlack);
mRebindRequests.push_back({texUnit, tex});
}
};
*out_error = false;
fnResolveAll(mWebGL->mBound2DTextures);
fnResolveAll(mWebGL->mBoundCubeMapTextures);
fnResolveAll(mWebGL->mBound3DTextures);
fnResolveAll(mWebGL->mBound2DArrayTextures);
if (*out_error) {
mWebGL->ErrorOutOfMemory("%s: Failed to resolve textures for draw.", funcName);
}
}
ScopedResolveTexturesForDraw::~ScopedResolveTexturesForDraw()
{
if (!mRebindRequests.size())
return;
gl::GLContext* gl = mWebGL->gl;
for (const auto& itr : mRebindRequests) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + itr.texUnit);
gl->fBindTexture(itr.tex->Target().get(), itr.tex->mGLName);
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mWebGL->mActiveTexture);
}
void
WebGLContext::BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack)
{
MOZ_ASSERT(fakeBlack == FakeBlackType::RGBA0000 ||
fakeBlack == FakeBlackType::RGBA0001);
const auto fnGetSlot = [this, target, fakeBlack]() -> UniquePtr<FakeBlackTexture>*
{
switch (fakeBlack) {
case FakeBlackType::RGBA0000:
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D : return &mFakeBlack_2D_0000;
case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0000;
case LOCAL_GL_TEXTURE_3D : return &mFakeBlack_3D_0000;
case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0000;
default: return nullptr;
}
case FakeBlackType::RGBA0001:
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D : return &mFakeBlack_2D_0001;
case LOCAL_GL_TEXTURE_CUBE_MAP: return &mFakeBlack_CubeMap_0001;
case LOCAL_GL_TEXTURE_3D : return &mFakeBlack_3D_0001;
case LOCAL_GL_TEXTURE_2D_ARRAY: return &mFakeBlack_2D_Array_0001;
default: return nullptr;
}
default:
return nullptr;
}
};
UniquePtr<FakeBlackTexture>* slot = fnGetSlot();
if (!slot) {
MOZ_CRASH("fnGetSlot failed.");
}
UniquePtr<FakeBlackTexture>& fakeBlackTex = *slot;
if (!fakeBlackTex) {
fakeBlackTex.reset(new FakeBlackTexture(gl, target, fakeBlack));
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + texUnit);
gl->fBindTexture(target.get(), fakeBlackTex->mGLName);
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
}
////////////////////////////////////////
bool
WebGLContext::DrawInstanced_check(const char* info)
{
if ((IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) &&
!mBufferFetchingHasPerVertex)
{
MOZ_ASSERT(IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
if (!mBufferFetchingHasPerVertex) {
/* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
* If all of the enabled vertex attribute arrays that are bound to active
* generic attributes in the program have a non-zero divisor, the draw
@ -111,25 +232,25 @@ WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
BindFakeBlackTextures();
return true;
}
void
WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
{
const char funcName[] = "drawArrays";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArrays: mode"))
if (!ValidateDrawModeEnum(mode, funcName))
return;
if (!DrawArrays_check(first, count, 1, "drawArrays"))
bool error;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
if (!DrawArrays_check(first, count, 1, funcName))
return;
RunContextLossTimer();
@ -139,19 +260,28 @@ WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
gl->fDrawArrays(mode, first, count);
}
Draw_cleanup();
Draw_cleanup(funcName);
}
void
WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
const char funcName[] = "drawArraysInstanced";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawArraysInstanced: mode"))
if (!ValidateDrawModeEnum(mode, funcName))
return;
if (!DrawArrays_check(first, count, primcount, "drawArraysInstanced"))
bool error;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
if (!DrawArrays_check(first, count, primcount, funcName))
return;
if (!DrawInstanced_check(funcName))
return;
RunContextLossTimer();
@ -161,7 +291,7 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsiz
gl->fDrawArraysInstanced(mode, first, count, primcount);
}
Draw_cleanup();
Draw_cleanup(funcName);
}
bool
@ -184,39 +314,40 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
}
// If count is 0, there's nothing to do.
if (count == 0 || primcount == 0) {
if (count == 0 || primcount == 0)
return false;
uint8_t bytesPerElem = 0;
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
bytesPerElem = 1;
break;
case LOCAL_GL_UNSIGNED_SHORT:
bytesPerElem = 2;
break;
case LOCAL_GL_UNSIGNED_INT:
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
bytesPerElem = 4;
}
break;
}
if (!bytesPerElem) {
ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
return false;
}
CheckedUint32 checked_byteCount;
GLsizei first = 0;
if (type == LOCAL_GL_UNSIGNED_SHORT) {
checked_byteCount = 2 * CheckedUint32(count);
if (byteOffset % 2 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
return false;
}
first = byteOffset / 2;
}
else if (type == LOCAL_GL_UNSIGNED_BYTE) {
checked_byteCount = count;
first = byteOffset;
}
else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
checked_byteCount = 4 * CheckedUint32(count);
if (byteOffset % 4 != 0) {
ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
return false;
}
first = byteOffset / 4;
}
else {
ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
if (byteOffset % bytesPerElem != 0) {
ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
info);
return false;
}
const GLsizei first = byteOffset / bytesPerElem;
const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);
if (!checked_byteCount.isValid()) {
ErrorInvalidValue("%s: overflow in byteCount", info);
return false;
@ -292,12 +423,6 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type,
return false;
}
if (!DrawInstanced_check(info)) {
return false;
}
BindFakeBlackTextures();
return true;
}
@ -305,18 +430,21 @@ void
WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset)
{
const char funcName[] = "drawElements";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElements: mode"))
if (!ValidateDrawModeEnum(mode, funcName))
return;
bool error;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
GLuint upperBound = 0;
if (!DrawElements_check(count, type, byteOffset, 1, "drawElements",
&upperBound))
{
if (!DrawElements_check(count, type, byteOffset, 1, funcName, &upperBound))
return;
}
RunContextLossTimer();
@ -332,25 +460,31 @@ WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
}
}
Draw_cleanup();
Draw_cleanup(funcName);
}
void
WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
WebGLintptr byteOffset, GLsizei primcount)
{
const char funcName[] = "drawElementsInstanced";
if (IsContextLost())
return;
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
if (!ValidateDrawModeEnum(mode, funcName))
return;
bool error;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
GLuint upperBound = 0;
if (!DrawElements_check(count, type, byteOffset, primcount,
"drawElementsInstanced", &upperBound))
{
if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
return;
if (!DrawInstanced_check(funcName))
return;
}
RunContextLossTimer();
@ -361,13 +495,12 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
primcount);
}
Draw_cleanup();
Draw_cleanup(funcName);
}
void WebGLContext::Draw_cleanup()
void WebGLContext::Draw_cleanup(const char* funcName)
{
UndoFakeVertexAttrib0();
UnbindFakeBlackTextures();
if (!mBoundDrawFramebuffer) {
Invalidate();
@ -386,17 +519,29 @@ void WebGLContext::Draw_cleanup()
}
}
// Let's check the viewport
const WebGLRectangleObject* rect = CurValidDrawFBRectObject();
if (rect) {
if (mViewportWidth > rect->Width() ||
mViewportHeight > rect->Height())
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
"(This warning will only be given once)");
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
// Let's check for a really common error: Viewport is larger than the actual
// destination framebuffer.
uint32_t destWidth = mViewportWidth;
uint32_t destHeight = mViewportHeight;
if (mBoundDrawFramebuffer) {
const auto& fba = mBoundDrawFramebuffer->ColorAttachment(0);
if (fba.IsDefined()) {
fba.Size(&destWidth, &destHeight);
}
} else {
destWidth = mWidth;
destHeight = mHeight;
}
if (mViewportWidth > int32_t(destWidth) ||
mViewportHeight > int32_t(destHeight))
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("%s: Drawing to a destination rect smaller than the viewport"
" rect. (This warning will only be given once)",
funcName);
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
}
}
@ -646,145 +791,67 @@ WebGLContext::UndoFakeVertexAttrib0()
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
}
WebGLContextFakeBlackStatus
WebGLContext::ResolvedFakeBlackStatus()
static GLuint
CreateGLTexture(gl::GLContext* gl)
{
// handle this case first, it's the generic case
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
return mFakeBlackStatus;
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
return mFakeBlackStatus;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
{
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
return mFakeBlackStatus;
}
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
return mFakeBlackStatus;
MOZ_ASSERT(gl->IsCurrent());
GLuint ret = 0;
gl->fGenTextures(1, &ret);
return ret;
}
void
WebGLContext::BindFakeBlackTexturesHelper(
GLenum target,
const nsTArray<WebGLRefPtr<WebGLTexture> > & boundTexturesArray,
UniquePtr<FakeBlackTexture> & opaqueTextureScopedPtr,
UniquePtr<FakeBlackTexture> & transparentTextureScopedPtr)
{
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (!boundTexturesArray[i]) {
continue;
}
WebGLTextureFakeBlackStatus s = boundTexturesArray[i]->ResolvedFakeBlackStatus();
MOZ_ASSERT(s != WebGLTextureFakeBlackStatus::Unknown);
if (MOZ_LIKELY(s == WebGLTextureFakeBlackStatus::NotNeeded)) {
continue;
}
bool alpha = s == WebGLTextureFakeBlackStatus::UninitializedImageData &&
FormatHasAlpha(boundTexturesArray[i]->ImageInfoBase().EffectiveInternalFormat());
UniquePtr<FakeBlackTexture>&
blackTexturePtr = alpha
? transparentTextureScopedPtr
: opaqueTextureScopedPtr;
if (!blackTexturePtr) {
GLenum format = alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
blackTexturePtr = MakeUnique<FakeBlackTexture>(gl, target, format);
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(target,
blackTexturePtr->GLName());
}
}
void
WebGLContext::BindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D,
mBound2DTextures,
mBlackOpaqueTexture2D,
mBlackTransparentTexture2D);
BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP,
mBoundCubeMapTextures,
mBlackOpaqueTextureCubeMap,
mBlackTransparentTextureCubeMap);
}
void
WebGLContext::UnbindFakeBlackTextures()
{
// this is the generic case: try to return early
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->mGLName);
}
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->mGLName);
}
}
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
}
WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target, GLenum format)
WebGLContext::FakeBlackTexture::FakeBlackTexture(gl::GLContext* gl, TexTarget target,
FakeBlackType type)
: mGL(gl)
, mGLName(0)
, mGLName(CreateGLTexture(gl))
{
MOZ_ASSERT(format == LOCAL_GL_RGB || format == LOCAL_GL_RGBA);
GLenum texFormat;
switch (type) {
case FakeBlackType::RGBA0000:
texFormat = LOCAL_GL_RGBA;
break;
mGL->MakeCurrent();
GLuint formerBinding = 0;
gl->GetUIntegerv(target == LOCAL_GL_TEXTURE_2D
? LOCAL_GL_TEXTURE_BINDING_2D
: LOCAL_GL_TEXTURE_BINDING_CUBE_MAP,
&formerBinding);
gl->fGenTextures(1, &mGLName);
gl->fBindTexture(target.get(), mGLName);
case FakeBlackType::RGBA0001:
texFormat = LOCAL_GL_RGB;
break;
// we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
// to minimize the risk of running into a driver bug in texImage2D, as it is
// a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
// that texImage2D expects.
UniquePtr<uint8_t> zeros((uint8_t*)moz_xcalloc(1, 16));
if (target == LOCAL_GL_TEXTURE_2D) {
gl->fTexImage2D(target.get(), 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
} else {
for (GLuint i = 0; i < 6; ++i) {
gl->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, format, 1, 1,
0, format, LOCAL_GL_UNSIGNED_BYTE, zeros.get());
}
}
default:
MOZ_CRASH("bad type");
}
gl->fBindTexture(target.get(), formerBinding);
gl::ScopedBindTexture scopedBind(mGL, mGLName, target.get());
mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
mGL->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
// We allocate our zeros on the heap, and we overallocate (16 bytes instead of 4) to
// minimize the risk of running into a driver bug in texImage2D, as it is a bit
// unusual maybe to create 1x1 textures, and the stack may not have the alignment that
// TexImage2D expects.
const webgl::DriverUnpackInfo dui = {texFormat, texFormat, LOCAL_GL_UNSIGNED_BYTE};
UniqueBuffer zeros = moz_xcalloc(1, 16); // Infallible allocation.
if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
for (int i = 0; i < 6; ++i) {
const TexImageTarget curTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
const GLenum error = DoTexImage(mGL, curTarget.get(), 0, &dui, 1, 1, 1,
zeros.get());
if (error)
MOZ_CRASH("Unexpected error during FakeBlack creation.");
}
} else {
const GLenum error = DoTexImage(mGL, target.get(), 0, &dui, 1, 1, 1,
zeros.get());
if (error)
MOZ_CRASH("Unexpected error during FakeBlack creation.");
}
}
WebGLContext::FakeBlackTexture::~FakeBlackTexture()
{
if (mGL) {
mGL->MakeCurrent();
mGL->fDeleteTextures(1, &mGLName);
}
mGL->MakeCurrent();
mGL->fDeleteTextures(1, &mGLName);
}
} // namespace mozilla

View File

@ -106,46 +106,20 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
if (mDisableExtensions)
return false;
// In alphabetical order
// Extensions for both WebGL 1 and 2.
switch (ext) {
// ANGLE_
case WebGLExtensionID::ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
// In alphabetical order
// EXT_
case WebGLExtensionID::EXT_blend_minmax:
return WebGLExtensionBlendMinMax::IsSupported(this);
case WebGLExtensionID::EXT_color_buffer_half_float:
return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
case WebGLExtensionID::EXT_frag_depth:
return WebGLExtensionFragDepth::IsSupported(this);
case WebGLExtensionID::EXT_shader_texture_lod:
return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
case WebGLExtensionID::EXT_sRGB:
return WebGLExtensionSRGB::IsSupported(this);
case WebGLExtensionID::EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
// OES_
case WebGLExtensionID::OES_element_index_uint:
return gl->IsSupported(gl::GLFeature::element_index_uint);
case WebGLExtensionID::OES_standard_derivatives:
return gl->IsSupported(gl::GLFeature::standard_derivatives);
case WebGLExtensionID::OES_texture_float:
return gl->IsSupported(gl::GLFeature::texture_float);
case WebGLExtensionID::OES_texture_float_linear:
return gl->IsSupported(gl::GLFeature::texture_float_linear);
case WebGLExtensionID::OES_texture_half_float:
// If we have Feature::texture_half_float, we must not be on ES2
// and need to translate HALF_FLOAT_OES -> HALF_FLOAT. We do that
// right before making the relevant calls.
return gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float) ||
gl->IsSupported(gl::GLFeature::texture_half_float);
case WebGLExtensionID::OES_texture_half_float_linear:
return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
case WebGLExtensionID::OES_vertex_array_object:
return true;
// WEBGL_
case WebGLExtensionID::WEBGL_color_buffer_float:
@ -167,15 +141,6 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
case WebGLExtensionID::WEBGL_debug_renderer_info:
return Preferences::GetBool("webgl.enable-debug-renderer-info", false);
case WebGLExtensionID::WEBGL_depth_texture:
// WEBGL_depth_texture supports DEPTH_STENCIL textures
if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
return false;
return gl->IsSupported(gl::GLFeature::depth_texture) ||
gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
case WebGLExtensionID::WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
case WebGLExtensionID::WEBGL_lose_context:
// We always support this extension.
return true;
@ -185,14 +150,61 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
break;
}
if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) {
if (!IsWebGL2()) {
// WebGL1-only extensions
switch (ext) {
case WebGLExtensionID::EXT_disjoint_timer_query:
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
// ANGLE_
case WebGLExtensionID::ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
// EXT_
case WebGLExtensionID::EXT_blend_minmax:
return WebGLExtensionBlendMinMax::IsSupported(this);
case WebGLExtensionID::EXT_frag_depth:
return WebGLExtensionFragDepth::IsSupported(this);
case WebGLExtensionID::EXT_shader_texture_lod:
return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
case WebGLExtensionID::EXT_sRGB:
return WebGLExtensionSRGB::IsSupported(this);
// OES_
case WebGLExtensionID::OES_element_index_uint:
return gl->IsSupported(gl::GLFeature::element_index_uint);
case WebGLExtensionID::OES_standard_derivatives:
return gl->IsSupported(gl::GLFeature::standard_derivatives);
case WebGLExtensionID::OES_texture_float:
return WebGLExtensionTextureFloat::IsSupported(this);
case WebGLExtensionID::OES_texture_half_float:
return WebGLExtensionTextureHalfFloat::IsSupported(this);
case WebGLExtensionID::OES_vertex_array_object:
return true;
// WEBGL_
case WebGLExtensionID::WEBGL_depth_texture:
// WEBGL_depth_texture supports DEPTH_STENCIL textures
if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
return false;
return gl->IsSupported(gl::GLFeature::depth_texture) ||
gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
case WebGLExtensionID::WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
if (gfxPrefs::WebGLDraftExtensionsEnabled()) {
switch (ext) {
case WebGLExtensionID::EXT_disjoint_timer_query:
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
default:
// For warnings-as-errors.
break;
}
}
}
return false;

View File

@ -137,71 +137,80 @@ WebGLContext::DepthMask(WebGLboolean b)
void
WebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers)
{
const char funcName[] = "drawBuffers";
if (IsContextLost())
return;
const size_t buffersLength = buffers.Length();
if (!buffersLength) {
return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers must not be empty)");
}
if (!mBoundDrawFramebuffer) {
// OK: we are rendering in the default framebuffer
/* EXT_draw_buffers :
If the GL is bound to the default framebuffer, then <buffersLength> must be 1
and the constant must be BACK or NONE. When draw buffer zero is
BACK, color values are written into the sole buffer for single-
buffered contexts, or into the back buffer for double-buffered
contexts. If DrawBuffersEXT is supplied with a constant other than
BACK and NONE, the error INVALID_OPERATION is generated.
*/
if (buffersLength != 1) {
return ErrorInvalidValue("drawBuffers: invalid <buffers> (main framebuffer: buffers.length must be 1)");
}
if (buffers[0] == LOCAL_GL_NONE || buffers[0] == LOCAL_GL_BACK) {
gl->Screen()->SetDrawBuffer(buffers[0]);
// GLES 3.0.4 p186:
// "If the GL is bound to the default framebuffer, then `n` must be 1 and the
// constant must be BACK or NONE. [...] If DrawBuffers is supplied with a
// constant other than BACK and NONE, or with a value of `n` other than 1, the
// error INVALID_OPERATION is generated."
if (buffers.Length() != 1) {
ErrorInvalidOperation("%s: For the default framebuffer, `buffers` must have a"
" length of 1.",
funcName);
return;
}
return ErrorInvalidOperation("drawBuffers: invalid operation (main framebuffer: buffers[0] must be GL_NONE or GL_BACK)");
switch (buffers[0]) {
case LOCAL_GL_NONE:
case LOCAL_GL_BACK:
break;
default:
ErrorInvalidOperation("%s: For the default framebuffer, `buffers[0]` must be"
" BACK or NONE.",
funcName);
return;
}
mDefaultFB_DrawBuffer0 = buffers[0];
gl->Screen()->SetDrawBuffer(buffers[0]);
return;
}
// OK: we are rendering in a framebuffer object
// Framebuffer object (not default framebuffer)
if (buffersLength > size_t(mGLMaxDrawBuffers)) {
/* EXT_draw_buffers :
The maximum number of draw buffers is implementation-dependent. The
number of draw buffers supported can be queried by calling
GetIntegerv with the symbolic constant MAX_DRAW_BUFFERS_EXT. An
INVALID_VALUE error is generated if <buffersLength> is greater than
MAX_DRAW_BUFFERS_EXT.
*/
return ErrorInvalidValue("drawBuffers: invalid <buffers> (buffers.length > GL_MAX_DRAW_BUFFERS)");
if (buffers.Length() > mImplMaxDrawBuffers) {
// "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
ErrorInvalidValue("%s: `buffers` must have a length <= MAX_DRAW_BUFFERS.",
funcName);
return;
}
for (uint32_t i = 0; i < buffersLength; i++)
{
/* EXT_draw_buffers :
If the GL is bound to a draw framebuffer object, the <i>th buffer listed
in <bufs> must be COLOR_ATTACHMENT<i>_EXT or NONE. Specifying a
buffer out of order, BACK, or COLOR_ATTACHMENT<m>_EXT where <m> is
greater than or equal to the value of MAX_COLOR_ATTACHMENTS_EXT,
will generate the error INVALID_OPERATION.
*/
/* WEBGL_draw_buffers :
The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter.
*/
for (size_t i = 0; i < buffers.Length(); i++) {
// "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
// bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
// BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
// MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
// WEBGL_draw_buffers:
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
// This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
// be larger than MaxColorAttachments.
if (buffers[i] != LOCAL_GL_NONE &&
buffers[i] != GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + i)) {
return ErrorInvalidOperation("drawBuffers: invalid operation (buffers[i] must be GL_NONE or GL_COLOR_ATTACHMENTi)");
buffers[i] != LOCAL_GL_COLOR_ATTACHMENT0 + i)
{
ErrorInvalidOperation("%s: `buffers[i]` must be NONE or COLOR_ATTACHMENTi.",
funcName);
return;
}
}
MakeContextCurrent();
gl->fDrawBuffers(buffersLength, buffers.Elements());
const GLenum* ptr = nullptr;
if (buffers.Length()) {
ptr = buffers.Elements();
}
gl->fDrawBuffers(buffers.Length(), ptr);
const auto end = ptr + buffers.Length();
mBoundDrawFramebuffer->mDrawBuffers.assign(ptr, end);
}
void

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,9 @@ WebGLContext::GetStencilBits(GLint* out_stencilBits)
{
*out_stencilBits = 0;
if (mBoundDrawFramebuffer) {
if (mBoundDrawFramebuffer->HasDepthStencilConflict()) {
if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() &&
mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
{
// Error, we don't know which stencil buffer's bits to use
ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
return false;
@ -142,15 +144,15 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
}
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
return JS::Int32Value(mGLMaxColorAttachments);
return JS::Int32Value(mImplMaxColorAttachments);
} else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
return JS::Int32Value(mGLMaxDrawBuffers);
return JS::Int32Value(mImplMaxDrawBuffers);
} else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mImplMaxDrawBuffers))
{
GLint iv = 0;
gl->fGetIntegerv(pname, &iv);
@ -166,7 +168,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
}
}
if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
WebGLVertexArray* vao =
(mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
@ -174,7 +176,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
}
}
if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
if (pname == LOCAL_GL_TIMESTAMP_EXT) {
GLuint64 iv = 0;
gl->fGetInteger64v(pname, (GLint64*) &iv);
@ -235,7 +237,7 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
}
}
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
GLint i = 0;
gl->fGetIntegerv(pname, &i);
@ -380,13 +382,13 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
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);
@ -449,13 +451,13 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
// 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

View File

@ -52,31 +52,43 @@
namespace mozilla {
static bool
IsValidTexTarget(WebGLContext* webgl, GLenum rawTexTarget, TexTarget* const out)
IsValidTexTarget(WebGLContext* webgl, uint8_t funcDims, GLenum rawTexTarget,
TexTarget* const out)
{
uint8_t targetDims;
switch (rawTexTarget) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP:
targetDims = 2;
break;
case LOCAL_GL_TEXTURE_3D:
case LOCAL_GL_TEXTURE_2D_ARRAY:
if (!webgl->IsWebGL2())
return false;
targetDims = 3;
break;
default:
return false;
}
// Some funcs (like GenerateMipmap) doesn't know the dimension, so don't check it.
if (funcDims && targetDims != funcDims)
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:
@ -85,31 +97,38 @@ IsValidTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
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:
case LOCAL_GL_TEXTURE_2D_ARRAY:
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,
TexTarget* const out_texTarget, WebGLTexture** const out_tex)
ValidateTexTarget(WebGLContext* webgl, const char* funcName, uint8_t funcDims,
GLenum rawTexTarget, TexTarget* const out_texTarget,
WebGLTexture** const out_tex)
{
if (webgl->IsContextLost())
return false;
TexTarget texTarget;
if (!IsValidTexTarget(webgl, rawTexTarget, &texTarget)) {
if (!IsValidTexTarget(webgl, funcDims, rawTexTarget, &texTarget)) {
webgl->ErrorInvalidEnum("%s: Invalid texTarget.", funcName);
return false;
}
@ -126,15 +145,15 @@ ValidateTexTarget(WebGLContext* webgl, GLenum rawTexTarget, const char* funcName
}
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;
}
@ -150,7 +169,7 @@ ValidateTexImageTarget(WebGLContext* webgl, GLenum rawTexImageTarget,
return true;
}
bool
/*virtual*/ bool
WebGLContext::IsTexParamValid(GLenum pname) const
{
switch (pname) {
@ -184,32 +203,38 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
// newTex->Target() returns a TexTarget, which will assert on invalid value.
WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
switch (rawTarget) {
case LOCAL_GL_TEXTURE_2D:
currentTexPtr = &mBound2DTextures[mActiveTexture];
break;
case LOCAL_GL_TEXTURE_2D:
currentTexPtr = &mBound2DTextures[mActiveTexture];
break;
case LOCAL_GL_TEXTURE_CUBE_MAP:
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
break;
case LOCAL_GL_TEXTURE_3D:
if (!IsWebGL2())
return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");
case LOCAL_GL_TEXTURE_CUBE_MAP:
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
break;
case LOCAL_GL_TEXTURE_3D:
if (IsWebGL2())
currentTexPtr = &mBound3DTextures[mActiveTexture];
break;
break;
default:
return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
case LOCAL_GL_TEXTURE_2D_ARRAY:
if (IsWebGL2())
currentTexPtr = &mBound2DArrayTextures[mActiveTexture];
break;
}
if (!currentTexPtr) {
ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
return;
}
const TexTarget texTarget(rawTarget);
MakeContextCurrent();
if (newTex && !newTex->BindTexture(texTarget))
return;
if (!newTex) {
if (newTex) {
if (!newTex->BindTexture(texTarget))
return;
} else {
gl->fBindTexture(texTarget.get(), 0);
}
@ -219,9 +244,12 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture* newTex)
void
WebGLContext::GenerateMipmap(GLenum rawTexTarget)
{
const char funcName[] = "generateMipmap";
const uint8_t funcDims = 0;
TexTarget texTarget;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
return;
tex->GenerateMipmap(texTarget);
@ -230,9 +258,12 @@ WebGLContext::GenerateMipmap(GLenum rawTexTarget)
JS::Value
WebGLContext::GetTexParameter(GLenum rawTexTarget, GLenum pname)
{
const char funcName[] = "getTexParameter";
const uint8_t funcDims = 0;
TexTarget texTarget;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
return JS::NullValue();
if (!IsTexParamValid(pname)) {
@ -261,9 +292,12 @@ WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, GLint* maybeI
{
MOZ_ASSERT(maybeIntParam || maybeFloatParam);
const char funcName[] = "texParameter";
const uint8_t funcDims = 0;
TexTarget texTarget;
WebGLTexture* tex;
if (!ValidateTexTarget(this, rawTexTarget, "texParameter", &texTarget, &tex))
if (!ValidateTexTarget(this, funcName, funcDims, rawTexTarget, &texTarget, &tex))
return;
tex->TexParameter(texTarget, pname, maybeIntParam, maybeFloatParam);
@ -274,140 +308,232 @@ WebGLContext::TexParameter_base(GLenum rawTexTarget, GLenum pname, GLint* maybeI
// 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::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
dom::Element* elem, ErrorResult* const out_rv)
WebGLContext::TexImage2D(GLenum rawTexImageTarget, GLint level, GLenum internalFormat,
GLenum unpackFormat, GLenum unpackType, dom::Element* elem,
ErrorResult* const out_error)
{
TexImageTarget texImageTarget;
const char funcName[] = "texImage2D";
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,
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;
}
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;
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& out_rv)
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
dom::ImageData* imageData, 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;
}
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, imageData);
}
void
WebGLContext::TexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOffset,
GLint yOffset, GLenum unpackFormat, GLenum unpackType,
dom::Element* elem, ErrorResult* const out_error)
{
const char funcName[] = "texSubImage2D";
const uint8_t funcDims = 2;
//////////////////////////////////////////////////////////////////////////////////////////
TexImageTarget target;
WebGLTexture* tex;
if (!ValidateTexImageTarget(this, funcName, funcDims, rawTexImageTarget, &target,
&tex))
{
return;
}
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
@ -415,55 +541,21 @@ WebGLContext::CopyTexSubImage2D(GLenum rawTexImageTarget, GLint level, GLint xOf
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);
}
const GLint zOffset = 0;
//////////////////////////////////////////////////////////////////////////////////////////
// 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;
}
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

View File

@ -27,38 +27,10 @@
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;
}
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:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@ -66,10 +38,9 @@ TexImageTargetToTexTarget(TexImageTarget texImageTarget)
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
return LOCAL_GL_TEXTURE_CUBE_MAP;
default:
MOZ_ASSERT(false, "Bad texture target");
// Should be caught by the constructor for TexTarget
return LOCAL_GL_NONE;
return texImageTarget.get();
}
}
@ -85,387 +56,6 @@ StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
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;
}
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;
}
// 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
};
// Map R to RGB, G to A
static const GLenum kLegacyLuminanceAlphaSwizzle[4] = {
LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_GREEN
};
void
SetLegacyTextureSwizzle(gl::GLContext* gl, GLenum target, GLenum internalformat)
{
if (!gl->IsCoreProfile())
return;
/* 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;
case LOCAL_GL_LUMINANCE:
gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
(GLint*) kLegacyLuminanceSwizzle);
break;
case LOCAL_GL_LUMINANCE_ALPHA:
gl->fTexParameteriv(target, LOCAL_GL_TEXTURE_SWIZZLE_RGBA,
(GLint*) kLegacyLuminanceAlphaSwizzle);
break;
}
}
/**
* 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, ...)
{
@ -520,27 +110,6 @@ WebGLContext::ShouldGenerateWarnings() const
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)
{
@ -1112,7 +681,7 @@ WebGLContext::AssertCachedBindings()
GetAndFlushUnderlyingGLErrors();
if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
}
@ -1168,10 +737,20 @@ WebGLContext::AssertCachedState()
GetAndFlushUnderlyingGLErrors();
// extensions
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
////////////////
AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
if (IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
{
MOZ_ASSERT(mImplMaxColorAttachments == std::min(mGLMaxColorAttachments,
mGLMaxDrawBuffers));
MOZ_ASSERT(mImplMaxDrawBuffers == mGLMaxDrawBuffers);
} else {
MOZ_ASSERT(mImplMaxColorAttachments == 1);
MOZ_ASSERT(mImplMaxDrawBuffers == 1);
}
// Draw state
@ -1234,8 +813,19 @@ WebGLContext::AssertCachedState()
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

View File

@ -15,35 +15,6 @@
namespace mozilla {
bool IsGLDepthFormat(TexInternalFormat webGLFormat);
bool IsGLDepthStencilFormat(TexInternalFormat webGLFormat);
bool FormatHasAlpha(TexInternalFormat webGLFormat);
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 SetLegacyTextureSwizzle(gl::GLContext* gl, GLenum target, GLenum internalformat);
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
@ -61,9 +32,6 @@ 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;
@ -96,7 +64,7 @@ WebGLContext::WebGLObjectAsJSValue(JSContext* cx, const WebGLObjectType* object,
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);

File diff suppressed because it is too large Load Diff

View File

@ -358,8 +358,11 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
if (IsWebGL2() ||
IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
{
return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor);
}
break;
case LOCAL_GL_CURRENT_VERTEX_ATTRIB:

View File

@ -9,32 +9,31 @@
#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->AllowRBFormat(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);
// The extension doesn't actually add RGB32F; only RGBA32F.
FOO(RGBA32F);
#undef FOO
}
WebGLExtensionColorBufferFloat::~WebGLExtensionColorBufferFloat()

View File

@ -9,32 +9,31 @@
#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->AllowRBFormat(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()

View File

@ -7,14 +7,33 @@
#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);
RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
auto& fua = webgl_->mFormatUsage;
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
fua->AllowSizedTexFormat(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()

View File

@ -7,12 +7,31 @@
#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);
RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
auto& fua = webgl_->mFormatUsage;
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
fua->AllowSizedTexFormat(sizedFormat, usage);
webgl_->mCompressedTextureFormats.AppendElement(sizedFormat);
};
#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
fnAdd(FOO(ETC1_RGB8_OES));
#undef FOO
}
WebGLExtensionCompressedTextureETC1::~WebGLExtensionCompressedTextureETC1()

View File

@ -7,15 +7,34 @@
#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);
RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
auto& fua = webgl_->mFormatUsage;
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
fua->AllowSizedTexFormat(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()

View File

@ -7,15 +7,34 @@
#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);
RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
auto& fua = webgl_->mFormatUsage;
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
fua->AllowSizedTexFormat(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()

View File

@ -13,6 +13,29 @@ 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);
usage->isRenderable = true;
const webgl::PackingInfo pi = {unpackFormat, unpackType};
const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
fua->AddTexUnpack(usage, pi, dui);
fua->AllowUnsizedTexFormat(pi, usage);
};
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()

View File

@ -20,26 +20,12 @@ WebGLExtensionDrawBuffers::WebGLExtensionDrawBuffers(WebGLContext* webgl)
{
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
GLint maxColorAttachments = 0;
GLint maxDrawBuffers = 0;
webgl->MakeContextCurrent();
gl::GLContext* gl = webgl->GL();
gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
gl->fGetIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &maxDrawBuffers);
// WEBGL_draw_buffers specifications don't give a maximal value reachable by MAX_COLOR_ATTACHMENTS.
maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::kMaxColorAttachments));
if (webgl->MinCapabilityMode())
maxColorAttachments = std::min(maxColorAttachments, GLint(kMinColorAttachments));
// WEBGL_draw_buffers specifications request MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
maxDrawBuffers = std::min(maxDrawBuffers, GLint(maxColorAttachments));
webgl->mGLMaxColorAttachments = maxColorAttachments;
webgl->mGLMaxDrawBuffers = maxDrawBuffers;
// WEBGL_draw_buffers:
// "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
// equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
webgl->mImplMaxColorAttachments = webgl->mGLMaxColorAttachments;
webgl->mImplMaxDrawBuffers = std::min(webgl->mGLMaxDrawBuffers,
webgl->mImplMaxColorAttachments);
}
WebGLExtensionDrawBuffers::~WebGLExtensionDrawBuffers()
@ -65,20 +51,12 @@ WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* webgl)
if (!gl->IsSupported(gl::GLFeature::draw_buffers))
return false;
GLint supportedColorAttachments = 0;
GLint supportedDrawBuffers = 0;
webgl->MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &supportedColorAttachments);
gl->fGetIntegerv(LOCAL_GL_MAX_COLOR_ATTACHMENTS, &supportedDrawBuffers);
// WEBGL_draw_buffers requires at least 4 color attachments.
if (size_t(supportedColorAttachments) < kMinColorAttachments)
return false;
if (size_t(supportedDrawBuffers) < kMinDrawBuffers)
if (webgl->mGLMaxDrawBuffers < webgl->kMinMaxDrawBuffers ||
webgl->mGLMaxColorAttachments < webgl->kMinMaxColorAttachments)
{
return false;
}
return true;
}

View File

@ -12,9 +12,6 @@
namespace mozilla {
using mozilla::webgl::EffectiveFormat;
WebGLExtensionSRGB::WebGLExtensionSRGB(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
@ -28,20 +25,32 @@ WebGLExtensionSRGB::WebGLExtensionSRGB(WebGLContext* webgl)
gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
}
webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
auto& fua = webgl->mFormatUsage;
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);
}
};
RefPtr<gl::GLContext> gl_ = gl; // Bug 1201275
const auto fnAdd = [&fua, &gl_](webgl::EffectiveFormat effFormat, GLenum format,
GLenum desktopUnpackFormat)
{
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
addFormatIfMissing(EffectiveFormat::SRGB8 , LOCAL_GL_SRGB , LOCAL_GL_UNSIGNED_BYTE, false);
addFormatIfMissing(EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_UNSIGNED_BYTE, true);
webgl::DriverUnpackInfo dui = {format, format, LOCAL_GL_UNSIGNED_BYTE};
const auto pi = dui.ToPacking();
if (!gl_->IsGLES())
dui.unpackFormat = desktopUnpackFormat;
fua->AddTexUnpack(usage, pi, dui);
fua->AllowUnsizedTexFormat(pi, usage);
};
fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB, LOCAL_GL_RGB);
fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_RGBA);
auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
usage->isRenderable = true;
fua->AllowRBFormat(LOCAL_GL_SRGB8_ALPHA8, usage);
}
WebGLExtensionSRGB::~WebGLExtensionSRGB()

View File

@ -4,63 +4,112 @@
#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();
MOZ_ASSERT(IsSupported(webgl));
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);
};
auto& fua = webgl->mFormatUsage;
gl::GLContext* gl = webgl->GL();
// Ensure require formats are initialized.
InitWebGLFormats(authority);
webgl::PackingInfo pi;
webgl::DriverUnpackInfo dui;
const GLint* swizzle = nullptr;
// 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);
const auto fnAdd = [&fua, &pi, &dui, &swizzle](webgl::EffectiveFormat effFormat)
{
auto usage = fua->EditUsage(effFormat);
usage->textureSwizzleRGBA = swizzle;
fua->AddTexUnpack(usage, pi, dui);
fua->AllowUnsizedTexFormat(pi, usage);
};
const bool needSizedInternal = !gl->IsGLES();
MOZ_ASSERT_IF(needSizedInternal, gl->IsSupported(gl::GLFeature::texture_swizzle));
////////////////
pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
dui.internalFormat = LOCAL_GL_RGBA32F;
}
fnAdd(webgl::EffectiveFormat::RGBA32F);
//////
pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
dui.internalFormat = LOCAL_GL_RGB32F;
}
fnAdd(webgl::EffectiveFormat::RGB32F);
//////
pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Luminance32F);
//////
pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_R32F, LOCAL_GL_RED, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Alpha32F);
//////
pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
dui = {pi.format, pi.format, pi.type};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_RG32F, LOCAL_GL_RG, LOCAL_GL_FLOAT};
swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F);
}
WebGLExtensionTextureFloat::~WebGLExtensionTextureFloat()
{
}
bool
WebGLExtensionTextureFloat::IsSupported(const WebGLContext* webgl)
{
gl::GLContext* gl = webgl->GL();
if (!gl->IsSupported(gl::GLFeature::texture_float))
return false;
const bool needSizedInternal = !gl->IsGLES();
const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
if (needSizedInternal && !hasSwizzle)
return false;
return true;
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureFloat, OES_texture_float)
} // namespace mozilla

View File

@ -10,32 +10,16 @@
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
auto& fua = webgl->mFormatUsage;
webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
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()

View File

@ -4,62 +4,119 @@
#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;
gl::GLContext* gl = webgl->GL();
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);
};
webgl::PackingInfo pi;
webgl::DriverUnpackInfo dui;
const GLint* swizzle = nullptr;
InitWebGLFormats(authority);
const auto fnAdd = [&fua, &pi, &dui, &swizzle](webgl::EffectiveFormat effFormat)
{
auto usage = fua->EditUsage(effFormat);
usage->textureSwizzleRGBA = swizzle;
fua->AddTexUnpack(usage, pi, dui);
// 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);
fua->AllowUnsizedTexFormat(pi, usage);
};
const bool needSizedInternal = !gl->IsGLES();
MOZ_ASSERT_IF(needSizedInternal, gl->IsSupported(gl::GLFeature::texture_swizzle));
GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT;
if (!gl->IsSupported(gl::GLFeature::texture_half_float)) {
MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
driverUnpackType = LOCAL_GL_HALF_FLOAT_OES;
}
////////////////
pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
dui.internalFormat = LOCAL_GL_RGBA16F;
}
fnAdd(webgl::EffectiveFormat::RGBA16F);
//////
pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
dui.internalFormat = LOCAL_GL_RGB16F;
}
fnAdd(webgl::EffectiveFormat::RGB16F);
//////
pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Luminance16F);
//////
pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_R16F, LOCAL_GL_RED, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Alpha16F);
//////
pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
dui = {pi.format, pi.format, driverUnpackType};
swizzle = nullptr;
if (needSizedInternal) {
dui = {LOCAL_GL_RG16F, LOCAL_GL_RG, driverUnpackType};
swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
}
fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F);
}
WebGLExtensionTextureHalfFloat::~WebGLExtensionTextureHalfFloat()
{
}
bool
WebGLExtensionTextureHalfFloat::IsSupported(const WebGLContext* webgl)
{
gl::GLContext* gl = webgl->GL();
if (!gl->IsSupported(gl::GLFeature::texture_half_float) &&
!gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float))
{
return false;
}
const bool needSizedInternal = !gl->IsGLES();
const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
if (needSizedInternal && !hasSwizzle)
return false;
return true;
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionTextureHalfFloat, OES_texture_half_float)
} // namespace mozilla

View File

@ -10,32 +10,16 @@
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
auto& fua = webgl->mFormatUsage;
webgl::FormatUsageAuthority* authority = webgl->mFormatUsage.get();
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()

View File

@ -38,7 +38,7 @@ public:
explicit WebGLExtensionBase(WebGLContext* webgl);
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
void MarkLost();
@ -219,6 +219,8 @@ public:
explicit WebGLExtensionTextureFloat(WebGLContext*);
virtual ~WebGLExtensionTextureFloat();
static bool IsSupported(const WebGLContext*);
DECL_WEBGL_EXTENSION_GOOP
};
@ -241,6 +243,8 @@ public:
explicit WebGLExtensionTextureHalfFloat(WebGLContext*);
virtual ~WebGLExtensionTextureHalfFloat();
static bool IsSupported(const WebGLContext*);
DECL_WEBGL_EXTENSION_GOOP
};
@ -289,14 +293,6 @@ public:
static bool IsSupported(const WebGLContext*);
static const size_t kMinColorAttachments = 4;
static const size_t kMinDrawBuffers = 4;
/*
WEBGL_draw_buffers does not give a minal value for GL_MAX_DRAW_BUFFERS. But, we request
for GL_MAX_DRAW_BUFFERS = 4 at least to be able to use all requested color attachments.
See DrawBuffersWEBGL in WebGLExtensionDrawBuffers.cpp inner comments for more informations.
*/
DECL_WEBGL_EXTENSION_GOOP
};

File diff suppressed because it is too large Load Diff

View File

@ -93,10 +93,7 @@ enum class EffectiveFormat : EffectiveFormatValueT {
// 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"
@ -117,10 +114,10 @@ enum class EffectiveFormat : EffectiveFormatValueT {
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,
@ -129,7 +126,14 @@ enum class EffectiveFormat : EffectiveFormatValueT {
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,
@ -157,116 +161,151 @@ enum class UnsizedFormat : uint8_t {
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,
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
Special, // DEPTH24_STENCIL8
};
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 hasColor;
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;
};
//////////////////////////////////////////////////////////////////////////////////////////
struct PackingInfo
{
GLenum format;
GLenum type;
const FormatInfo* GetFormatInfo(EffectiveFormat format);
const FormatInfo* GetInfoByUnpackTuple(GLenum unpackFormat, GLenum unpackType);
const FormatInfo* GetInfoBySizedFormat(GLenum sizedFormat);
////////////////////////////////////////
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;
bool asRenderbuffer;
bool isRenderable;
bool asTexture;
bool isFilterable;
std::set<UnpackTuple> validUnpacks;
struct DriverUnpackInfo
{
GLenum internalFormat;
GLenum unpackFormat;
GLenum unpackType;
bool CanUnpackWith(GLenum unpackFormat, GLenum unpackType) const;
PackingInfo ToPacking() const {
return {unpackFormat, unpackType};
}
};
//////////////////////////////////////////////////////////////////////////////////////////
const FormatInfo* GetFormat(EffectiveFormat format);
uint8_t BytesPerPixel(const PackingInfo& packing);
/*
GLint ComponentSize(const FormatInfo* format, GLenum component);
GLenum ComponentType(const FormatInfo* format);
*/
////////////////////////////////////////
struct FormatUsageInfo
{
const FormatInfo* const format;
bool isRenderable;
bool isFilterable;
std::map<PackingInfo, DriverUnpackInfo> validUnpacks;
const DriverUnpackInfo* idealUnpack;
const GLint* textureSwizzleRGBA;
static const GLint kLuminanceSwizzleRGBA[4];
static const GLint kAlphaSwizzleRGBA[4];
static const GLint kLumAlphaSwizzleRGBA[4];
explicit FormatUsageInfo(const FormatInfo* _format)
: format(_format)
, isRenderable(false)
, isFilterable(false)
, idealUnpack(nullptr)
, textureSwizzleRGBA(nullptr)
{ }
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;
std::set<GLenum> mValidTexInternalFormats;
std::set<GLenum> mValidTexUnpackFormats;
std::set<GLenum> mValidTexUnpackTypes;
public:
static UniquePtr<FormatUsageAuthority> CreateForWebGL1();
static UniquePtr<FormatUsageAuthority> CreateForWebGL2();
static UniquePtr<FormatUsageAuthority> CreateForWebGL1(gl::GLContext* gl);
static UniquePtr<FormatUsageAuthority> CreateForWebGL2(gl::GLContext* gl);
private:
FormatUsageAuthority() { }
public:
void AddFormat(EffectiveFormat format, bool asRenderbuffer, bool isRenderable,
bool asTexture, bool isFilterable);
FormatUsageInfo* EditUsage(EffectiveFormat format);
const FormatUsageInfo* GetUsage(EffectiveFormat format) const;
void AddUnpackOption(GLenum unpackFormat, GLenum unpackType,
EffectiveFormat effectiveFormat);
void AddTexUnpack(FormatUsageInfo* usage, const PackingInfo& pi,
const DriverUnpackInfo& dui);
FormatUsageInfo* GetUsage(EffectiveFormat format);
FormatUsageInfo* GetUsage(const FormatInfo* format)
{
if (!format)
return nullptr;
bool IsInternalFormatEnumValid(GLenum internalFormat) const;
bool AreUnpackEnumsValid(GLenum unpackFormat, GLenum unpackType) const;
return GetUsage(format->effectiveFormat);
}
void AllowRBFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
void AllowSizedTexFormat(GLenum sizedFormat, const FormatUsageInfo* usage);
void AllowUnsizedTexFormat(const PackingInfo& pi, const FormatUsageInfo* usage);
const FormatUsageInfo* GetRBUsage(GLenum sizedFormat) const;
const FormatUsageInfo* GetSizedTexUsage(GLenum sizedFormat) const;
const FormatUsageInfo* GetUnsizedTexUsage(const PackingInfo& pi) const;
};
////////////////////////////////////////////////////////////////////////////////
GLint GetComponentSize(EffectiveFormat format, GLenum component);
GLenum GetComponentType(EffectiveFormat format);
GLenum GetColorEncoding(EffectiveFormat format);
} // namespace webgl
} // namespace mozilla

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,9 @@ class WebGLFramebuffer;
class WebGLRenderbuffer;
class WebGLTexture;
template<typename T>
class PlacementArray;
namespace gl {
class GLContext;
} // namespace gl
@ -29,34 +32,39 @@ class WebGLFBAttachPoint
{
public:
WebGLFramebuffer* const mFB;
const GLenum mAttachmentPoint;
private:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
FBAttachment mAttachmentPoint;
TexImageTarget mTexImageTarget;
GLint mTexImageLayer;
GLint mTexImageLevel;
// PlacementArray needs a default constructor.
template<typename T>
friend class PlacementArray;
WebGLFBAttachPoint()
: mFB(nullptr)
, mAttachmentPoint(0)
{ }
public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, FBAttachment attachmentPoint);
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
void Unlink() {
mRenderbufferPtr = nullptr;
mTexturePtr = nullptr;
}
void Unlink();
bool IsDefined() const;
bool IsDeleteRequested() const;
TexInternalFormat EffectiveInternalFormat() const;
const webgl::FormatUsageInfo* Format() const;
bool HasAlpha() const;
bool IsReadableFloat() const;
void Clear() {
SetRenderbuffer(nullptr);
}
void Clear();
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
@ -88,15 +96,68 @@ public:
bool HasUninitializedImageData() const;
void SetImageDataStatus(WebGLImageDataStatus x);
const WebGLRectangleObject& RectangleObject() const;
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
//const WebGLRectangleObject& RectangleObject() const;
bool HasImage() const;
bool IsComplete() const;
bool IsComplete(WebGLContext* webgl) const;
void FinalizeAttachment(gl::GLContext* gl,
FBAttachment attachmentLoc) const;
void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
JS::Value GetParameter(WebGLContext* context, GLenum pname);
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
GLenum target, GLenum attachment, GLenum pname,
ErrorResult* const out_error);
void OnBackingStoreRespecified() const;
};
template<typename T>
class PlacementArray
{
public:
const size_t mCapacity;
protected:
size_t mSize;
T* const mArray;
public:
explicit PlacementArray(size_t capacity)
: mCapacity(capacity)
, mSize(0)
, mArray((T*)moz_xmalloc(sizeof(T) * capacity))
{ }
~PlacementArray() {
for (auto& cur : *this) {
cur.~T();
}
free(mArray);
}
T* begin() const {
return mArray;
}
T* end() const {
return mArray + mSize;
}
T& operator [](size_t offset) const {
MOZ_ASSERT(offset < mSize);
return mArray[offset];
}
const size_t& Size() const { return mSize; }
template<typename A, typename B>
void AppendNew(A a, B b) {
if (mSize == mCapacity)
MOZ_CRASH("Bad EmplaceAppend.");
// Placement `new`:
new (&(mArray[mSize])) T(a, b);
++mSize;
}
};
class WebGLFramebuffer final
@ -114,7 +175,7 @@ public:
const GLuint mGLName;
private:
mutable GLenum mStatus;
mutable bool mIsKnownFBComplete;
GLenum mReadBufferMode;
@ -123,7 +184,17 @@ private:
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
nsTArray<WebGLFBAttachPoint> mMoreColorAttachments;
PlacementArray<WebGLFBAttachPoint> mMoreColorAttachments;
std::vector<GLenum> mDrawBuffers;
bool IsDrawBuffer(size_t n) const {
if (n < mDrawBuffers.size())
return bool(mDrawBuffers[n]);
return false;
}
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
@ -147,14 +218,11 @@ private:
public:
void Delete();
void FramebufferRenderbuffer(FBAttachment attachment, RBTarget rbtarget,
void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(FBAttachment attachment,
TexImageTarget texImageTarget, WebGLTexture* tex,
GLint level);
void FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, GLint level,
void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
GLint layer);
bool HasDefinedAttachments() const;
@ -163,20 +231,11 @@ public:
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;
}
size_t ColorAttachmentCount() const {
return 1 + mMoreColorAttachments.Length();
}
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
MOZ_ASSERT(colorAttachmentId < ColorAttachmentCount());
MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.Size());
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
: mColorAttachment0;
}
@ -193,16 +252,16 @@ public:
return mDepthStencilAttachment;
}
WebGLFBAttachPoint& GetAttachPoint(FBAttachment attachPointEnum);
protected:
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
public:
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
const WebGLRectangleObject& RectangleObject() const;
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
void FinalizeAttachments() const;
@ -217,19 +276,17 @@ public:
bool CheckAndInitializeAttachments();
bool CheckColorAttachmentNumber(FBAttachment attachment,
const char* funcName) const;
void EnsureColorAttachPoints(size_t colorAttachmentId);
void InvalidateFramebufferStatus() const {
mStatus = 0;
mIsKnownFBComplete = false;
}
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(const char* funcName, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
};
} // namespace mozilla

View File

@ -269,10 +269,8 @@ public:
bool IsCompatibleWithContext(WebGLContext* other);
WebGLContext* Context() const { return mContext; }
protected:
WebGLContext* const mContext;
protected:
const uint32_t mContextGeneration;
};

View File

@ -167,7 +167,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
#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:
@ -232,7 +232,7 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
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);
}
@ -327,8 +327,9 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
}
}
AddActiveInfo(prog->Context(), size, type, isArray, baseUserName, mappedName,
&info->transformFeedbackVaryings, &info->transformFeedbackVaryingsMap);
AddActiveInfo(prog->mContext, size, type, isArray, baseUserName, mappedName,
&info->transformFeedbackVaryings,
&info->transformFeedbackVaryingsMap);
}
}
@ -337,7 +338,6 @@ QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
////////////////////////////////////////////////////////////////////////////////
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
: prog(prog)
, fragDataMap(nullptr)

View File

@ -196,7 +196,7 @@ public:
}
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;

View File

@ -33,7 +33,7 @@ public:
// nsWrapperCache
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
// NS

View File

@ -51,10 +51,10 @@ 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
@ -86,62 +86,21 @@ WebGLRenderbuffer::Delete()
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
@ -172,27 +131,60 @@ RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
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)) {
@ -203,35 +195,42 @@ WebGLRenderbuffer::RenderbufferStorage(GLsizei samples, GLenum internalFormat,
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
height);
if (!mSecondaryRB) {
MOZ_ASSERT(!secondaryFormat);
return;
}
// We can't leave the secondary RB unspecified either, since we should
// handle the case where we attach a non-depth-stencil RB to a
// depth-stencil attachment point, or attach this depth-stencil RB to a
// non-depth-stencil attachment point.
gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
if (secondaryFormat) {
RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
height);
} else {
RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
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);
}
}
mSamples = samples;
mFormat = format;
mWidth = width;
mHeight = height;
mImageDataStatus = WebGLImageDataStatus::UninitializedImageData;
mIsUsingSecondary = bool(secondaryFormat);
InvalidateStatusOfAttachedFBs();
}
void
WebGLRenderbuffer::FramebufferRenderbuffer(FBAttachment attachment) const
WebGLRenderbuffer::FramebufferRenderbuffer(GLenum attachment) const
{
gl::GLContext* gl = mContext->gl;
if (attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment.get(),
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachment,
LOCAL_GL_RENDERBUFFER, mPrimaryRB);
return;
}
GLuint stencilRB = mPrimaryRB;
if (NeedsDepthStencilEmu(mContext->gl, InternalFormatForGL())) {
if (mIsUsingSecondary) {
MOZ_ASSERT(mSecondaryRB);
stencilRB = mSecondaryRB;
}
@ -251,20 +250,13 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
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:
@ -278,6 +270,19 @@ WebGLRenderbuffer::GetRenderbufferParameter(RBTarget target,
gl->fGetRenderbufferParameteriv(target.get(), pname.get(), &i);
return i;
}
case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
{
GLenum ret = 0;
if (mFormat) {
ret = mFormat->format->sizedFormat;
if (!mContext->IsWebGL2() && ret == LOCAL_GL_DEPTH24_STENCIL8) {
ret = LOCAL_GL_DEPTH_STENCIL;
}
}
return ret;
}
}
MOZ_ASSERT(false,

View File

@ -14,6 +14,9 @@
#include "WebGLStrongTypes.h"
namespace mozilla {
namespace webgl {
struct FormatUsageInfo;
}
class WebGLRenderbuffer final
: public nsWrapperCache
@ -29,40 +32,34 @@ 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 (!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;
}
GLenum InternalFormatForGL() const { return mInternalFormatForGL; }
void SetInternalFormatForGL(GLenum internalFormatForGL) {
mInternalFormatForGL = internalFormatForGL;
}
const webgl::FormatUsageInfo* Format() const { return mFormat; }
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 FramebufferRenderbuffer(FBAttachment attachment) const;
void RenderbufferStorage(GLsizei samples, const webgl::FormatUsageInfo* format,
GLsizei width, GLsizei height);
void FramebufferRenderbuffer(GLenum attachment) const;
// Only handles a subset of `pname`s.
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
@ -78,10 +75,10 @@ protected:
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.
@ -93,6 +90,7 @@ protected:
friend class WebGLContext;
friend class WebGLFramebuffer;
friend class WebGLFBAttachPoint;
};
} // namespace mozilla

View File

@ -35,7 +35,7 @@ WebGLSampler::Delete()
WebGLContext*
WebGLSampler::GetParentObject() const
{
return Context();
return mContext;
}
JSObject*

View File

@ -11,6 +11,7 @@
#include "mozilla/MemoryReporting.h"
#include "nsPrintfCString.h"
#include "nsString.h"
#include "prenv.h"
#include "WebGLContext.h"
#include "WebGLObjectModel.h"
#include "WebGLShaderValidator.h"
@ -167,7 +168,7 @@ WebGLShader::ShaderSource(const nsAString& source)
// 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;
@ -179,23 +180,24 @@ WebGLShader::ShaderSource(const nsAString& source)
}
}
// 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;

View File

@ -76,7 +76,7 @@ public:
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;

View File

@ -118,16 +118,16 @@ WebGLContext::CreateShaderValidator(GLenum shaderType) const
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
resources.MaxDrawBuffers = mGLMaxDrawBuffers;
if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
resources.EXT_frag_depth = 1;
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
resources.OES_standard_derivatives = 1;
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
resources.EXT_draw_buffers = 1;
if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
resources.EXT_shader_texture_lod = 1;
// Tell ANGLE to allow highp in frag shaders. (unless disabled)

View File

@ -223,6 +223,7 @@ STRONG_GLENUM_BEGIN(TexImageTarget)
STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_NEGATIVE_Y),
STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_POSITIVE_Z),
STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP_NEGATIVE_Z),
STRONG_GLENUM_VALUE(TEXTURE_2D_ARRAY),
STRONG_GLENUM_END(TexImageTarget)
STRONG_GLENUM_BEGIN(TexTarget)
@ -230,6 +231,7 @@ STRONG_GLENUM_BEGIN(TexTarget)
STRONG_GLENUM_VALUE(TEXTURE_2D),
STRONG_GLENUM_VALUE(TEXTURE_3D),
STRONG_GLENUM_VALUE(TEXTURE_CUBE_MAP),
STRONG_GLENUM_VALUE(TEXTURE_2D_ARRAY),
STRONG_GLENUM_END(TexTarget)
STRONG_GLENUM_BEGIN(TexType)
@ -398,28 +400,6 @@ STRONG_GLENUM_BEGIN(RBTarget)
STRONG_GLENUM_VALUE(RENDERBUFFER),
STRONG_GLENUM_END(RBTarget)
STRONG_GLENUM_BEGIN(FBAttachment)
STRONG_GLENUM_VALUE(DEPTH_STENCIL_ATTACHMENT),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT0),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT1),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT2),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT3),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT4),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT5),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT6),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT7),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT8),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT9),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT10),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT11),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT12),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT13),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT14),
STRONG_GLENUM_VALUE(COLOR_ATTACHMENT15),
STRONG_GLENUM_VALUE(DEPTH_ATTACHMENT),
STRONG_GLENUM_VALUE(STENCIL_ATTACHMENT),
STRONG_GLENUM_END(FBAttachment)
STRONG_GLENUM_BEGIN(FBStatus)
STRONG_GLENUM_VALUE(FRAMEBUFFER_COMPLETE),
STRONG_GLENUM_VALUE(FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
@ -433,6 +413,7 @@ STRONG_GLENUM_END(FBStatus)
STRONG_GLENUM_BEGIN(RBParam)
STRONG_GLENUM_VALUE(RENDERBUFFER_WIDTH),
STRONG_GLENUM_VALUE(RENDERBUFFER_HEIGHT),
STRONG_GLENUM_VALUE(RENDERBUFFER_INTERNAL_FORMAT),
STRONG_GLENUM_VALUE(RENDERBUFFER_RED_SIZE),
STRONG_GLENUM_VALUE(RENDERBUFFER_GREEN_SIZE),
STRONG_GLENUM_VALUE(RENDERBUFFER_BLUE_SIZE),

View File

@ -34,7 +34,7 @@ WebGLSync::Delete()
WebGLContext*
WebGLSync::GetParentObject() const
{
return Context();
return mContext;
}
// -------------------------------------------------------------------------

View File

@ -326,73 +326,73 @@ public:
} // 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.
converter.run(srcFormat, dstFormat, premultiplicationOp);
MOZ_ASSERT(shouldYFlip || srcStride != dstStride,
"Performance trap -- should handle this case earlier to avoid memcpy");
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

View File

@ -38,6 +38,14 @@
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

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@
#define WEBGL_TEXTURE_H_
#include <algorithm>
#include <map>
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
@ -20,6 +21,7 @@
namespace mozilla {
class ErrorResult;
class WebGLContext;
namespace dom {
class Element;
@ -27,18 +29,16 @@ class ImageData;
class ArrayBufferViewOrSharedArrayBufferView;
} // namespace dom
// Zero is not an integer power of two.
inline bool
IsPOTAssumingNonnegative(GLsizei x)
{
MOZ_ASSERT(x >= 0);
return x && (x & (x-1)) == 0;
}
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
@ -46,33 +46,145 @@ class WebGLTexture final
, public WebGLRefCountedObject<WebGLTexture>
, public LinkedListElement<WebGLTexture>
, public WebGLContextBoundObject
, public WebGLFramebufferAttachable
{
// Friends
friend class WebGLContext;
friend class WebGLFramebuffer;
////////////////////////////////////
// Members
public:
class ImageInfo;
const GLuint mGLName;
protected:
GLenum mTarget;
TexTarget mTarget;
static const uint8_t kMaxFaceCount = 6;
uint8_t mFaceCount; // 6 for cube maps, 1 otherwise.
TexMinFilter mMinFilter;
TexMagFilter mMagFilter;
TexWrap mWrapS, mWrapT;
size_t mFacesCount, mMaxLevelWithCustomImages;
nsTArray<ImageInfo> mImageInfos;
bool mHaveGeneratedMipmap; // Set by generateMipmap
bool mImmutable; // Set by texStorage*
uint8_t mImmutableLevelCount;
size_t mBaseMipmapLevel; // Set by texParameter (defaults to 0)
size_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000)
uint32_t mBaseMipmapLevel; // Set by texParameter (defaults to 0)
uint32_t mMaxMipmapLevel; // Set by texParameter (defaults to 1000)
// You almost certainly don't want to query mMaxMipmapLevel.
// You almost certainly want MaxEffectiveMipmapLevel().
WebGLTextureFakeBlackStatus mFakeBlackStatus;
GLenum mTexCompareMode;
// Resolvable optimizations:
bool mIsResolved;
FakeBlackType mResolved_FakeBlack;
const GLint* mResolved_Swizzle; // nullptr means 'default swizzle'.
public:
class ImageInfo;
// numLevels = log2(size) + 1
// numLevels(16k) = log2(16k) + 1 = 14 + 1 = 15
// numLevels(1M) = log2(1M) + 1 = 19.9 + 1 ~= 21
// Or we can just max this out to 31, which is the number of unsigned bits in GLsizei.
static const uint8_t kMaxLevelCount = 31;
// And in turn, it needs these forwards:
protected:
// We need to forward these.
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::SetImageInfo(ImageInfo* target,
const ImageInfo& newInfo);
friend void WebGLTexture::SetImageInfosAtLevel(uint32_t level,
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 webgl::FormatUsageInfo* const mFormat;
const uint32_t mWidth;
const uint32_t mHeight;
const uint32_t mDepth;
protected:
bool mIsDataInitialized;
std::set<WebGLFBAttachPoint*> mAttachPoints;
public:
ImageInfo()
: mFormat(LOCAL_GL_NONE)
, mWidth(0)
, mHeight(0)
, mDepth(0)
, mIsDataInitialized(false)
{ }
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);
}
void Clear();
~ImageInfo() {
if (!IsDefined())
Clear();
}
protected:
ImageInfo& operator =(const ImageInfo& a);
public:
uint32_t MaxMipmapLevels() const {
// GLES 3.0.4, 3.8 - Mipmapping: `floor(log2(largest_of_dims)) + 1`
uint32_t largest = std::max(std::max(mWidth, mHeight), mDepth);
return FloorLog2Size(largest) + 1;
}
bool IsPowerOfTwo() const;
void AddAttachPoint(WebGLFBAttachPoint* attachPoint);
void RemoveAttachPoint(WebGLFBAttachPoint* attachPoint);
void OnRespecify() const;
size_t MemoryUsage() const;
bool IsDefined() const {
if (mFormat == LOCAL_GL_NONE) {
MOZ_ASSERT(!mWidth && !mHeight && !mDepth);
return false;
}
return true;
}
bool IsDataInitialized() const { return mIsDataInitialized; }
void SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex);
};
ImageInfo mImageInfoArr[kMaxLevelCount * kMaxFaceCount];
////////////////////////////////////
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
@ -82,10 +194,10 @@ public:
void Delete();
bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
GLenum Target() const { return mTarget; }
TexTarget Target() const { return mTarget; }
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
@ -94,6 +206,7 @@ protected:
~WebGLTexture() {
DeleteOnce();
}
public:
////////////////////////////////////
// GL calls
@ -107,290 +220,129 @@ public:
////////////////////////////////////
// WebGLTextureUpload.cpp
void CompressedTexImage2D(TexImageTarget texImageTarget, GLint level,
GLenum internalFormat, GLsizei width, GLsizei height,
GLint border, const dom::ArrayBufferViewOrSharedArrayBufferView& view);
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 CompressedTexImage3D(TexImageTarget texImageTarget, GLint level,
GLenum internalFormat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLsizei imageSize,
const dom::ArrayBufferViewOrSharedArrayBufferView& view);
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 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 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 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:
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);
/** 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);
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, TexInternalFormat internalFormat,
GLint xoffset, GLint yoffset, GLint x, GLint y,
GLsizei width, GLsizei height, bool isSub);
bool TexImageFromVideoElement(TexImageTarget texImageTarget, GLint level,
GLenum internalFormat, GLenum unpackFormat,
GLenum unpackType, dom::Element* elem);
// 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);
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);
public:
// We store information about the various images that are part of this
// texture. (cubemap faces, mipmap levels)
class ImageInfo
: public WebGLRectangleObject
{
public:
ImageInfo()
: mEffectiveInternalFormat(LOCAL_GL_NONE)
, mDepth(0)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
{}
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);
ImageInfo(GLsizei width, GLsizei height, GLsizei depth,
TexInternalFormat effectiveInternalFormat,
WebGLImageDataStatus status)
: WebGLRectangleObject(width, height)
, mEffectiveInternalFormat(effectiveInternalFormat)
, mDepth(depth)
, mImageDataStatus(status)
{
// shouldn't use this constructor to construct a null ImageInfo
MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
}
////////////////////////////////////
bool operator==(const ImageInfo& a) const {
return mImageDataStatus == a.mImageDataStatus &&
mWidth == a.mWidth &&
mHeight == a.mHeight &&
mDepth == a.mDepth &&
mEffectiveInternalFormat == a.mEffectiveInternalFormat;
}
bool operator!=(const ImageInfo& a) const {
return !(*this == a);
}
bool IsSquare() const {
return mWidth == mHeight;
}
bool IsPositive() const {
return mWidth > 0 && mHeight > 0 && mDepth > 0;
}
bool IsPowerOfTwo() const {
MOZ_ASSERT(mWidth >= 0);
MOZ_ASSERT(mHeight >= 0);
return IsPOTAssumingNonnegative(mWidth) &&
IsPOTAssumingNonnegative(mHeight);
}
bool HasUninitializedImageData() const {
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
}
size_t MemoryUsage() const;
protected:
void ClampLevelBaseAndMax();
TexInternalFormat EffectiveInternalFormat() const {
return mEffectiveInternalFormat;
}
GLsizei Depth() const { return mDepth; }
void PopulateMipChain(uint32_t baseLevel, uint32_t maxLevel);
protected:
// 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.
TexInternalFormat mEffectiveInternalFormat;
uint32_t MaxEffectiveMipmapLevel() const;
/* Used only for 3D textures.
* Note that mWidth and mHeight are inherited from WebGLRectangleObject.
* It's a pity to store a useless mDepth on non-3D texture images, but
* the size of GLsizei is negligible compared to the typical size of a texture image.
*/
GLsizei mDepth;
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:
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 rawTexImageTarget - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
WebGLImageDataStatus mImageDataStatus;
friend class WebGLTexture;
};
private:
static size_t FaceForTarget(TexImageTarget texImageTarget) {
if (texImageTarget == LOCAL_GL_TEXTURE_2D ||
texImageTarget == LOCAL_GL_TEXTURE_3D)
{
default:
return 0;
}
return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
}
ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
MOZ_ASSERT(face < mFacesCount,
"Wrong face index, must be 0 for TEXTURE_2D or TEXTURE_3D,"
" and at most 5 for cube maps.");
// No need to check level as a wrong value would be caught by
// ElementAt().
return mImageInfos.ElementAt(level * mFacesCount + face);
ImageInfo& ImageInfoAtFace(uint8_t face, uint32_t level) {
MOZ_ASSERT(face < mFaceCount);
MOZ_ASSERT(level < kMaxLevelCount);
size_t pos = (level * mFaceCount) + face;
return mImageInfoArr[pos];
}
const ImageInfo& ImageInfoAtFace(size_t face, GLint level) const {
return const_cast<const ImageInfo&>(
const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level)
);
const ImageInfo& ImageInfoAtFace(uint8_t face, uint32_t level) const {
return const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level);
}
public:
ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) {
size_t face = FaceForTarget(imageTarget);
ImageInfo& ImageInfoAt(TexImageTarget texImageTarget, GLint level) {
auto face = FaceForTarget(texImageTarget);
return ImageInfoAtFace(face, level);
}
const ImageInfo& ImageInfoAt(TexImageTarget imageTarget, GLint level) const
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)
{
return const_cast<WebGLTexture*>(this)->ImageInfoAt(imageTarget, level);
ImageInfo* target = &ImageInfoAt(texImageTarget, level);
SetImageInfo(target, val);
}
bool HasImageInfoAt(TexImageTarget imageTarget, GLint level) const {
size_t face = FaceForTarget(imageTarget);
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
return checked_index.isValid() &&
checked_index.value() < mImageInfos.Length() &&
ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData;
}
const ImageInfo& BaseImageInfo() const {
if (mBaseMipmapLevel >= kMaxLevelCount)
return ImageInfo::kUndefined;
ImageInfo& ImageInfoBase() {
return ImageInfoAtFace(0, 0);
}
const ImageInfo& ImageInfoBase() const {
return ImageInfoAtFace(0, 0);
return ImageInfoAtFace(0, mBaseMipmapLevel);
}
size_t MemoryUsage() const;
void SetImageDataStatus(TexImageTarget imageTarget, GLint level,
WebGLImageDataStatus newStatus)
{
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
// There is no way to go from having image data to not having any.
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
if (imageInfo.mImageDataStatus != newStatus)
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
imageInfo.mImageDataStatus = newStatus;
}
bool EnsureInitializedImageData(TexImageTarget imageTarget, GLint level);
bool InitializeImageData(const char* funcName, TexImageTarget target, uint32_t level);
protected:
void EnsureMaxLevelWithCustomImagesAtLeast(size_t maxLevelWithCustomImages) {
mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages,
maxLevelWithCustomImages);
mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount);
}
bool EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
uint32_t level);
bool CheckFloatTextureFilterParams() const {
// Without OES_texture_float_linear, only NEAREST and
@ -405,33 +357,7 @@ protected:
mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
}
bool DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
public:
void Bind(TexTarget texTarget);
void SetImageInfo(TexImageTarget target, GLint level, GLsizei width,
GLsizei height, GLsizei depth, TexInternalFormat format,
WebGLImageDataStatus status);
void SetMinFilter(TexMinFilter minFilter) {
mMinFilter = minFilter;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetMagFilter(TexMagFilter magFilter) {
mMagFilter = magFilter;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetWrapS(TexWrap wrapS) {
mWrapS = wrapS;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetWrapT(TexWrap wrapT) {
mWrapT = wrapT;
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
TexMinFilter MinFilter() const { return mMinFilter; }
bool DoesMinFilterRequireMipmap() const {
return !(mMinFilter == LOCAL_GL_NEAREST ||
mMinFilter == LOCAL_GL_LINEAR);
@ -441,51 +367,31 @@ public:
void SetCustomMipmap();
bool IsFirstImagePowerOfTwo() const {
return ImageInfoBase().IsPowerOfTwo();
}
bool AreAllLevel0ImageInfosEqual() const;
bool IsMipmapComplete() const;
bool IsCubeComplete() const;
bool IsComplete(const char** const out_reason) const;
bool IsMipmapCubeComplete() const;
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x);
bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
bool IsImmutable() const { return mImmutable; }
void SetImmutable() { mImmutable = true; }
// Resolve cache optimizations
protected:
bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
FakeBlackType* const out_fakeBlack);
public:
bool ResolveForDraw(const char* funcName, uint32_t texUnit,
FakeBlackType* const out_fakeBlack);
void SetBaseMipmapLevel(size_t level) { mBaseMipmapLevel = level; }
void SetMaxMipmapLevel(size_t level) { mMaxMipmapLevel = level; }
// Clamping (from ES 3.0.4, section 3.8 - Texturing). When not immutable,
// the ranges must be guarded.
size_t EffectiveBaseMipmapLevel() const {
if (IsImmutable())
return std::min(mBaseMipmapLevel, mMaxLevelWithCustomImages);
return mBaseMipmapLevel;
}
size_t EffectiveMaxMipmapLevel() const {
if (IsImmutable()) {
return mozilla::clamped(mMaxMipmapLevel, EffectiveBaseMipmapLevel(),
mMaxLevelWithCustomImages);
}
return std::min(mMaxMipmapLevel, mMaxLevelWithCustomImages);
}
bool IsMipmapRangeValid() const;
size_t MaxLevelWithCustomImages() const { return mMaxLevelWithCustomImages; }
// Returns the current fake-black-status, except if it was Unknown,
// in which case this function resolves it first, so it never returns Unknown.
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
void InvalidateResolveCache() { mIsResolved = false; }
};
inline TexImageTarget
TexImageTargetForTargetAndFace(TexTarget target, size_t face)
TexImageTargetForTargetAndFace(TexTarget target, uint8_t face)
{
switch (target.get()) {
case LOCAL_GL_TEXTURE_2D:
@ -500,6 +406,23 @@ TexImageTargetForTargetAndFace(TexTarget target, size_t face)
}
}
already_AddRefed<mozilla::layers::Image>
ImageFromVideo(dom::HTMLVideoElement* elem);
GLenum
DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
GLsizei depth, const void* data);
GLenum
DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffset,
GLint yOffset, GLint zOffset, GLsizei width, GLsizei height,
GLsizei depth, const webgl::PackingInfo& pi, 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_

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@ WebGLTimerQuery::Delete()
WebGLContext*
WebGLTimerQuery::GetParentObject() const
{
return Context();
return mContext;
}

View File

@ -41,7 +41,7 @@ WebGLTransformFeedback::Delete()
WebGLContext*
WebGLTransformFeedback::GetParentObject() const
{
return Context();
return mContext;
}
JSObject*

View File

@ -18,12 +18,10 @@ typedef bool WebGLboolean;
namespace mozilla {
/*
* WebGLContextFakeBlackStatus and WebGLTextureFakeBlackStatus are enums to
* track what needs to use a dummy 1x1 black texture, which we refer to as a
* 'fake black' texture.
* WebGLTextureFakeBlackStatus is an enum to track what needs to use a dummy 1x1 black
* texture, which we refer to as a 'fake black' texture.
*
* There are generally two things that can cause us to use such 'fake black'
* textures:
* There are two things that can cause us to use such 'fake black' textures:
*
* (1) OpenGL ES rules on sampling incomplete textures specify that they
* must be sampled as RGBA(0, 0, 0, 1) (opaque black). We have to implement these rules
@ -38,23 +36,12 @@ namespace mozilla {
* uninitialized image data must be exposed to WebGL as if it were filled
* with zero bytes, which means it's either opaque or transparent black
* depending on whether the image format has alpha.
*
* Why are there _two_ separate enums there, WebGLContextFakeBlackStatus
* and WebGLTextureFakeBlackStatus? That's because each texture must know the precise
* reason why it needs to be faked (incomplete texture vs. uninitialized image data),
* whereas the WebGL context can only know whether _any_ faking is currently needed at all.
*/
enum class WebGLContextFakeBlackStatus : uint8_t {
Unknown,
NotNeeded,
Needed
};
enum class WebGLTextureFakeBlackStatus : uint8_t {
Unknown,
NotNeeded,
IncompleteTexture,
UninitializedImageData
enum class FakeBlackType : uint8_t {
None,
RGBA0001, // Incomplete textures and uninitialized no-alpha color textures.
RGBA0000, // Uninitialized with-alpha color textures.
};
/*
@ -115,6 +102,7 @@ enum class WebGLTexelFormat : uint8_t {
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

View File

@ -47,7 +47,7 @@ public:
bool IsVertexArray();
WebGLContext* GetParentObject() const {
return Context();
return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;

View File

@ -54,6 +54,7 @@ UNIFIED_SOURCES += [
# WebGL Sources
UNIFIED_SOURCES += [
'MurmurHash3.cpp',
'TexUnpackBlob.cpp',
'WebGL1Context.cpp',
'WebGL1ContextBuffers.cpp',
'WebGL1ContextUniforms.cpp',

View File

@ -78,26 +78,27 @@ function expectResult(target, successMessage, failureMessage) {
}
}
function createGreysRGBTexture(gl, color) {
function createGreySRGBATexture(gl, color) {
var numPixels = gl.drawingBufferWidth * gl.drawingBufferHeight;
var size = numPixels * 3;
var size = numPixels * 4;
var buf = new Uint8Array(size);
for (var ii = 0; ii < numPixels; ++ii) {
var off = ii * 3;
buf[off + 0] = color;
buf[off + 1] = color;
buf[off + 2] = color;
buf[off + 3] = 0xff;
}
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D,
0,
ext.SRGB_EXT,
ext.SRGB_ALPHA_EXT,
gl.drawingBufferWidth,
gl.drawingBufferHeight,
0,
ext.SRGB_EXT,
ext.SRGB_ALPHA_EXT,
gl.UNSIGNED_BYTE,
buf);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
@ -266,11 +267,11 @@ function runTextureReadConversionTest() {
gl.uniform1i(gl.getUniformLocation(program, "tex2d"), 0);
for (var ii = 0; ii < conversions.length; ii++) {
var tex = createGreysRGBTexture(gl, conversions[ii][0]);
var tex = createGreySRGBATexture(gl, conversions[ii][0]);
wtu.drawQuad(gl);
expectResult(conversions[ii][1],
"sRGB texture read returned correct data",
"sRGB texture read returned incorrect data");
"sRGBA texture read returned correct data",
"sRGBA texture read returned incorrect data");
}
}
@ -279,13 +280,14 @@ function runFramebufferTextureConversionTest() {
debug("Test the conversion of colors from linear to sRGB on framebuffer (texture) write");
var program = wtu.setupProgram(gl, ['vertexShader', 'fragmentShader'], ['aPosition'], [0]);
var tex = createGreysRGBTexture(gl, 0);
var tex = createGreySRGBATexture(gl, 0);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
// Draw
@ -307,6 +309,7 @@ function runFramebufferTextureConversionTest() {
"framebuffer (texture) read returned incorrect data");
}
glErrorShouldBe(gl, gl.NO_ERROR);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
@ -327,6 +330,7 @@ function runFramebufferRenderbufferConversionTest() {
glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
return fbo;
@ -352,6 +356,8 @@ function runFramebufferRenderbufferConversionTest() {
"framebuffer (renderbuffer) read returned the correct data",
"framebuffer (renderbuffer) read returned incorrect data");
}
glErrorShouldBe(gl, gl.NO_ERROR);
}
debug("");

View File

@ -131,7 +131,8 @@ function runTextureCreationTest(testProgram, extensionEnabled)
}
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, data);
if (expectFailure) {
glErrorShouldBe(gl, gl.INVALID_ENUM, "floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
wtu.glErrorShouldBeIn(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION],
"floating-point texture allocation must be disallowed if OES_texture_float isn't enabled");
return;
} else {
glErrorShouldBe(gl, gl.NO_ERROR, "floating-point texture allocation should succeed if OES_texture_float is enabled");

View File

@ -76,7 +76,7 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteTexture(tex)");
// Deleting a texture bound to the currently-bound fbo is the same as
// detaching the textue from fbo first, then delete the texture.
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "null");
shouldBeFalse("gl.isTexture(tex)");
shouldBeNull("gl.getParameter(gl.TEXTURE_BINDING_2D)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindTexture(gl.TEXTURE_2D, tex)");
@ -128,7 +128,7 @@ shouldGenerateGLError(gl, gl.NO_ERROR, "gl.deleteRenderbuffer(rbo)");
// Deleting a renderbuffer bound to the currently-bound fbo is the same as
// detaching the renderbuffer from fbo first, then delete the renderbuffer.
shouldBe("gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)", "gl.NONE");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)", "null");
shouldBeFalse("gl.isRenderbuffer(rbo)");
shouldBeNull("gl.getParameter(gl.RENDERBUFFER_BINDING)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindRenderbuffer(gl.RENDERBUFFER, rbo)");
@ -263,7 +263,7 @@ if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE) {
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, fbo)");
shouldGenerateGLError(gl, gl.INVALID_ENUM, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)");
shouldGenerateGLError(gl, gl.NONE, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)");
shouldNotBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
// Bind backbuffer.
shouldGenerateGLError(gl, gl.NO_ERROR, "gl.bindFramebuffer(gl.FRAMEBUFFER, null)");

View File

@ -58,53 +58,53 @@ function teardown(gl, tex) {
gl.deleteTexture(tex);
}
function testrunner(gl, expected, desc, fn) {
function testrunner(gl, expectedList, desc, fn) {
var tex = setup(gl);
fn();
glErrorShouldBe(gl, expected, desc);
wtu.glErrorShouldBeIn(gl, expectedList, desc);
teardown(gl, tex);
}
var data = new Uint8Array(4);
testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2,1,0,gl.RGBA,gl.UNSIGNED_BYTE, data);
});
testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,2,0,gl.RGBA,gl.UNSIGNED_BYTE, data);
});
testrunner(gl, gl.INVALID_ENUM, "bad target", function(){
testrunner(gl, [gl.INVALID_ENUM], "bad target", function(){
gl.texImage2D(gl.FLOAT, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_ENUM, "bad internal format/format", function(){
testrunner(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE], "bad internal format/format", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.FLOAT, 1,1,0,gl.FLOAT,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_VALUE, "border > 0", function(){
testrunner(gl, [gl.INVALID_VALUE], "border > 0", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,48,gl.RGBA,gl.UNSIGNED_BYTE, null);
});
// The spec says zero size is OK. If you disagree please list the section
// in the spec that details this issue.
testrunner(gl, gl.NO_ERROR, "zero size", function(){
testrunner(gl, [gl.NO_ERROR], "zero size", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0,0,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_VALUE, "negative width", function(){
testrunner(gl, [gl.INVALID_VALUE], "negative width", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, -1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_VALUE, "negative height", function(){
testrunner(gl, [gl.INVALID_VALUE], "negative height", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,-1,0,gl.RGBA,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_ENUM, "bad format", function(){
testrunner(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], "bad format", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.FLOAT,gl.UNSIGNED_BYTE, null);
});
testrunner(gl, gl.INVALID_ENUM, "bad type", function(){
testrunner(gl, [gl.INVALID_ENUM], "bad type", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.TEXTURE_2D, null);
});
testrunner(gl, gl.INVALID_OPERATION, "not enough data", function(){
testrunner(gl, [gl.INVALID_OPERATION], "not enough data", function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array(3));
});
testrunner(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
testrunner(gl, [gl.INVALID_OPERATION], "format and type incompatible",function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1,1,0,gl.RGBA,gl.UNSIGNED_SHORT_5_6_5, null);
});
testrunner(gl, gl.INVALID_OPERATION, "format and type incompatible",function(){
testrunner(gl, [gl.INVALID_OPERATION], "format and type incompatible",function(){
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1,1,0,gl.RGB,gl.UNSIGNED_SHORT_4_4_4_4, null);
});

View File

@ -31,6 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE.
<link rel="stylesheet" type="text/css" href="../unit.css" />
<script type="application/x-javascript" src="../unit.js"></script>
<script type="application/x-javascript" src="../util.js"></script>
<script src="../../resources/webgl-test-utils.js"></script>
<script type="application/x-javascript">
Tests.startUnit = function () {
@ -51,7 +52,7 @@ Tests.teardown = function(gl,tex) {
}
Tests.testTexImage2D = function(gl) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2,2,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]));
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2,2,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]));
assertGLError(gl, gl.INVALID_OPERATION, "not enough data", function(){
gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 2,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
});
@ -70,10 +71,10 @@ Tests.testTexImage2D = function(gl) {
assertOk("zero size", function(){
gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 0,0,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
});
assertSomeGLError(gl, "negative width", function(){
assertGLError(gl, gl.INVALID_VALUE, "negative width", function(){
gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, -1,1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
});
assertSomeGLError(gl, "negative height", function(){
assertGLError(gl, gl.INVALID_VALUE, "negative height", function(){
gl.texSubImage2D(gl.TEXTURE_2D, 0,0, 0, 1,-1,gl.RGBA,gl.UNSIGNED_BYTE, new Uint8Array([0,0,0,0]));
});
assertGLError(gl, gl.INVALID_VALUE, "negative x", function(){

View File

@ -1001,12 +1001,11 @@ function wrapGLContext(gl) {
// Assert that f generates a specific GL error.
function assertGLError(gl, err, name, f) {
if (f == null) { f = name; name = null; }
var r = false;
var glErr = 0;
try { f(); } catch(e) { r=true; glErr = e.glError; }
try { f(); } catch(e) { glErr = e.glError; }
if (glErr !== err) {
if (glErr === undefined) {
testFailed("assertGLError: UNEXPCETED EXCEPTION", name, f);
testFailed("assertGLError: UNEXPECTED EXCEPTION", name, f);
} else {
testFailed("assertGLError: expected: " + getGLErrorAsString(gl, err) +
" actual: " + getGLErrorAsString(gl, glErr), name, f);
@ -1016,6 +1015,40 @@ function assertGLError(gl, err, name, f) {
return true;
}
// Assert that f generates a specific GL error.
function assertGLErrorIn(gl, expectedErrorList, name, f) {
if (f == null) { f = name; name = null; }
var actualError = 0;
try {
f();
} catch(e) {
if ('glError' in e) {
actualError = e.glError;
} else {
testFailed("assertGLErrorIn: UNEXPECTED EXCEPTION", name, f);
return false;
}
}
var expectedErrorStrList = [];
var expectedErrorSet = {};
for (var i in expectedErrorList) {
var cur = expectedErrorList[i];
expectedErrorSet[cur] = true;
expectedErrorStrList.push(getGLErrorAsString(gl, cur));
}
var expectedErrorListStr = "[" + expectedErrorStrList.join(", ") + "]";
if (actualError in expectedErrorSet) {
return true;
}
testFailed("assertGLErrorIn: expected: " + expectedErrorListStr +
" actual: " + getGLErrorAsString(gl, actualError), name, f);
return false;
}
// Assert that f generates some GL error. Used in situations where it's
// ambigious which of multiple possible errors will be generated.
function assertSomeGLError(gl, name, f) {

View File

@ -132,16 +132,17 @@ if (!gl) {
glErrorShouldBe(gl, gl.INVALID_ENUM,
"calling framebufferRenderbuffer with attachment = COLOR_ATTACHMENT1 should generate INVALID_ENUM.");
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 0);
glErrorShouldBe(gl, gl.NO_ERROR,
"attaching a texture to a framebuffer should succeed.");
// Must have a valid attachment, otherwise may also generate INVALID_OPERATION.
gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
desktopGL.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING);
glErrorShouldBe(gl, gl.INVALID_ENUM,
"calling getFramebufferAttachmentParameter with pname = GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING should generate INVALID_ENUM.");
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fbtex, 0);
glErrorShouldBe(gl, gl.NO_ERROR,
"attaching a texture to a framebuffer should succeed.");
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, null, 0);
glErrorShouldBe(gl, gl.NO_ERROR,
"detaching a texture from a framebuffer should succeed.");

View File

@ -634,31 +634,6 @@ function create3DContextWithWrapperThatThrowsOnGLError(canvas) {
return wrap;
};
/**
* Tests that an evaluated expression generates a specific GL error.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} glError The expected gl error.
* @param {string} evalSTr The string to evaluate.
*/
var shouldGenerateGLError = function(gl, glError, evalStr) {
var exception;
try {
eval(evalStr);
} catch (e) {
exception = e;
}
if (exception) {
testFailed(evalStr + " threw exception " + exception);
} else {
var err = gl.getError();
if (err != glError) {
testFailed(evalStr + " expected: " + getGLErrorAsString(gl, glError) + ". Was " + getGLErrorAsString(gl, err) + ".");
} else {
testPassed(evalStr + " was expected value: " + getGLErrorAsString(gl, glError) + ".");
}
}
};
/**
* Tests that the first error GL returns is the specified error.
* @param {!WebGLContext} gl The WebGLContext to use.
@ -677,6 +652,84 @@ var glErrorShouldBe = function(gl, glError, opt_msg) {
}
};
/**
* Tests that the first error GL returns is in the specified error list.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {!Array.<number>} expectedErrorList The list of expected gl errors.
* @param {string} opt_msg
*/
var glErrorShouldBeIn = function(gl, expectedErrorList, opt_msg) {
opt_msg = opt_msg || "";
var expectedErrorStrList = [];
var expectedErrorSet = {};
for (var i in expectedErrorList) {
var cur = expectedErrorList[i];
expectedErrorStrList.push(getGLErrorAsString(gl, cur));
expectedErrorSet[cur] = true;
}
var expectedErrorStr = "[" + expectedErrorStrList.join(", ") + "]";
var actualError = gl.getError();
if (actualError in expectedErrorSet) {
testPassed("getError was in expected values: " + expectedErrorStr + " : " + opt_msg);
} else {
testFailed("getError expected: " + expectedErrorStr +
". Was " + getGLErrorAsString(gl, actualError) + " : " + opt_msg);
}
};
/**
* Tests that an evaluated expression generates a specific GL error.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {number} glError The expected gl error.
* @param {string} evalSTr The string to evaluate.
*/
var shouldGenerateGLError = function(gl, glError, evalStr) {
glErrorShouldBe(gl, 0,
"Should not be pre-existing errors during call to"
+ " shouldGenerateGLError().");
var exception;
try {
eval(evalStr);
} catch (e) {
exception = e;
}
if (exception) {
testFailed(evalStr + " threw exception " + exception);
} else {
glErrorShouldBe(gl, glError, evalStr);
}
};
/**
* Tests that an evaluated expression generates a GL error from a list.
* @param {!WebGLContext} gl The WebGLContext to use.
* @param {!Array.<number>} expectedErrorList The list of expected gl errors.
* @param {string} evalSTr The string to evaluate.
*/
var shouldGenerateGLErrorIn = function(gl, expectedErrorList, evalStr) {
glErrorShouldBe(gl, 0,
"Should not be pre-existing errors during call to"
+ " shouldGenerateGLErrorIn().");
var exception;
try {
eval(evalStr);
} catch (e) {
exception = e;
}
if (exception) {
testFailed(evalStr + " threw exception " + exception);
} else {
glErrorShouldBeIn(gl, expectedErrorList, evalStr);
}
};
/**
* Links a WebGL program, throws if there are errors.
* @param {!WebGLContext} gl The WebGLContext to use.
@ -1365,6 +1418,7 @@ return {
getUrlArguments: getUrlArguments,
glEnumToString: glEnumToString,
glErrorShouldBe: glErrorShouldBe,
glErrorShouldBeIn: glErrorShouldBeIn,
fillTexture: fillTexture,
insertImage: insertImage,
loadImageAsync: loadImageAsync,

View File

@ -39,8 +39,8 @@ function testTexImage2D(testCase)
" border: " + testCase.border;
gl.texImage2D(testCase.target, level, testCase.internalFormat, width, height, testCase.border, testCase.format, testCase.type, null);
error = testCase.expectedError;
glErrorShouldBe(gl, error, msg);
errors = testCase.expectedErrors;
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testTexSubImage2D(testCase)
@ -55,26 +55,26 @@ function testTexSubImage2D(testCase)
" type: " + enumToString(testCase.type);
var array = new Uint8Array(width * height * 4);
gl.texSubImage2D(testCase.target, level, xoffset, yoffset, width, height, testCase.format, testCase.type, array);
error = testCase.expectedError;
glErrorShouldBe(gl, error, msg);
errors = testCase.expectedErrors;
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testTexParameter(testCase)
{
var msg = "paramName: " + enumToString(testCase.pname);
error = testCase.expectedError;
errors = testCase.expectedErrors;
gl.texParameteri(testCase.target, testCase.pname, testCase.param);
glErrorShouldBe(gl, error, msg);
wtu.glErrorShouldBeIn(gl, errors, msg);
gl.texParameterf(testCase.target, testCase.pname, testCase.param);
glErrorShouldBe(gl, error, msg);
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testGetTexParameter(testCase)
{
var msg = "paramName: " + enumToString(testCase.pname);
error = testCase.expectedError;
errors = testCase.expectedErrors;
gl.getTexParameter(testCase.target, testCase.pname);
glErrorShouldBe(gl, error, msg);
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testCopyTexImage2D(testCase)
@ -96,8 +96,8 @@ function testCopyTexImage2D(testCase)
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
gl.copyTexImage2D(testCase.target, level, testCase.internalFormat, x, y, width, height, testCase.border);
error = testCase.expectedError;
glErrorShouldBe(gl, error, msg);
errors = testCase.expectedErrors;
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testCopyTexSubImage2D(testCase)
@ -124,8 +124,8 @@ function testCopyTexSubImage2D(testCase)
glErrorShouldBe(gl, gl.NO_ERROR);
gl.copyTexSubImage2D(testCase.target, level, xoffset, yoffset, x, y, width, height);
error = testCase.expectedError;
glErrorShouldBe(gl, error, msg);
errors = testCase.expectedErrors;
wtu.glErrorShouldBeIn(gl, errors, msg);
}
function testCopyFromInternalFBO(testCase)
@ -159,8 +159,8 @@ function testCopyFromInternalFBO(testCase)
glErrorShouldBe(gl, gl.NO_ERROR);
gl.copyTexImage2D(target, level, testCase.internalFormat, x, y, width, height, border);
}
error = testCase.expectedError;
glErrorShouldBe(gl, error, msg);
errors = testCase.expectedErrors;
wtu.glErrorShouldBeIn(gl, errors, msg);
}
description("Validate tex functions input parameters");
@ -179,37 +179,37 @@ var testCases =
border: 0,
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
internalFormat: 0x1903, // GL_RED
border: 0,
format: 0x1903, // GL_RED
type: gl.UNSIGNED_BYTE,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM, gl.INVALID_VALUE]},
{target: gl.TEXTURE_2D,
internalFormat: gl.RGBA,
border: 1,
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
expectedError: gl.INVALID_VALUE},
expectedErrors: [gl.INVALID_VALUE]},
{target: gl.TEXTURE_2D,
internalFormat: gl.RGBA,
border: 0,
format: gl.RGB,
type: gl.UNSIGNED_BYTE,
expectedError: gl.INVALID_OPERATION},
expectedErrors: [gl.INVALID_OPERATION]},
{target: gl.TEXTURE_2D,
internalFormat: gl.RGBA,
border: 0,
format: gl.RGBA,
type: gl.BYTE,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
internalFormat: gl.RGBA,
border: 0,
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
expectedError: gl.NO_ERROR} ];
expectedErrors: [gl.NO_ERROR]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testTexImage2D(testCases[ii]);
@ -221,15 +221,15 @@ testCases =
[ {target: gl.TEXTURE_2D,
format: 0x1903, // GL_RED
type: gl.UNSIGNED_BYTE,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
{target: gl.TEXTURE_2D,
format: gl.RGBA,
type: gl.BYTE,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM, gl.INVALID_OPERATION]},
{target: gl.TEXTURE_2D,
format: gl.RGBA,
type: gl.UNSIGNED_BYTE,
expectedError: gl.NO_ERROR} ];
expectedErrors: [gl.NO_ERROR]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testTexSubImage2D(testCases[ii]);
@ -241,19 +241,19 @@ testCases =
[ {target: 0x0DE0, // GL_TEXTURE_1D
pname: gl.TEXTURE_WRAP_T,
param: gl.REPEAT,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
pname: 0x813A, // GL_TEXTURE_MIN_LOD
param: 0,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
pname: gl.TEXTURE_WRAP_T,
param: 0x2900, // GL_CLAMP
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
pname: gl.TEXTURE_WRAP_T,
param: gl.REPEAT,
expectedError: gl.NO_ERROR} ];
expectedErrors: [gl.NO_ERROR]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testTexParameter(testCases[ii]);
@ -264,13 +264,13 @@ debug("Checking GetTexParameter: a set of inputs that are valid in GL but invali
testCases =
[ {target: 0x0DE0, // GL_TEXTURE_1D
pname: gl.TEXTURE_WRAP_T,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
pname: 0x813A, // GL_TEXTURE_MIN_LOD
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
pname: gl.TEXTURE_WRAP_T,
expectedError: gl.NO_ERROR} ];
expectedErrors: [gl.NO_ERROR]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testGetTexParameter(testCases[ii]);
@ -293,22 +293,22 @@ testCases =
colorBufferFormat: gl.RGB565,
internalFormat: 0x8054, // GL_RGB16
border: 0,
expectedError: gl.INVALID_ENUM},
expectedErrors: [gl.INVALID_ENUM]},
{target: gl.TEXTURE_2D,
colorBufferFormat: gl.RGB565,
internalFormat: gl.RGBA,
border: 1,
expectedError: gl.INVALID_VALUE},
expectedErrors: [gl.INVALID_VALUE]},
{target: gl.TEXTURE_2D,
colorBufferFormat: gl.RGB565,
internalFormat: gl.RGBA,
border: 0,
expectedError: gl.INVALID_OPERATION},
expectedErrors: [gl.INVALID_OPERATION]},
{target: gl.TEXTURE_2D,
colorBufferFormat: gl.RGB565,
internalFormat: gl.RGB,
border: 0,
expectedError: gl.NO_ERROR} ];
expectedErrors: [gl.NO_ERROR]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testCopyTexImage2D(testCases[ii]);
@ -320,11 +320,11 @@ testCases =
[ {target: gl.TEXTURE_2D,
colorBufferFormat: gl.RGB5_A1,
internalFormat: gl.RGBA,
expectedError: gl.NO_ERROR},
expectedErrors: [gl.NO_ERROR]},
{target: gl.TEXTURE_2D,
colorBufferFormat: gl.RGB565,
internalFormat: gl.RGBA,
expectedError: gl.INVALID_OPERATION} ];
expectedErrors: [gl.INVALID_OPERATION]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testCopyTexSubImage2D(testCases[ii]);
@ -336,19 +336,19 @@ testCases =
[ {contextAlpha: true,
internalFormat: gl.RGBA,
subImage: false,
expectedError: gl.NO_ERROR},
expectedErrors: [gl.NO_ERROR]},
{contextAlpha: false,
internalFormat: gl.RGBA,
subImage: false,
expectedError: gl.INVALID_OPERATION},
expectedErrors: [gl.INVALID_OPERATION]},
{contextAlpha: true,
internalFormat: gl.RGBA,
subImage: true,
expectedError: gl.NO_ERROR},
expectedErrors: [gl.NO_ERROR]},
{contextAlpha: false,
internalFormat: gl.RGBA,
subImage: true,
expectedError: gl.INVALID_OPERATION} ];
expectedErrors: [gl.INVALID_OPERATION]} ];
for (var ii = 0; ii < testCases.length; ++ii)
testCopyFromInternalFBO(testCases[ii]);

View File

@ -66,9 +66,9 @@ if (!gl) {
var err = gl.getError();
if (err == gl.NO_ERROR) {
testFailed("should NOT be able to create texture of type " + formatName);
} else if (err == gl.INVALID_OPERATION) {
testFailed("should return gl.INVALID_ENUM for type " + formatName);
} else if (err == gl.INVALID_ENUM) {
} else if (err == gl.INVALID_ENUM ||
err == gl.INVALID_OPERATION)
{
testPassed("not able to create invalid format: " + formatName);
}
}

View File

@ -35,10 +35,10 @@ function IsFormatValidForTex(gl, format, type) {
gl.texImage2D(gl.TEXTURE_2D, 0, format, 4, 4, 0, format, type, null);
var error = gl.getError();
if (error == gl.INVALID_ENUM)
if (error == gl.INVALID_ENUM || error == gl.INVALID_OPERATION)
return false;
ok(error == gl.NO_ERROR, 'Error should be INVALID_ENUM or NO_ERROR.');
ok(error == gl.NO_ERROR, 'Error should be INVALID_{ENUM,OPERATION} or NO_ERROR.');
return error == gl.NO_ERROR;
}
@ -50,10 +50,10 @@ function IsFormatValidForTexFB(gl, format, type) {
gl.texImage2D(gl.TEXTURE_2D, 0, format, 4, 4, 0, format, type, null);
var error = gl.getError();
if (error == gl.INVALID_ENUM)
if (error == gl.INVALID_ENUM || error == gl.INVALID_OPERATION)
return false;
ok(error == gl.NO_ERROR, 'Error should be INVALID_ENUM or NO_ERROR.');
ok(error == gl.NO_ERROR, 'Error should be INVALID_{ENUM,OPERATION} or NO_ERROR.');
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
@ -75,10 +75,10 @@ function IsFormatValidForTexFBRead(gl, texFormat, texType, readType) {
null);
var error = gl.getError();
if (error == gl.INVALID_ENUM)
if (error == gl.INVALID_ENUM || error == gl.INVALID_OPERATION)
return false;
ok(error == gl.NO_ERROR, 'Error should be INVALID_ENUM or NO_ERROR.');
ok(error == gl.NO_ERROR, 'Error should be INVALID_{ENUM,OPERATION} or NO_ERROR.');
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

View File

@ -478,7 +478,8 @@ skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
[webgl/test_compressedTexImage2D.html]
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
[webgl/test_compressedTexSubImage2D.html]
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
skip-if = true # Bug 1226336
#skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
[webgl/test_texImage2D.html]
skip-if = (toolkit == 'android') || (buildapp == 'b2g') #android(WebGL)
[webgl/test_texSubImage2D.html]

View File

@ -344,30 +344,40 @@ interface WebGL2RenderingContext : WebGLRenderingContext
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);

View File

@ -694,11 +694,12 @@ interface WebGLRenderingContext {
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]
@ -714,11 +715,11 @@ interface WebGLRenderingContext {
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]

View File

@ -89,7 +89,7 @@ struct DrawOptions {
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. */
};
@ -415,25 +415,25 @@ public:
}
}
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;
@ -527,7 +527,7 @@ 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
@ -803,7 +803,7 @@ public:
/** @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.
*/
@ -863,7 +863,7 @@ public:
const Pattern &aPattern,
const StrokeOptions &aStrokeOptions = StrokeOptions(),
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Fill a path on the draw target with a certain source pattern.
*
@ -968,7 +968,7 @@ public:
* 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);
@ -1170,7 +1170,7 @@ public:
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);

View File

@ -17,7 +17,7 @@ namespace gfx {
uint8_t*
DataAtOffset(DataSourceSurface* aSurface,
DataSourceSurface::MappedSurface* aMap,
const DataSourceSurface::MappedSurface* aMap,
IntPoint aPoint)
{
if (!SurfaceContainsPoint(aSurface, aPoint)) {

View File

@ -874,11 +874,8 @@ Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride,
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>

View File

@ -12,7 +12,7 @@
namespace mozilla {
namespace gfx {
bool
void
SourceSurfaceRawData::InitWrappingData(uint8_t *aData,
const IntSize &aSize,
int32_t aStride,
@ -24,8 +24,6 @@ SourceSurfaceRawData::InitWrappingData(uint8_t *aData,
mStride = aStride;
mFormat = aFormat;
mOwnData = aOwnData;
return true;
}
void

View File

@ -33,7 +33,7 @@ public:
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,

View File

@ -42,6 +42,7 @@ EXPORTS.mozilla.gfx += [
'ScaleFactor.h',
'ScaleFactors2D.h',
'SourceSurfaceCairo.h',
'SourceSurfaceRawData.h',
'StackArray.h',
'Tools.h',
'Types.h',

View File

@ -141,6 +141,9 @@ GLenum TextureD3D::getBaseLevelInternalFormat() const
bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
{
if (image->isDirty())
return false;
if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
{
return false;

View File

@ -505,6 +505,13 @@ gl::Error Blit9::setFormatConvertShaders(GLenum destFormat)
return gl::Error(GL_NO_ERROR);
}
static bool
IsEmpty(const RECT& rect)
{
return rect.left == rect.right ||
rect.top == rect.bottom;
}
gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect, IDirect3DTexture9 **outTexture)
{
ASSERT(surface);
@ -516,7 +523,10 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so
// Copy the render target into a texture
IDirect3DTexture9 *texture;
HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left,
sourceRect.bottom - sourceRect.top, 1,
D3DUSAGE_RENDERTARGET, sourceDesc.Format,
D3DPOOL_DEFAULT, &texture, NULL);
if (FAILED(result))
{
@ -534,13 +544,82 @@ gl::Error Blit9::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &so
return gl::Error(GL_OUT_OF_MEMORY, "Failed to query surface of internal blit texture, result: 0x%X.", result);
}
D3DSURFACE_DESC destDesc;
textureSurface->GetDesc(&destDesc);
RECT subsetSourceRect = sourceRect;
RECT subsetDestRect = { 0, 0, destDesc.Width, destDesc.Height };
if (sourceRect.left < 0) {
LONG diff = 0 - sourceRect.left;
ASSERT(diff > 0);
subsetSourceRect.left += diff;
subsetDestRect.left += diff;
}
if (sourceRect.top < 0) {
LONG diff = 0 - sourceRect.top;
ASSERT(diff > 0);
subsetSourceRect.top += diff;
subsetDestRect.top += diff;
}
if (sourceRect.right > LONG(sourceDesc.Width)) {
LONG diff = sourceRect.right - sourceDesc.Width;
ASSERT(diff > 0);
subsetSourceRect.right -= diff;
subsetDestRect.right -= diff;
}
if (sourceRect.bottom > LONG(sourceDesc.Height)) {
LONG diff = sourceRect.bottom - sourceDesc.Height;
ASSERT(diff > 0);
subsetSourceRect.bottom -= diff;
subsetDestRect.bottom -= diff;
}
ASSERT(subsetSourceRect.left <= subsetSourceRect.right);
ASSERT(subsetSourceRect.top <= subsetSourceRect.bottom);
ASSERT(subsetDestRect.left <= subsetDestRect.right);
ASSERT(subsetDestRect.top <= subsetDestRect.bottom);
ASSERT(subsetSourceRect.right - subsetSourceRect.left == subsetDestRect.right - subsetDestRect.left);
ASSERT(subsetSourceRect.bottom - subsetSourceRect.top == subsetDestRect.bottom - subsetDestRect.top);
mRenderer->endScene();
result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
if (!IsEmpty(subsetSourceRect)) {
result = device->StretchRect(surface, &subsetSourceRect, textureSurface, &subsetDestRect, D3DTEXF_NONE);
}
SafeRelease(textureSurface);
if (FAILED(result))
{
if (!(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)) {
std::printf("Bad result: 0x%x\n", result);
std::printf("sourceRect: %i,%i - %i,%i\n", sourceRect.left, sourceRect.top,
sourceRect.right, sourceRect.bottom);
std::printf("sourceDesc: Format: %u, Type: %u, Usage: %u, Pool: %u,"
" MSType: %u, MSQuality: %u, Width: %u, Height: %u\n",
sourceDesc.Format, sourceDesc.Type, sourceDesc.Usage,
sourceDesc.Pool, sourceDesc.MultiSampleType,
sourceDesc.MultiSampleQuality, sourceDesc.Width,
sourceDesc.Height);
std::printf("subsetSourceRect: %i,%i - %i,%i\n", subsetSourceRect.left, subsetSourceRect.top,
subsetSourceRect.right, subsetSourceRect.bottom);
std::printf("destDesc: Format: %u, Type: %u, Usage: %u, Pool: %u, MSType: %u,"
" MSQuality: %u, Width: %u, Height: %u\n",
destDesc.Format, destDesc.Type, destDesc.Usage, destDesc.Pool,
destDesc.MultiSampleType, destDesc.MultiSampleQuality,
destDesc.Width, destDesc.Height);
std::printf("subsetDestRect: %i,%i - %i,%i\n", subsetDestRect.left, subsetDestRect.top,
subsetDestRect.right, subsetDestRect.bottom);
}
ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
SafeRelease(texture);
return gl::Error(GL_OUT_OF_MEMORY, "Failed to copy between internal blit textures, result: 0x%X.", result);

View File

@ -934,6 +934,18 @@ GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
return;
}
DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
internalFBs);
}
void
GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
GLenum srcTarget,
bool internalFBs)
{
BlitType type;
switch (srcTarget) {
case LOCAL_GL_TEXTURE_2D:

View File

@ -143,6 +143,11 @@ public:
const gfx::IntSize& destSize,
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
bool internalFBs = false);
void DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
bool internalFBs = false);
void BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
const gfx::IntSize& srcSize,
const gfx::IntSize& destSize,

View File

@ -647,7 +647,11 @@ public:
MOZ_ASSERT(!mHasBeenChecked);
mHasBeenChecked = true;
return mGL.fGetError();
const GLenum ret = mGL.fGetError();
while (mGL.fGetError()) {}
return ret;
}
~LocalErrorScope() {
@ -2309,6 +2313,7 @@ public:
public:
void fDrawBuffers(GLsizei n, const GLenum* bufs) {
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fDrawBuffers);
mSymbols.fDrawBuffers(n, bufs);
AFTER_GL_CALL;
}

View File

@ -836,6 +836,15 @@ GLContext::InitFeatures()
}
}
if (ShouldDumpExts()) {
for (size_t featureId = 0; featureId < size_t(GLFeature::EnumMax); featureId++) {
GLFeature feature = GLFeature(featureId);
printf_stderr("[%s] Feature::%s\n",
IsSupported(feature) ? "enabled" : "disabled",
GetFeatureName(feature));
}
}
if (WorkAroundDriverBugs()) {
#ifdef XP_MACOSX
// MacOSX 10.6 reports to support EXT_framebuffer_sRGB and EXT_texture_sRGB but

View File

@ -114,6 +114,7 @@ GLContextCGL::MakeCurrentImpl(bool aForce)
if (mContext) {
[mContext makeCurrentContext];
MOZ_ASSERT(IsCurrent());
// Use non-blocking swap in "ASAP mode".
// ASAP mode means that rendering is iterated as fast as possible.
// ASAP mode is entered when layout.frame_rate=0 (requires restart).

View File

@ -174,34 +174,56 @@ ScopedRenderbuffer::UnwrapImpl()
}
/* ScopedBindTexture **********************************************************/
void
ScopedBindTexture::Init(GLenum aTarget)
static GLuint
GetBoundTexture(GLContext* gl, GLenum texTarget)
{
mTarget = aTarget;
mOldTex = 0;
GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
: (aTarget == LOCAL_GL_TEXTURE_3D) ? LOCAL_GL_TEXTURE_BINDING_3D
: (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
: (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
: (aTarget == LOCAL_GL_TEXTURE_EXTERNAL) ? LOCAL_GL_TEXTURE_BINDING_EXTERNAL
: LOCAL_GL_NONE;
MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
mGL->GetUIntegerv(bindingTarget, &mOldTex);
GLenum bindingTarget;
switch (texTarget) {
case LOCAL_GL_TEXTURE_2D:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D;
break;
case LOCAL_GL_TEXTURE_CUBE_MAP:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_CUBE_MAP;
break;
case LOCAL_GL_TEXTURE_3D:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_3D;
break;
case LOCAL_GL_TEXTURE_2D_ARRAY:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_2D_ARRAY;
break;
case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB;
break;
case LOCAL_GL_TEXTURE_EXTERNAL:
bindingTarget = LOCAL_GL_TEXTURE_BINDING_EXTERNAL;
break;
default:
MOZ_CRASH("bad texTarget");
}
GLuint ret = 0;
gl->GetUIntegerv(bindingTarget, &ret);
return ret;
}
ScopedBindTexture::ScopedBindTexture(GLContext* aGL, GLuint aNewTex, GLenum aTarget)
: ScopedGLWrapper<ScopedBindTexture>(aGL)
{
Init(aTarget);
mGL->fBindTexture(aTarget, aNewTex);
}
, mTarget(aTarget)
, mOldTex(GetBoundTexture(aGL, aTarget))
{
mGL->fBindTexture(mTarget, aNewTex);
}
void
ScopedBindTexture::UnwrapImpl()
{
// Check that we're not falling out of scope after the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
mGL->fBindTexture(mTarget, mOldTex);
}
@ -314,16 +336,16 @@ ScopedViewportRect::ScopedViewportRect(GLContext* aGL,
GLsizei width, GLsizei height)
: ScopedGLWrapper<ScopedViewportRect>(aGL)
{
mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
mGL->fViewport(x, y, width, height);
mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, mSavedViewportRect);
mGL->fViewport(x, y, width, height);
}
void ScopedViewportRect::UnwrapImpl()
{
mGL->fViewport(mSavedViewportRect[0],
mSavedViewportRect[1],
mSavedViewportRect[2],
mSavedViewportRect[3]);
mGL->fViewport(mSavedViewportRect[0],
mSavedViewportRect[1],
mSavedViewportRect[2],
mSavedViewportRect[3]);
}
/* ScopedScissorRect **********************************************************/
@ -333,22 +355,22 @@ ScopedScissorRect::ScopedScissorRect(GLContext* aGL,
GLsizei width, GLsizei height)
: ScopedGLWrapper<ScopedScissorRect>(aGL)
{
mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
mGL->fScissor(x, y, width, height);
mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
mGL->fScissor(x, y, width, height);
}
ScopedScissorRect::ScopedScissorRect(GLContext* aGL)
: ScopedGLWrapper<ScopedScissorRect>(aGL)
{
mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
mGL->fGetIntegerv(LOCAL_GL_SCISSOR_BOX, mSavedScissorRect);
}
void ScopedScissorRect::UnwrapImpl()
{
mGL->fScissor(mSavedScissorRect[0],
mSavedScissorRect[1],
mSavedScissorRect[2],
mSavedScissorRect[3]);
mGL->fScissor(mSavedScissorRect[0],
mSavedScissorRect[1],
mSavedScissorRect[2],
mSavedScissorRect[3]);
}
/* ScopedVertexAttribPointer **************************************************/
@ -459,6 +481,8 @@ ScopedGLDrawState::ScopedGLDrawState(GLContext* aGL)
ScopedGLDrawState::~ScopedGLDrawState()
{
MOZ_ASSERT(mGL->IsCurrent());
mGL->fScissor(scissorBox[0], scissorBox[1],
scissorBox[2], scissorBox[3]);
@ -524,5 +548,31 @@ ScopedPackAlignment::UnwrapImpl() {
}
}
////////////////////////////////////////////////////////////////////////
// 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);
}
}
void
ScopedUnpackAlignment::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, mOldVal);
}
} /* namespace gl */
} /* namespace mozilla */

View File

@ -45,6 +45,7 @@ protected:
public:
void Unwrap() {
MOZ_ASSERT(!mIsUnwrapped);
MOZ_ASSERT(IsContextCurrent(mGL));
Derived* derived = static_cast<Derived*>(this);
derived->UnwrapImpl();
@ -168,11 +169,8 @@ struct ScopedBindTexture
friend struct ScopedGLWrapper<ScopedBindTexture>;
protected:
GLuint mOldTex;
GLenum mTarget;
private:
void Init(GLenum aTarget);
const GLenum mTarget;
const GLuint mOldTex;
public:
ScopedBindTexture(GLContext* aGL, GLuint aNewTex,
@ -358,6 +356,23 @@ public:
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 */

View File

@ -414,6 +414,9 @@ private:
DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-DOM-blit-uploads",
WebGLDisableDOMBlitUploads, bool, false);
DECL_GFX_PREF(Live, "webgl.disabled", WebGLDisabled, bool, false);
DECL_GFX_PREF(Live, "webgl.enable-draft-extensions", WebGLDraftExtensionsEnabled, bool, false);
@ -427,6 +430,8 @@ private:
DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false);
DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true);
DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false);
// WARNING:
// Please make sure that you've added your new preference to the list above in alphabetical order.
// Please do not just append it to the end of the list.

View File

@ -4787,7 +4787,7 @@ nsImageRenderer::PrepareImage()
// prefer SurfaceFromElement as it's more reliable.
mImageElementSurface =
nsLayoutUtils::SurfaceFromElement(property->GetReferencedElement());
if (!mImageElementSurface.mSourceSurface) {
if (!mImageElementSurface.GetSourceSurface()) {
mPaintServerFrame = property->GetReferencedFrame();
if (!mPaintServerFrame) {
mPrepareResult = DrawResult::BAD_IMAGE;
@ -4872,7 +4872,8 @@ nsImageRenderer::ComputeIntrinsicSize()
appUnitsPerDevPixel));
}
} else {
NS_ASSERTION(mImageElementSurface.mSourceSurface, "Surface should be ready.");
NS_ASSERTION(mImageElementSurface.GetSourceSurface(),
"Surface should be ready.");
IntSize surfaceSize = mImageElementSurface.mSize;
result.SetSize(
nsSize(nsPresContext::CSSPixelsToAppUnits(surfaceSize.width),
@ -5113,9 +5114,9 @@ nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
return drawable.forget();
}
NS_ASSERTION(mImageElementSurface.mSourceSurface, "Surface should be ready.");
NS_ASSERTION(mImageElementSurface.GetSourceSurface(), "Surface should be ready.");
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(
mImageElementSurface.mSourceSurface,
mImageElementSurface.GetSourceSurface().get(),
mImageElementSurface.mSize);
return drawable.forget();
}

View File

@ -1137,7 +1137,7 @@ public:
* edge of the presshell area. The aPoint, aScreenRect and aFlags arguments
* function in a similar manner as RenderSelection.
*/
virtual already_AddRefed<SourceSurface>
virtual already_AddRefed<mozilla::gfx::SourceSurface>
RenderNode(nsIDOMNode* aNode,
nsIntRegion* aRegion,
nsIntPoint& aPoint,
@ -1160,7 +1160,7 @@ public:
* point isn't used because the position can be determined from the displayed
* frames.
*/
virtual already_AddRefed<SourceSurface>
virtual already_AddRefed<mozilla::gfx::SourceSurface>
RenderSelection(nsISelection* aSelection,
nsIntPoint& aPoint,
nsIntRect* aScreenRect,
@ -1279,7 +1279,7 @@ public:
nsCOMPtr<nsIContent> mOverrideContent;
bool mReleaseContent;
bool mPrimaryState;
explicit PointerCaptureInfo(nsIContent* aPendingContent, bool aPrimaryState) :
mPendingContent(aPendingContent), mReleaseContent(false), mPrimaryState(aPrimaryState)
{

View File

@ -7176,20 +7176,23 @@ nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
if (!principal)
return result;
ImageContainer *container = aElement->GetImageContainer();
ImageContainer* container = aElement->GetImageContainer();
if (!container)
return result;
AutoLockImage lockImage(container);
layers::Image* image = lockImage.GetImage();
if (!image) {
return result;
}
result.mSourceSurface = image->GetAsSourceSurface();
if (!result.mSourceSurface)
result.mLayersImage = lockImage.GetImage();
if (!result.mLayersImage)
return result;
if (aTarget) {
// They gave us a DrawTarget to optimize for, so even though we have a layers::Image,
// we should unconditionally grab a SourceSurface and try to optimize it.
result.mSourceSurface = result.mLayersImage->GetAsSourceSurface();
if (!result.mSourceSurface)
return result;
RefPtr<SourceSurface> opt = aTarget->OptimizeSourceSurface(result.mSourceSurface);
if (opt) {
result.mSourceSurface = opt;
@ -7198,7 +7201,7 @@ nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
result.mCORSUsed = aElement->GetCORSMode() != CORS_NONE;
result.mHasSize = true;
result.mSize = image->GetSize();
result.mSize = result.mLayersImage->GetSize();
result.mPrincipal = principal.forget();
result.mIsWriteOnly = false;
@ -8270,6 +8273,9 @@ nsLayoutUtils::IsAPZTestLoggingEnabled()
return gfxPrefs::APZTestLoggingEnabled();
}
////////////////////////////////////////
// SurfaceFromElementResult
nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
// Use safe default values here
: mIsWriteOnly(true)
@ -8280,6 +8286,18 @@ nsLayoutUtils::SurfaceFromElementResult::SurfaceFromElementResult()
{
}
const RefPtr<mozilla::gfx::SourceSurface>&
nsLayoutUtils::SurfaceFromElementResult::GetSourceSurface()
{
if (!mSourceSurface && mLayersImage) {
mSourceSurface = mLayersImage->GetAsSourceSurface();
}
return mSourceSurface;
}
////////////////////////////////////////
bool
nsLayoutUtils::IsNonWrapperBlock(nsIFrame* aFrame)
{

View File

@ -29,6 +29,7 @@
#include "Units.h"
#include "mozilla/ToString.h"
#include "nsHTMLReflowMetrics.h"
#include "ImageContainer.h"
#include <limits>
#include <algorithm>
@ -67,6 +68,7 @@ struct IntrinsicSize;
struct ContainerLayerParameters;
class WritingMode;
namespace dom {
class CanvasRenderingContext2D;
class DOMRectList;
class Element;
class HTMLImageElement;
@ -78,6 +80,7 @@ namespace gfx {
struct RectCornerRadii;
} // namespace gfx
namespace layers {
class Image;
class Layer;
} // namespace layers
} // namespace mozilla
@ -2098,10 +2101,25 @@ public:
};
struct SurfaceFromElementResult {
SurfaceFromElementResult();
friend class mozilla::dom::CanvasRenderingContext2D;
friend class nsLayoutUtils;
/* mSourceSurface will contain the resulting surface, or will be nullptr on error */
RefPtr<SourceSurface> mSourceSurface;
/* If SFEResult contains a valid surface, it either mLayersImage or mSourceSurface
* will be non-null, and GetSourceSurface() will not be null.
*
* For valid surfaces, mSourceSurface may be null if mLayersImage is non-null, but
* GetSourceSurface() will create mSourceSurface from mLayersImage when called.
*/
/* Video elements (at least) often are already decoded as layers::Images. */
RefPtr<mozilla::layers::Image> mLayersImage;
protected:
/* GetSourceSurface() fills this and returns its non-null value if this SFEResult
* was successful. */
RefPtr<mozilla::gfx::SourceSurface> mSourceSurface;
public:
/* Contains info for drawing when there is no mSourceSurface. */
DirectDrawInfo mDrawInfo;
@ -2123,6 +2141,13 @@ public:
bool mCORSUsed;
/* Whether the returned image contains premultiplied pixel data */
bool mIsPremultiplied;
// Methods:
SurfaceFromElementResult();
// Gets mSourceSurface, or makes a SourceSurface from mLayersImage.
const RefPtr<mozilla::gfx::SourceSurface>& GetSourceSurface();
};
static SurfaceFromElementResult SurfaceFromElement(mozilla::dom::Element *aElement,
@ -2647,7 +2672,7 @@ public:
/**
* Log a key/value pair for APZ testing during a paint.
* @param aManager The data will be written to the APZTestData associated
* @param aManager The data will be written to the APZTestData associated
* with this layer manager.
* @param aScrollId Identifies the scroll frame to which the data pertains.
* @param aKey The key under which to log the data.

View File

@ -4202,6 +4202,8 @@ pref("webgl.enable-privileged-extensions", false);
pref("webgl.bypass-shader-validation", false);
pref("webgl.enable-prototype-webgl2", false);
pref("webgl.disable-fail-if-major-performance-caveat", false);
pref("webgl.disable-DOM-blit-uploads", false);
pref("webgl.webgl2-compat-mode", false);
#ifdef RELEASE_BUILD
// Keep this disabled on Release and Beta for now. (see bug 1171228)

Some files were not shown because too many files have changed in this diff Show More