Bug 1072680 - Untangle the mixup of formats vs internalformats in the WebGL implementation - r=jgilbert

This commit is contained in:
Benoit Jacob 2014-10-04 22:24:24 -04:00
parent bbaadc6b16
commit 2ff4bedf68
4 changed files with 245 additions and 158 deletions

View File

@ -17,6 +17,7 @@
#include "WebGLActiveInfo.h"
#include "WebGLObjectModel.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
#include "WebGLStrongTypes.h"
#include <stdarg.h>
@ -221,6 +222,7 @@ public:
*/
static const char *EnumName(GLenum glenum);
bool IsCompressedTextureFormat(GLenum format);
bool IsTextureFormatCompressed(TexInternalFormat format);
void DummyFramebufferOperation(const char *info);
@ -543,9 +545,12 @@ public:
// Allow whatever element types the bindings are willing to pass
// us in TexSubImage2D
template<class ElementType>
void TexSubImage2D(GLenum rawTexImageTarget, GLint level,
GLint xoffset, GLint yoffset, GLenum format,
GLenum type, ElementType& elt, ErrorResult& rv)
void TexSubImage2D(GLenum rawTexImageTarget,
GLint level,
GLint xoffset, GLint yoffset,
GLenum format,
GLenum type,
ElementType& elt, ErrorResult& rv)
{
if (IsContextLost())
return;
@ -565,8 +570,17 @@ public:
if (level > maxLevel)
return ErrorInvalidValue("texSubImage2D: level %d is too large, max is %d", level, maxLevel);
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
}
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
const TexInternalFormat internalformat = imageInfo.InternalFormat();
// Trying to handle the video by GPU directly first
if (TexImageFromVideoElement(texImageTarget, level, format, format, type, elt)) {
if (TexImageFromVideoElement(texImageTarget, level,
internalformat.get(), format, type, elt))
{
return;
}
@ -580,7 +594,7 @@ public:
gfx::IntSize size = data->GetSize();
uint32_t byteLength = data->Stride() * size.height;
return TexSubImage2D_base(texImageTarget, level, xoffset, yoffset,
return TexSubImage2D_base(texImageTarget.get(), level, xoffset, yoffset,
size.width, size.height,
data->Stride(), format, type,
data->GetData(), byteLength,
@ -1073,7 +1087,7 @@ protected:
// -------------------------------------------------------------------------
// Validation functions (implemented in WebGLContextValidate.cpp)
TexFormat BaseTexFormat(TexInternalFormat internalFormat) const;
TexInternalFormat BaseTexFormat(TexInternalFormat internalFormat) const;
bool CreateOffscreenGL(bool forceEnabled);
bool InitAndValidateGL();
@ -1095,7 +1109,8 @@ protected:
bool ValidateGLSLCharacter(char16_t c);
bool ValidateGLSLString(const nsAString& string, const char *info);
bool ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func);
bool ValidateCopyTexImage(GLenum internalformat,
WebGLTexImageFunc func);
bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
GLint level, GLenum internalFormat,
GLint xoffset, GLint yoffset, GLint zoffset,
@ -1103,9 +1118,14 @@ protected:
GLint border, GLenum format, GLenum type,
WebGLTexImageFunc func);
bool ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func);
bool ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func);
bool ValidateTexImageFormat(GLenum internalformat,
WebGLTexImageFunc func);
bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func);
bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func);
bool ValidateCompTexImageInternalFormat(GLenum format,
WebGLTexImageFunc func);
bool ValidateCopyTexImageInternalFormat(GLenum format,
WebGLTexImageFunc func);
bool ValidateTexImageSize(TexImageTarget target, GLint level,
GLint width, GLint height, GLint depth,
WebGLTexImageFunc func);
@ -1114,16 +1134,17 @@ protected:
GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth,
WebGLTexImageFunc func);
bool ValidateCompTexImageSize(GLint level, GLenum format,
bool ValidateCompTexImageSize(GLint level,
GLenum internalformat,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLsizei levelWidth, GLsizei levelHeight,
WebGLTexImageFunc func);
bool ValidateCompTexImageDataSize(GLint level, GLenum format,
bool ValidateCompTexImageDataSize(GLint level,
GLenum internalformat,
GLsizei width, GLsizei height,
uint32_t byteLength, WebGLTexImageFunc func);
static uint32_t GetBitsPerTexel(TexInternalFormat format, TexType type);
void Invalidate();
@ -1132,16 +1153,20 @@ protected:
void MakeContextCurrent() const;
// helpers
void TexImage2D_base(TexImageTarget target, GLint level, GLenum internalformat,
void TexImage2D_base(TexImageTarget target,
GLint level,
GLenum internalformat,
GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border,
GLenum format, GLenum type,
GLenum format,
GLenum type,
void *data, uint32_t byteLength,
int jsArrayType,
WebGLTexelFormat srcFormat, bool srcPremultiplied);
void TexSubImage2D_base(TexImageTarget target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
GLenum format, GLenum type,
GLenum format,
GLenum type,
void *pixels, uint32_t byteLength,
int jsArrayType,
WebGLTexelFormat srcFormat, bool srcPremultiplied);
@ -1227,12 +1252,12 @@ protected:
* by this glTexImage2D call and returns it */
GLenum CheckedTexImage2D(TexImageTarget texImageTarget,
GLint level,
GLenum internalFormat,
TexInternalFormat internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
TexFormat format,
TexType type,
const GLvoid *data);
void ForceLoseContext(bool simulateLosing = false);

View File

@ -375,7 +375,8 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
if (!ValidateTexImage(2, texImageTarget, level, internalformat,
xoffset, yoffset, 0,
width, height, 0,
0, internalformat, LOCAL_GL_UNSIGNED_BYTE,
0,
LOCAL_GL_NONE, LOCAL_GL_NONE,
func))
{
return;
@ -478,22 +479,20 @@ WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
// copyTexImage2D only generates textures with type = UNSIGNED_BYTE
const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
const GLenum format = internalformat; // WebGL/ES Format
const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format
if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage))
return;
if (!ValidateTexImage(2, rawTexImgTarget, level, format,
if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
0, 0, 0,
width, height, 0,
border, format, type,
border, LOCAL_GL_NONE, LOCAL_GL_NONE,
func))
{
return;
}
if (!ValidateCopyTexImage(format, func))
if (!ValidateCopyTexImage(internalformat, func))
return;
if (!mBoundFramebuffer)
@ -509,14 +508,13 @@ WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
sizeMayChange = width != imageInfo.Width() ||
height != imageInfo.Height() ||
internalformat != imageInfo.InternalFormat() ||
type != imageInfo.Type();
internalformat != imageInfo.InternalFormat();
}
if (sizeMayChange)
GetAndFlushUnderlyingGLErrors();
CopyTexSubImage2D_base(texImageTarget, level, format, 0, 0, x, y, width, height, false);
CopyTexSubImage2D_base(texImageTarget, level, internalformat, 0, 0, x, y, width, height, false);
if (sizeMayChange) {
GLenum error = GetAndFlushUnderlyingGLErrors();
@ -526,7 +524,10 @@ WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
}
}
tex->SetImageInfo(texImageTarget, level, width, height, internalformat, type,
tex->SetImageInfo(texImageTarget, level, width, height,
internalformat,
LOCAL_GL_UNSIGNED_BYTE, /* dummy, artifact of us storing
the wrong data in ImageInfo */
WebGLImageDataStatus::InitializedImageData);
}
@ -3298,7 +3299,9 @@ WebGLContext::CompileShader(WebGLShader *shader)
}
void
WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum internalformat,
WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
GLint level,
GLenum internalformat,
GLsizei width, GLsizei height, GLint border,
const ArrayBufferView& view)
{
@ -3312,7 +3315,8 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum i
if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
0, 0, 0, width, height, 0,
border, internalformat, LOCAL_GL_UNSIGNED_BYTE,
border, LOCAL_GL_NONE,
LOCAL_GL_NONE,
func))
{
return;
@ -3343,7 +3347,8 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget, GLint level, GLenum i
void
WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset,
GLint yoffset, GLsizei width, GLsizei height,
GLenum format, const ArrayBufferView& view)
GLenum internalformat,
const ArrayBufferView& view)
{
if (IsContextLost())
return;
@ -3354,10 +3359,10 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
return;
if (!ValidateTexImage(2, rawTexImgTarget,
level, format,
level, internalformat,
xoffset, yoffset, 0,
width, height, 0,
0, format, LOCAL_GL_UNSIGNED_BYTE,
0, LOCAL_GL_NONE, LOCAL_GL_NONE,
func))
{
return;
@ -3369,13 +3374,17 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
MOZ_ASSERT(tex);
WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(texImageTarget, level);
if (internalformat != levelInfo.InternalFormat()) {
return ErrorInvalidOperation("compressedTexImage2D: internalformat does not match the existing image");
}
view.ComputeLengthAndData();
uint32_t byteLength = view.Length();
if (!ValidateCompTexImageDataSize(level, format, width, height, byteLength, func))
if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
return;
if (!ValidateCompTexImageSize(level, format,
if (!ValidateCompTexImageSize(level, internalformat,
xoffset, yoffset,
width, height,
levelInfo.Width(), levelInfo.Height(),
@ -3388,7 +3397,7 @@ WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint
tex->DoDeferredImageInitialization(texImageTarget, level);
MakeContextCurrent();
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, format, byteLength, view.Data());
gl->fCompressedTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, internalformat, byteLength, view.Data());
}
JS::Value
@ -3577,15 +3586,14 @@ WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval)
GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
GLint level,
GLenum internalFormat,
TexInternalFormat internalFormat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
TexFormat format,
TexType type,
const GLvoid *data)
{
MOZ_ASSERT(internalFormat == format);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
MOZ_ASSERT(tex != nullptr, "no texture bound");
@ -3595,15 +3603,14 @@ GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
sizeMayChange = width != imageInfo.Width() ||
height != imageInfo.Height() ||
format != imageInfo.InternalFormat() ||
type != imageInfo.Type();
internalFormat != imageInfo.InternalFormat();
}
// Convert to format and type required by OpenGL 'driver'.
GLenum driverType = DriverTypeFromType(gl, type);
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
DriverFormatsFromFormatAndType(gl, internalFormat, type, &driverInternalFormat, &driverFormat);
if (sizeMayChange) {
GetAndFlushUnderlyingGLErrors();
@ -3620,10 +3627,12 @@ GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
}
void
WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum internalformat,
WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
GLenum internalformat,
GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
GLint border,
GLenum format, GLenum type,
GLenum format,
GLenum type,
void* data, uint32_t byteLength,
int jsArrayType, // a TypedArray format enum, or -1 if not relevant
WebGLTexelFormat srcFormat, bool srcPremultiplied)
@ -3652,7 +3661,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum
if (!ValidateTexInputData(type, jsArrayType, func))
return;
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@ -3686,7 +3695,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level, GLenum
if (byteLength) {
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
size_t dstPlainRowSize = dstTexelSize * width;
size_t unpackAlignment = mPixelStoreUnpackAlignment;
size_t dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
@ -3803,7 +3812,14 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
{
const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
if (!ValidateTexImage(2, texImageTarget, level, format,
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
if (!tex) {
return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
}
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
const TexInternalFormat internalformat = imageInfo.InternalFormat();
if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
xoffset, yoffset, 0,
width, height, 0,
0, format, type, func))
@ -3814,7 +3830,11 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
if (!ValidateTexInputData(type, jsArrayType, func))
return;
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
if (imageInfo.Type() != type) {
return ErrorInvalidOperation("texSubImage2D: type parameter does not match the existing image");
}
WebGLTexelFormat dstFormat = GetWebGLTexelFormat(internalformat, type);
WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
@ -3838,16 +3858,13 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
if (byteLength < bytesNeeded)
return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(texImageTarget, level);
if (imageInfo.HasUninitializedImageData())
tex->DoDeferredImageInitialization(texImageTarget, level);
MakeContextCurrent();
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
uint32_t dstTexelSize = GetBitsPerTexel(internalformat, type) / 8;
size_t dstPlainRowSize = dstTexelSize * width;
// There are checks above to ensure that this won't overflow.
size_t dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
@ -3874,7 +3891,7 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
GLenum driverType = DriverTypeFromType(gl, type);
GLenum driverInternalFormat = LOCAL_GL_NONE;
GLenum driverFormat = LOCAL_GL_NONE;
DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
DriverFormatsFromFormatAndType(gl, internalformat, type, &driverInternalFormat, &driverFormat);
gl->fTexSubImage2D(texImageTarget.get(), level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
}

View File

@ -490,11 +490,10 @@ WebGLContext::EnumName(GLenum glenum)
return "[Unknown enum name]";
}
bool
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
WebGLContext::IsCompressedTextureFormat(GLenum format)
{
switch (format.get()) {
switch (format) {
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
@ -513,6 +512,13 @@ WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
}
}
bool
WebGLContext::IsTextureFormatCompressed(TexInternalFormat format)
{
return IsCompressedTextureFormat(format.get());
}
GLenum
WebGLContext::GetAndFlushUnderlyingGLErrors()
{

View File

@ -82,6 +82,13 @@ InfoFrom(WebGLTexImageFunc func)
}
}
static bool
IsCompressedFunc(WebGLTexImageFunc func)
{
return func == WebGLTexImageFunc::CompTexImage ||
func == WebGLTexImageFunc::CompTexSubImage;
}
/**
* Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
* name for \a glenum.
@ -248,7 +255,7 @@ WebGLProgram::UpdateInfo()
* \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
* GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA), or GL_NONE if invalid enum.
*/
TexFormat
TexInternalFormat
WebGLContext::BaseTexFormat(TexInternalFormat internalFormat) const
{
if (internalFormat == LOCAL_GL_ALPHA ||
@ -257,56 +264,56 @@ WebGLContext::BaseTexFormat(TexInternalFormat internalFormat) const
internalFormat == LOCAL_GL_RGB ||
internalFormat == LOCAL_GL_RGBA)
{
return TexFormat(internalFormat.get());
return internalFormat;
}
if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
if (internalFormat == LOCAL_GL_SRGB)
return TexFormat(LOCAL_GL_RGB);
return LOCAL_GL_RGB;
if (internalFormat == LOCAL_GL_SRGB_ALPHA)
return TexFormat(LOCAL_GL_RGBA);
return LOCAL_GL_RGBA;
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc)) {
if (internalFormat == LOCAL_GL_ATC_RGB)
return TexFormat(LOCAL_GL_RGB);
return LOCAL_GL_RGB;
if (internalFormat == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
internalFormat == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
{
return TexFormat(LOCAL_GL_RGBA);
return LOCAL_GL_RGBA;
}
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1)) {
if (internalFormat == LOCAL_GL_ETC1_RGB8_OES)
return TexFormat(LOCAL_GL_RGB);
return LOCAL_GL_RGB;
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) {
if (internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1)
{
return TexFormat(LOCAL_GL_RGB);
return LOCAL_GL_RGB;
}
if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
{
return TexFormat(LOCAL_GL_RGBA);
return LOCAL_GL_RGBA;
}
}
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc)) {
if (internalFormat == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
return TexFormat(LOCAL_GL_RGB);
return LOCAL_GL_RGB;
if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
return TexFormat(LOCAL_GL_RGBA);
return LOCAL_GL_RGBA;
}
}
@ -315,13 +322,13 @@ WebGLContext::BaseTexFormat(TexInternalFormat internalFormat) const
internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
internalFormat == LOCAL_GL_DEPTH_COMPONENT32)
{
return TexFormat(LOCAL_GL_DEPTH_COMPONENT);
return LOCAL_GL_DEPTH_COMPONENT;
}
if (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
internalFormat == LOCAL_GL_DEPTH24_STENCIL8)
{
return TexFormat(LOCAL_GL_DEPTH_STENCIL);
return LOCAL_GL_DEPTH_STENCIL;
}
}
@ -608,53 +615,6 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
return validFormat;
}
/* WEBGL_compressed_texture_atc added formats */
if (format == LOCAL_GL_ATC_RGB ||
format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
// WEBGL_compressed_texture_etc1
if (format == LOCAL_GL_ETC1_RGB8_OES) {
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
ErrorInvalidEnumWithName(this, "invalid format", format, func);
return false;
@ -664,7 +624,9 @@ WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
* Check if the given texture target is valid for TexImage.
*/
bool
WebGLContext::ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func)
WebGLContext::ValidateTexImageTarget(GLuint dims,
GLenum target,
WebGLTexImageFunc func)
{
switch (dims) {
case 2:
@ -689,7 +651,8 @@ WebGLContext::ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFu
* taking into account enabled WebGL extensions.
*/
bool
WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func)
WebGLContext::ValidateTexImageType(GLenum type,
WebGLTexImageFunc func)
{
/* Core WebGL texture types */
if (type == LOCAL_GL_UNSIGNED_BYTE ||
@ -740,7 +703,8 @@ WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func)
*/
// TODO: WebGL 2
bool
WebGLContext::ValidateCompTexImageSize(GLint level, GLenum format,
WebGLContext::ValidateCompTexImageSize(GLint level,
GLenum format,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height,
GLsizei levelWidth, GLsizei levelHeight,
@ -1155,8 +1119,14 @@ WebGLContext::GetBitsPerTexel(TexInternalFormat format, TexType type)
* Returns true if the format/type is a valid combination, false otherwise.
*/
bool
WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func)
WebGLContext::ValidateTexImageFormatAndType(GLenum format,
GLenum type, WebGLTexImageFunc func)
{
if (IsCompressedFunc(func) || IsCopyFunc(func))
{
MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
return true;
}
if (!ValidateTexImageFormat(format, func) ||
!ValidateTexImageType(type, func))
{
@ -1203,21 +1173,6 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTex
validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
break;
case LOCAL_GL_ATC_RGB:
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
case LOCAL_GL_ETC1_RGB8_OES:
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
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:
validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
break;
default:
// Only valid formats should be passed to the switch stmt.
MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
@ -1233,6 +1188,89 @@ WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTex
return validCombo;
}
bool
WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
WebGLTexImageFunc func)
{
if (!IsCompressedTextureFormat(format)) {
ErrorInvalidEnum("%s: invalid compressed texture format: %s",
InfoFrom(func), WebGLContext::EnumName(format));
return false;
}
/* WEBGL_compressed_texture_atc added formats */
if (format == LOCAL_GL_ATC_RGB ||
format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
// WEBGL_compressed_texture_etc1
if (format == LOCAL_GL_ETC1_RGB8_OES) {
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
{
bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
if (!validFormat)
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
InfoFrom(func), WebGLContext::EnumName(format));
return validFormat;
}
return false;
}
bool
WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
WebGLTexImageFunc func)
{
bool valid = format == LOCAL_GL_RGBA ||
format == LOCAL_GL_RGB ||
format == LOCAL_GL_LUMINANCE_ALPHA ||
format == LOCAL_GL_LUMINANCE ||
format == LOCAL_GL_ALPHA;
if (!valid)
{
// in CopyTexImage, the internalformat is a function parameter,
// so a bad value is an INVALID_ENUM error.
// in CopyTexSubImage, the internalformat is part of existing state,
// so this is an INVALID_OPERATION error.
GenerateWarning("%s: invalid texture internal format: %s",
InfoFrom(func), WebGLContext::EnumName(format));
SynthesizeGLError(func == WebGLTexImageFunc::CopyTexImage
? LOCAL_GL_INVALID_ENUM
: LOCAL_GL_INVALID_OPERATION);
}
return valid;
}
/**
* Return true if format, type and jsArrayType are a valid combination.
* Also returns the size for texel of format and type (in bytes) via
@ -1287,7 +1325,8 @@ WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFu
* - Copy format is a subset of framebuffer format (i.e. all required components are available)
*/
bool
WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func)
WebGLContext::ValidateCopyTexImage(GLenum format,
WebGLTexImageFunc func)
{
MOZ_ASSERT(IsCopyFunc(func));
@ -1332,10 +1371,13 @@ WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func)
// TODO: Texture dims is here for future expansion in WebGL 2.0
bool
WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
GLint level, GLenum internalFormat,
GLint level,
GLenum internalFormat,
GLint xoffset, GLint yoffset, GLint zoffset,
GLint width, GLint height, GLint depth,
GLint border, GLenum format, GLenum type,
GLint border,
GLenum format,
GLenum type,
WebGLTexImageFunc func)
{
const char* info = InfoFrom(func);
@ -1356,13 +1398,21 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
if (!ValidateTexImageFormatAndType(format, type, func))
return false;
if (IsCompressedFunc(func)) {
if (!ValidateCompTexImageInternalFormat(internalFormat, func)) {
return false;
}
} else if (IsCopyFunc(func)) {
if (!ValidateCopyTexImageInternalFormat(internalFormat, func)) {
return false;
}
} else if (format != internalFormat) {
/* WebGL and OpenGL ES 2.0 impose additional restrictions on the
* combinations of format, internalFormat, and type that can be
* used. Formats and types that require additional extensions
* (e.g., GL_FLOAT requires GL_OES_texture_float) are filtered
* elsewhere.
*/
if (format != internalFormat) {
ErrorInvalidOperation("%s: format does not match internalformat", info);
return false;
}
@ -1406,17 +1456,6 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
{
return false;
}
/* Require the format and type to match that of the existing
* texture as created
*/
if (imageInfo.InternalFormat() != internalFormat ||
imageInfo.Type() != type)
{
ErrorInvalidOperation("%s: format or type doesn't match the existing texture",
info);
return false;
}
}
/* Additional checks for depth textures */
@ -1430,7 +1469,7 @@ WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
}
/* Additional checks for compressed textures */
if (!IsAllowedFromSource(format, func)) {
if (!IsAllowedFromSource(internalFormat, func)) {
ErrorInvalidOperation("%s: Invalid format %s for this operation",
info, WebGLContext::EnumName(format));
return false;