зеркало из https://github.com/mozilla/gecko-dev.git
677 строки
20 KiB
C++
677 строки
20 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "WebGLContext.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "GLContext.h"
|
|
#include "jsapi.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "nsIDOMDataContainerEvent.h"
|
|
#include "nsIDOMEvent.h"
|
|
#include "nsIScriptSecurityManager.h"
|
|
#include "nsIVariant.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "prprf.h"
|
|
#include "WebGLBuffer.h"
|
|
#include "WebGLExtensions.h"
|
|
#include "WebGLFramebuffer.h"
|
|
#include "WebGLProgram.h"
|
|
#include "WebGLTexture.h"
|
|
#include "WebGLVertexArray.h"
|
|
#include "WebGLContextUtils.h"
|
|
|
|
#include "mozilla/dom/ScriptSettings.h"
|
|
|
|
namespace mozilla {
|
|
|
|
using namespace gl;
|
|
|
|
bool
|
|
IsGLDepthFormat(TexInternalFormat webGLFormat)
|
|
{
|
|
return (webGLFormat == LOCAL_GL_DEPTH_COMPONENT ||
|
|
webGLFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
|
|
webGLFormat == LOCAL_GL_DEPTH_COMPONENT32);
|
|
}
|
|
|
|
bool
|
|
IsGLDepthStencilFormat(TexInternalFormat webGLFormat)
|
|
{
|
|
return (webGLFormat == LOCAL_GL_DEPTH_STENCIL ||
|
|
webGLFormat == LOCAL_GL_DEPTH24_STENCIL8);
|
|
}
|
|
|
|
bool
|
|
FormatHasAlpha(TexInternalFormat webGLFormat)
|
|
{
|
|
return webGLFormat == LOCAL_GL_RGBA ||
|
|
webGLFormat == LOCAL_GL_LUMINANCE_ALPHA ||
|
|
webGLFormat == LOCAL_GL_ALPHA ||
|
|
webGLFormat == LOCAL_GL_RGBA4 ||
|
|
webGLFormat == LOCAL_GL_RGB5_A1 ||
|
|
webGLFormat == LOCAL_GL_SRGB_ALPHA;
|
|
}
|
|
|
|
TexTarget
|
|
TexImageTargetToTexTarget(TexImageTarget texImageTarget)
|
|
{
|
|
switch (texImageTarget.get()) {
|
|
case LOCAL_GL_TEXTURE_2D:
|
|
return LOCAL_GL_TEXTURE_2D;
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
|
return LOCAL_GL_TEXTURE_CUBE_MAP;
|
|
default:
|
|
MOZ_ASSERT(false, "Bad texture conversion");
|
|
// Should be caught by the constructor for TexTarget
|
|
return LOCAL_GL_NONE;
|
|
}
|
|
}
|
|
|
|
GLComponents::GLComponents(TexInternalFormat format)
|
|
{
|
|
mComponents = 0;
|
|
|
|
switch (format.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;
|
|
}
|
|
|
|
/**
|
|
* Convert WebGL/ES format and type into GL internal
|
|
* format valid for underlying driver.
|
|
*/
|
|
void
|
|
DriverFormatsFromFormatAndType(GLContext* gl, TexInternalFormat webGLInternalFormat, TexType webGLType,
|
|
GLenum* out_driverInternalFormat, GLenum* out_driverFormat)
|
|
{
|
|
MOZ_ASSERT(out_driverInternalFormat);
|
|
MOZ_ASSERT(out_driverFormat);
|
|
|
|
// ES2 requires that format == internalformat; floating-point is
|
|
// indicated purely by the type that's loaded. For desktop GL, we
|
|
// have to specify a floating point internal format.
|
|
if (gl->IsGLES()) {
|
|
*out_driverFormat = *out_driverInternalFormat = webGLInternalFormat.get();
|
|
return;
|
|
}
|
|
|
|
GLenum internalFormat = LOCAL_GL_NONE;
|
|
GLenum format = LOCAL_GL_NONE;
|
|
|
|
if (webGLInternalFormat == LOCAL_GL_DEPTH_COMPONENT) {
|
|
format = LOCAL_GL_DEPTH_COMPONENT;
|
|
if (webGLType == LOCAL_GL_UNSIGNED_SHORT)
|
|
internalFormat = LOCAL_GL_DEPTH_COMPONENT16;
|
|
else if (webGLType == LOCAL_GL_UNSIGNED_INT)
|
|
internalFormat = LOCAL_GL_DEPTH_COMPONENT32;
|
|
} else if (webGLInternalFormat == LOCAL_GL_DEPTH_STENCIL) {
|
|
format = LOCAL_GL_DEPTH_STENCIL;
|
|
if (webGLType == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
|
|
internalFormat = LOCAL_GL_DEPTH24_STENCIL8;
|
|
} else {
|
|
switch (webGLType.get()) {
|
|
case LOCAL_GL_UNSIGNED_BYTE:
|
|
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
|
format = internalFormat = webGLInternalFormat.get();
|
|
break;
|
|
|
|
case LOCAL_GL_FLOAT:
|
|
switch (webGLInternalFormat.get()) {
|
|
case LOCAL_GL_RGBA:
|
|
format = LOCAL_GL_RGBA;
|
|
internalFormat = LOCAL_GL_RGBA32F;
|
|
break;
|
|
|
|
case LOCAL_GL_RGB:
|
|
format = LOCAL_GL_RGB;
|
|
internalFormat = LOCAL_GL_RGB32F;
|
|
break;
|
|
|
|
case LOCAL_GL_ALPHA:
|
|
format = LOCAL_GL_ALPHA;
|
|
internalFormat = LOCAL_GL_ALPHA32F_ARB;
|
|
break;
|
|
|
|
case LOCAL_GL_LUMINANCE:
|
|
format = LOCAL_GL_LUMINANCE;
|
|
internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
|
|
break;
|
|
|
|
case LOCAL_GL_LUMINANCE_ALPHA:
|
|
format = LOCAL_GL_LUMINANCE_ALPHA;
|
|
internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case LOCAL_GL_HALF_FLOAT_OES:
|
|
switch (webGLInternalFormat.get()) {
|
|
case LOCAL_GL_RGBA:
|
|
format = LOCAL_GL_RGBA;
|
|
internalFormat = LOCAL_GL_RGBA16F;
|
|
break;
|
|
|
|
case LOCAL_GL_RGB:
|
|
format = LOCAL_GL_RGB;
|
|
internalFormat = LOCAL_GL_RGB16F;
|
|
break;
|
|
|
|
case LOCAL_GL_ALPHA:
|
|
format = LOCAL_GL_ALPHA;
|
|
internalFormat = LOCAL_GL_ALPHA16F_ARB;
|
|
break;
|
|
|
|
case LOCAL_GL_LUMINANCE:
|
|
format = LOCAL_GL_LUMINANCE;
|
|
internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
|
|
break;
|
|
|
|
case LOCAL_GL_LUMINANCE_ALPHA:
|
|
format = LOCAL_GL_LUMINANCE_ALPHA;
|
|
internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Handle ES2 and GL differences when supporting sRGB internal formats. GL ES
|
|
// requires that format == internalformat, but GL will fail in this case.
|
|
// GL requires:
|
|
// format -> internalformat
|
|
// GL_RGB GL_SRGB_EXT
|
|
// GL_RGBA GL_SRGB_ALPHA_EXT
|
|
switch (webGLInternalFormat.get()) {
|
|
case LOCAL_GL_SRGB:
|
|
format = LOCAL_GL_RGB;
|
|
internalFormat = LOCAL_GL_SRGB;
|
|
break;
|
|
case LOCAL_GL_SRGB_ALPHA:
|
|
format = LOCAL_GL_RGBA;
|
|
internalFormat = LOCAL_GL_SRGB_ALPHA;
|
|
break;
|
|
}
|
|
}
|
|
|
|
MOZ_ASSERT(webGLInternalFormat != LOCAL_GL_NONE && internalFormat != LOCAL_GL_NONE,
|
|
"Coding mistake -- bad format/type passed?");
|
|
|
|
*out_driverInternalFormat = internalFormat;
|
|
*out_driverFormat = format;
|
|
}
|
|
|
|
GLenum
|
|
DriverTypeFromType(GLContext* gl, TexType webGLType)
|
|
{
|
|
GLenum type = webGLType.get();
|
|
|
|
if (gl->IsGLES())
|
|
return type;
|
|
|
|
// convert type for half float if not on GLES2
|
|
if (type == LOCAL_GL_HALF_FLOAT_OES) {
|
|
if (gl->IsSupported(gl::GLFeature::texture_half_float)) {
|
|
return LOCAL_GL_HALF_FLOAT;
|
|
} else {
|
|
MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
|
|
}
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
void
|
|
WebGLContext::GenerateWarning(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
|
|
GenerateWarning(fmt, ap);
|
|
|
|
va_end(ap);
|
|
}
|
|
|
|
void
|
|
WebGLContext::GenerateWarning(const char *fmt, va_list ap)
|
|
{
|
|
if (!ShouldGenerateWarnings())
|
|
return;
|
|
|
|
mAlreadyGeneratedWarnings++;
|
|
|
|
char buf[1024];
|
|
PR_vsnprintf(buf, 1024, fmt, ap);
|
|
|
|
// no need to print to stderr, as JS_ReportWarning takes care of this for us.
|
|
|
|
AutoJSContext cx;
|
|
JS_ReportWarning(cx, "WebGL: %s", buf);
|
|
if (!ShouldGenerateWarnings()) {
|
|
JS_ReportWarning(cx,
|
|
"WebGL: No further warnings will be reported for this WebGL context "
|
|
"(already reported %d warnings)", mAlreadyGeneratedWarnings);
|
|
}
|
|
}
|
|
|
|
bool
|
|
WebGLContext::ShouldGenerateWarnings() const
|
|
{
|
|
if (mMaxWarnings == -1) {
|
|
return true;
|
|
}
|
|
|
|
return mAlreadyGeneratedWarnings < mMaxWarnings;
|
|
}
|
|
|
|
CheckedUint32
|
|
WebGLContext::GetImageSize(GLsizei height,
|
|
GLsizei width,
|
|
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_neededByteLength
|
|
= height <= 0 ? 0 : (height-1) * checked_alignedRowSize + checked_plainRowSize;
|
|
|
|
return checked_neededByteLength;
|
|
}
|
|
|
|
void
|
|
WebGLContext::SynthesizeGLError(GLenum err)
|
|
{
|
|
/* ES2 section 2.5 "GL Errors" states that implementations can have
|
|
* multiple 'flags', as errors might be caught in different parts of
|
|
* a distributed implementation.
|
|
* We're signing up as a distributed implementation here, with
|
|
* separate flags for WebGL and the underlying GLContext.
|
|
*/
|
|
if (!mWebGLError)
|
|
mWebGLError = err;
|
|
}
|
|
|
|
void
|
|
WebGLContext::SynthesizeGLError(GLenum err, const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(err);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorInvalidEnum(const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(LOCAL_GL_INVALID_ENUM);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorInvalidEnumInfo(const char *info, GLenum enumvalue)
|
|
{
|
|
return ErrorInvalidEnum("%s: invalid enum value 0x%x", info, enumvalue);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorInvalidOperation(const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(LOCAL_GL_INVALID_OPERATION);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorInvalidValue(const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(LOCAL_GL_INVALID_VALUE);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorInvalidFramebufferOperation(const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
|
|
}
|
|
|
|
void
|
|
WebGLContext::ErrorOutOfMemory(const char *fmt, ...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
GenerateWarning(fmt, va);
|
|
va_end(va);
|
|
|
|
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
|
|
}
|
|
|
|
const char *
|
|
WebGLContext::ErrorName(GLenum error)
|
|
{
|
|
switch(error) {
|
|
case LOCAL_GL_INVALID_ENUM:
|
|
return "INVALID_ENUM";
|
|
case LOCAL_GL_INVALID_OPERATION:
|
|
return "INVALID_OPERATION";
|
|
case LOCAL_GL_INVALID_VALUE:
|
|
return "INVALID_VALUE";
|
|
case LOCAL_GL_OUT_OF_MEMORY:
|
|
return "OUT_OF_MEMORY";
|
|
case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
|
|
return "INVALID_FRAMEBUFFER_OPERATION";
|
|
case LOCAL_GL_NO_ERROR:
|
|
return "NO_ERROR";
|
|
default:
|
|
MOZ_ASSERT(false);
|
|
return "[unknown WebGL error!]";
|
|
}
|
|
}
|
|
|
|
const char*
|
|
WebGLContext::EnumName(GLenum glenum)
|
|
{
|
|
switch (glenum) {
|
|
#define XX(x) case LOCAL_GL_##x: return #x
|
|
XX(ALPHA);
|
|
XX(ATC_RGB);
|
|
XX(ATC_RGBA_EXPLICIT_ALPHA);
|
|
XX(ATC_RGBA_INTERPOLATED_ALPHA);
|
|
XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
|
|
XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
|
|
XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
|
|
XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
|
|
XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
|
|
XX(COMPRESSED_RGB_PVRTC_2BPPV1);
|
|
XX(COMPRESSED_RGB_PVRTC_4BPPV1);
|
|
XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
|
|
XX(DEPTH_COMPONENT);
|
|
XX(DEPTH_COMPONENT16);
|
|
XX(DEPTH_COMPONENT32);
|
|
XX(DEPTH_STENCIL);
|
|
XX(DEPTH24_STENCIL8);
|
|
XX(ETC1_RGB8_OES);
|
|
XX(FLOAT);
|
|
XX(HALF_FLOAT);
|
|
XX(LUMINANCE);
|
|
XX(LUMINANCE_ALPHA);
|
|
XX(RGB);
|
|
XX(RGB16F);
|
|
XX(RGB32F);
|
|
XX(RGBA);
|
|
XX(RGBA16F);
|
|
XX(RGBA32F);
|
|
XX(SRGB);
|
|
XX(SRGB_ALPHA);
|
|
XX(TEXTURE_2D);
|
|
XX(TEXTURE_3D);
|
|
XX(TEXTURE_CUBE_MAP);
|
|
XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
|
|
XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
|
|
XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
|
XX(TEXTURE_CUBE_MAP_POSITIVE_X);
|
|
XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
|
|
XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
|
|
XX(UNSIGNED_BYTE);
|
|
XX(UNSIGNED_INT);
|
|
XX(UNSIGNED_INT_24_8);
|
|
XX(UNSIGNED_SHORT);
|
|
XX(UNSIGNED_SHORT_4_4_4_4);
|
|
XX(UNSIGNED_SHORT_5_5_5_1);
|
|
XX(UNSIGNED_SHORT_5_6_5);
|
|
#undef XX
|
|
}
|
|
|
|
return "[Unknown enum name]";
|
|
}
|
|
|
|
|
|
bool
|
|
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
|
|
{
|
|
switch (format.get()) {
|
|
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
|
case LOCAL_GL_ATC_RGB:
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
|
|
case LOCAL_GL_ETC1_RGB8_OES:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
GLenum
|
|
WebGLContext::GetAndFlushUnderlyingGLErrors()
|
|
{
|
|
// Get and clear GL error in ALL cases.
|
|
GLenum error = gl->GetAndClearError();
|
|
|
|
// Only store in mUnderlyingGLError if is hasn't already recorded an
|
|
// error.
|
|
if (!mUnderlyingGLError)
|
|
mUnderlyingGLError = error;
|
|
|
|
return error;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// For NaNs, etc.
|
|
static bool
|
|
IsCacheCorrect(float cached, float actual)
|
|
{
|
|
if (IsNaN(cached)) {
|
|
// GL is allowed to do anything it wants for NaNs, so if we're shadowing
|
|
// a NaN, then whatever `actual` is might be correct.
|
|
return true;
|
|
}
|
|
|
|
return cached == actual;
|
|
}
|
|
|
|
void
|
|
AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow)
|
|
{
|
|
GLuint val = 0;
|
|
gl->GetUIntegerv(pname, &val);
|
|
if (val != shadow) {
|
|
printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
|
|
pname, shadow, shadow, val, val);
|
|
MOZ_ASSERT(false, "Bad cached value.");
|
|
}
|
|
}
|
|
#else
|
|
void
|
|
AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void
|
|
WebGLContext::AssertCachedBindings()
|
|
{
|
|
#ifdef DEBUG
|
|
MakeContextCurrent();
|
|
|
|
GetAndFlushUnderlyingGLErrors();
|
|
|
|
if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
|
|
GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
|
|
}
|
|
|
|
// Bound object state
|
|
GLuint bound = mBoundFramebuffer ? mBoundFramebuffer->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
|
|
|
|
bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
|
|
|
|
// Textures
|
|
GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);
|
|
|
|
WebGLTexture* curTex = activeBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
|
|
bound = curTex ? curTex->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound);
|
|
|
|
curTex = activeBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP);
|
|
bound = curTex ? curTex->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound);
|
|
|
|
// Buffers
|
|
bound = mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound);
|
|
|
|
MOZ_ASSERT(mBoundVertexArray);
|
|
WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer;
|
|
bound = curBuff ? curBuff->GLName() : 0;
|
|
AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound);
|
|
|
|
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
|
|
#endif
|
|
}
|
|
|
|
void
|
|
WebGLContext::AssertCachedState()
|
|
{
|
|
#ifdef DEBUG
|
|
MakeContextCurrent();
|
|
|
|
GetAndFlushUnderlyingGLErrors();
|
|
|
|
// extensions
|
|
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
|
|
AssertUintParamCorrect(gl, LOCAL_GL_MAX_COLOR_ATTACHMENTS, mGLMaxColorAttachments);
|
|
AssertUintParamCorrect(gl, LOCAL_GL_MAX_DRAW_BUFFERS, mGLMaxDrawBuffers);
|
|
}
|
|
|
|
// Draw state
|
|
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
|
|
MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
|
|
MOZ_ASSERT_IF(IsWebGL2(),
|
|
gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
|
|
|
|
|
|
realGLboolean colorWriteMask[4] = {0, 0, 0, 0};
|
|
gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
|
|
MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
|
|
colorWriteMask[1] == mColorWriteMask[1] &&
|
|
colorWriteMask[2] == mColorWriteMask[2] &&
|
|
colorWriteMask[3] == mColorWriteMask[3]);
|
|
|
|
GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
|
|
MOZ_ASSERT(IsCacheCorrect(mColorClearValue[0], colorClearValue[0]) &&
|
|
IsCacheCorrect(mColorClearValue[1], colorClearValue[1]) &&
|
|
IsCacheCorrect(mColorClearValue[2], colorClearValue[2]) &&
|
|
IsCacheCorrect(mColorClearValue[3], colorClearValue[3]));
|
|
|
|
realGLboolean depthWriteMask = 0;
|
|
gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
|
|
MOZ_ASSERT(depthWriteMask == mDepthWriteMask);
|
|
|
|
GLfloat depthClearValue = 0.0f;
|
|
gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
|
|
MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue));
|
|
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
|
|
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, mStencilRefFront);
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, mStencilRefBack);
|
|
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
|
|
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront);
|
|
AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
|
|
|
|
// Viewport
|
|
GLint int4[4] = {0, 0, 0, 0};
|
|
gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4);
|
|
MOZ_ASSERT(int4[0] == mViewportX &&
|
|
int4[1] == mViewportY &&
|
|
int4[2] == mViewportWidth &&
|
|
int4[3] == mViewportHeight);
|
|
|
|
AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStorePackAlignment);
|
|
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStoreUnpackAlignment);
|
|
|
|
MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
|
|
#endif
|
|
}
|
|
|
|
} // namespace mozilla
|