2009-09-03 00:47:49 +00:00
|
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2012-05-21 11:12:37 +00:00
|
|
|
|
/* 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/. */
|
2009-09-18 06:01:12 +00:00
|
|
|
|
|
2009-09-03 00:47:49 +00:00
|
|
|
|
#include "WebGLContext.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include "angle/ShaderLang.h"
|
|
|
|
|
#include "CanvasUtils.h"
|
|
|
|
|
#include "GLContext.h"
|
|
|
|
|
#include "jsfriendapi.h"
|
|
|
|
|
#include "mozilla/CheckedInt.h"
|
|
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
|
#include "mozilla/Services.h"
|
|
|
|
|
#include "nsIObserverService.h"
|
2013-06-10 20:00:35 +00:00
|
|
|
|
#include "WebGLBuffer.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#include "WebGLContextUtils.h"
|
2013-06-10 20:00:35 +00:00
|
|
|
|
#include "WebGLFramebuffer.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#include "WebGLProgram.h"
|
2013-06-10 20:00:35 +00:00
|
|
|
|
#include "WebGLRenderbuffer.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#include "WebGLShader.h"
|
2013-06-10 20:00:35 +00:00
|
|
|
|
#include "WebGLTexture.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#include "WebGLUniformLocation.h"
|
2013-06-27 21:07:21 +00:00
|
|
|
|
#include "WebGLVertexArray.h"
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#include "WebGLVertexAttribData.h"
|
2012-03-02 20:42:49 +00:00
|
|
|
|
|
2014-10-22 20:57:53 +00:00
|
|
|
|
#if defined(MOZ_WIDGET_COCOA)
|
|
|
|
|
#include "nsCocoaFeatures.h"
|
|
|
|
|
#endif
|
2012-04-21 20:48:22 +00:00
|
|
|
|
|
2009-09-03 00:47:49 +00:00
|
|
|
|
using namespace mozilla;
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the block size for format.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
BlockSizeFor(GLenum format, GLint* blockWidth, GLint* blockHeight)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(blockWidth && blockHeight);
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case LOCAL_GL_ATC_RGB:
|
|
|
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
|
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
|
|
|
|
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:
|
|
|
|
|
if (blockWidth)
|
|
|
|
|
*blockWidth = 4;
|
|
|
|
|
if (blockHeight)
|
|
|
|
|
*blockHeight = 4;
|
|
|
|
|
break;
|
2014-03-10 22:42:58 +00:00
|
|
|
|
|
|
|
|
|
case LOCAL_GL_ETC1_RGB8_OES:
|
|
|
|
|
// 4x4 blocks, but no 4-multiple requirement.
|
2014-02-21 01:20:28 +00:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-05 02:24:24 +00:00
|
|
|
|
static bool
|
|
|
|
|
IsCompressedFunc(WebGLTexImageFunc func)
|
|
|
|
|
{
|
|
|
|
|
return func == WebGLTexImageFunc::CompTexImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CompTexSubImage;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
2014-06-02 20:30:00 +00:00
|
|
|
|
* Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
|
2014-02-21 01:20:28 +00:00
|
|
|
|
* name for \a glenum.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func, WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
2014-06-02 20:30:00 +00:00
|
|
|
|
const char* name = WebGLContext::EnumName(glenum);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (name)
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func, dims), msg, name);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
else
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func, dims), msg, glenum);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return true if the format is valid for source calls.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
|
|
|
|
|
{
|
|
|
|
|
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:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
|
|
|
|
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:
|
|
|
|
|
return (func == WebGLTexImageFunc::CompTexImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CompTexSubImage);
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_ATC_RGB:
|
|
|
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
|
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
2014-03-10 22:42:58 +00:00
|
|
|
|
case LOCAL_GL_ETC1_RGB8_OES:
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return func == WebGLTexImageFunc::CompTexImage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if func is a CopyTexImage variant.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
IsCopyFunc(WebGLTexImageFunc func)
|
|
|
|
|
{
|
|
|
|
|
return (func == WebGLTexImageFunc::CopyTexImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CopyTexSubImage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if func is a SubImage variant.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
IsSubFunc(WebGLTexImageFunc func)
|
|
|
|
|
{
|
|
|
|
|
return (func == WebGLTexImageFunc::TexSubImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CopyTexSubImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CompTexSubImage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* returns true is target is a texture cube map target.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
2014-09-18 23:14:22 +00:00
|
|
|
|
IsTexImageCubemapTarget(GLenum texImageTarget)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
2014-09-18 23:14:22 +00:00
|
|
|
|
return (texImageTarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
|
|
|
|
|
texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char *info)
|
2010-06-19 14:48:44 +00:00
|
|
|
|
{
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case LOCAL_GL_FUNC_ADD:
|
|
|
|
|
case LOCAL_GL_FUNC_SUBTRACT:
|
|
|
|
|
case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2013-07-18 15:24:23 +00:00
|
|
|
|
case LOCAL_GL_MIN:
|
|
|
|
|
case LOCAL_GL_MAX:
|
2014-06-14 16:07:53 +00:00
|
|
|
|
if (IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) {
|
2013-07-18 15:24:23 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
default:
|
2013-07-18 15:24:23 +00:00
|
|
|
|
break;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
}
|
2013-07-18 15:24:23 +00:00
|
|
|
|
|
|
|
|
|
ErrorInvalidEnumInfo(info, mode);
|
|
|
|
|
return false;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char *info)
|
2010-06-19 14:48:44 +00:00
|
|
|
|
{
|
|
|
|
|
switch (factor) {
|
|
|
|
|
case LOCAL_GL_ZERO:
|
|
|
|
|
case LOCAL_GL_ONE:
|
|
|
|
|
case LOCAL_GL_SRC_COLOR:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_SRC_COLOR:
|
|
|
|
|
case LOCAL_GL_DST_COLOR:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_DST_COLOR:
|
|
|
|
|
case LOCAL_GL_SRC_ALPHA:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
|
|
|
|
|
case LOCAL_GL_DST_ALPHA:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_DST_ALPHA:
|
|
|
|
|
case LOCAL_GL_CONSTANT_COLOR:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
|
|
|
|
|
case LOCAL_GL_CONSTANT_ALPHA:
|
|
|
|
|
case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
default:
|
2010-07-16 14:31:48 +00:00
|
|
|
|
ErrorInvalidEnumInfo(info, factor);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char *info)
|
2010-06-19 14:48:44 +00:00
|
|
|
|
{
|
2010-06-30 15:49:59 +00:00
|
|
|
|
if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-19 14:48:44 +00:00
|
|
|
|
else
|
2010-06-30 15:49:59 +00:00
|
|
|
|
return ValidateBlendFuncDstEnum(factor, info);
|
2010-06-19 14:48:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info)
|
2010-12-06 11:34:35 +00:00
|
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
|
2010-12-06 11:34:35 +00:00
|
|
|
|
sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
|
2010-12-06 11:34:35 +00:00
|
|
|
|
sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
|
2010-12-06 11:34:35 +00:00
|
|
|
|
dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
|
2010-12-06 11:34:35 +00:00
|
|
|
|
dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
|
|
|
|
|
if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
|
|
|
|
|
(dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
|
|
|
|
|
ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-12-06 11:34:35 +00:00
|
|
|
|
} else {
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-12-06 11:34:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
|
2010-06-30 15:48:30 +00:00
|
|
|
|
{
|
|
|
|
|
switch (target) {
|
|
|
|
|
case LOCAL_GL_TEXTURE_2D:
|
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2014-10-15 21:20:17 +00:00
|
|
|
|
case LOCAL_GL_TEXTURE_3D: {
|
|
|
|
|
const bool isValid = IsWebGL2();
|
|
|
|
|
if (!isValid) {
|
|
|
|
|
ErrorInvalidEnumInfo(info, target);
|
|
|
|
|
}
|
|
|
|
|
return isValid;
|
|
|
|
|
}
|
2010-06-30 15:48:30 +00:00
|
|
|
|
default:
|
2010-07-16 14:31:48 +00:00
|
|
|
|
ErrorInvalidEnumInfo(info, target);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateComparisonEnum(GLenum target, const char *info)
|
2010-06-30 15:48:30 +00:00
|
|
|
|
{
|
|
|
|
|
switch (target) {
|
|
|
|
|
case LOCAL_GL_NEVER:
|
|
|
|
|
case LOCAL_GL_LESS:
|
|
|
|
|
case LOCAL_GL_LEQUAL:
|
|
|
|
|
case LOCAL_GL_GREATER:
|
|
|
|
|
case LOCAL_GL_GEQUAL:
|
|
|
|
|
case LOCAL_GL_EQUAL:
|
|
|
|
|
case LOCAL_GL_NOTEQUAL:
|
|
|
|
|
case LOCAL_GL_ALWAYS:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
default:
|
2010-07-16 14:31:48 +00:00
|
|
|
|
ErrorInvalidEnumInfo(info, target);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char *info)
|
2010-06-30 15:48:30 +00:00
|
|
|
|
{
|
|
|
|
|
switch (action) {
|
|
|
|
|
case LOCAL_GL_KEEP:
|
|
|
|
|
case LOCAL_GL_ZERO:
|
|
|
|
|
case LOCAL_GL_REPLACE:
|
|
|
|
|
case LOCAL_GL_INCR:
|
|
|
|
|
case LOCAL_GL_INCR_WRAP:
|
|
|
|
|
case LOCAL_GL_DECR:
|
|
|
|
|
case LOCAL_GL_DECR_WRAP:
|
|
|
|
|
case LOCAL_GL_INVERT:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
default:
|
2010-07-16 14:31:48 +00:00
|
|
|
|
ErrorInvalidEnumInfo(info, action);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateFaceEnum(GLenum face, const char *info)
|
2010-06-30 15:48:30 +00:00
|
|
|
|
{
|
2010-07-16 14:31:48 +00:00
|
|
|
|
switch (face) {
|
2010-06-30 15:48:30 +00:00
|
|
|
|
case LOCAL_GL_FRONT:
|
|
|
|
|
case LOCAL_GL_BACK:
|
|
|
|
|
case LOCAL_GL_FRONT_AND_BACK:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
default:
|
2010-07-16 14:31:48 +00:00
|
|
|
|
ErrorInvalidEnumInfo(info, face);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-06-30 15:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-04 12:14:43 +00:00
|
|
|
|
bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char *info)
|
2010-07-16 14:31:48 +00:00
|
|
|
|
{
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case LOCAL_GL_TRIANGLES:
|
|
|
|
|
case LOCAL_GL_TRIANGLE_STRIP:
|
|
|
|
|
case LOCAL_GL_TRIANGLE_FAN:
|
|
|
|
|
case LOCAL_GL_POINTS:
|
|
|
|
|
case LOCAL_GL_LINE_STRIP:
|
|
|
|
|
case LOCAL_GL_LINE_LOOP:
|
|
|
|
|
case LOCAL_GL_LINES:
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-07-16 14:31:48 +00:00
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnumInfo(info, mode);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-07-03 22:34:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-07 21:17:44 +00:00
|
|
|
|
bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
|
2011-07-28 21:12:31 +00:00
|
|
|
|
{
|
2012-06-15 21:39:21 +00:00
|
|
|
|
if (name.IsEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
2012-05-23 16:07:01 +00:00
|
|
|
|
const uint32_t maxSize = 256;
|
2011-07-28 21:12:31 +00:00
|
|
|
|
if (name.Length() > maxSize) {
|
|
|
|
|
ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
|
|
|
|
|
info, name.Length(), maxSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-09-07 21:17:44 +00:00
|
|
|
|
|
|
|
|
|
if (!ValidateGLSLString(name, info)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 21:36:06 +00:00
|
|
|
|
nsString prefix1 = NS_LITERAL_STRING("webgl_");
|
|
|
|
|
nsString prefix2 = NS_LITERAL_STRING("_webgl_");
|
|
|
|
|
|
|
|
|
|
if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
|
|
|
|
|
Substring(name, 0, prefix2.Length()).Equals(prefix2))
|
|
|
|
|
{
|
|
|
|
|
ErrorInvalidOperation("%s: string contains a reserved GLSL prefix", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-07 21:17:44 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
|
|
|
|
|
{
|
2012-05-23 16:07:01 +00:00
|
|
|
|
for (uint32_t i = 0; i < string.Length(); ++i) {
|
2011-09-07 21:17:44 +00:00
|
|
|
|
if (!ValidateGLSLCharacter(string.CharAt(i))) {
|
|
|
|
|
ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-28 21:12:31 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 15:21:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return true if the framebuffer attachment is valid. Attachment must
|
|
|
|
|
* be one of depth/stencil/depth_stencil/color attachment.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateFramebufferAttachment(GLenum attachment, const char* funcName)
|
|
|
|
|
{
|
2014-10-14 21:49:49 +00:00
|
|
|
|
if (!mBoundFramebuffer) {
|
|
|
|
|
switch (attachment) {
|
|
|
|
|
case LOCAL_GL_COLOR:
|
|
|
|
|
case LOCAL_GL_DEPTH:
|
|
|
|
|
case LOCAL_GL_STENCIL:
|
|
|
|
|
return true;
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 15:21:33 +00:00
|
|
|
|
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
|
|
|
|
|
attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
|
|
|
|
|
attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLenum colorAttachCount = 1;
|
|
|
|
|
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
|
|
|
|
|
colorAttachCount = mGLMaxColorAttachments;
|
|
|
|
|
|
|
|
|
|
if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
|
|
|
|
|
attachment < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + colorAttachCount))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName, attachment);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-26 23:40:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return true if pname is valid for GetSamplerParameter calls.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateSamplerParameterName(GLenum pname, const char* info)
|
|
|
|
|
{
|
|
|
|
|
switch (pname) {
|
|
|
|
|
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
|
|
|
|
case LOCAL_GL_TEXTURE_MAG_FILTER:
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_S:
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_T:
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_R:
|
|
|
|
|
case LOCAL_GL_TEXTURE_MIN_LOD:
|
|
|
|
|
case LOCAL_GL_TEXTURE_MAX_LOD:
|
|
|
|
|
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
|
|
|
|
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return true if pname and param are valid combination for SamplerParameter calls.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info)
|
|
|
|
|
{
|
|
|
|
|
const GLenum p = param.AsInt();
|
|
|
|
|
|
|
|
|
|
switch (pname) {
|
|
|
|
|
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
|
|
|
|
switch (p) {
|
|
|
|
|
case LOCAL_GL_NEAREST:
|
|
|
|
|
case LOCAL_GL_LINEAR:
|
|
|
|
|
case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
|
|
|
|
|
case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
|
|
|
|
|
case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
|
|
|
|
|
case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_TEXTURE_MAG_FILTER:
|
|
|
|
|
switch (p) {
|
|
|
|
|
case LOCAL_GL_NEAREST:
|
|
|
|
|
case LOCAL_GL_LINEAR:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_S:
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_T:
|
|
|
|
|
case LOCAL_GL_TEXTURE_WRAP_R:
|
|
|
|
|
switch (p) {
|
|
|
|
|
case LOCAL_GL_CLAMP_TO_EDGE:
|
|
|
|
|
case LOCAL_GL_REPEAT:
|
|
|
|
|
case LOCAL_GL_MIRRORED_REPEAT:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_TEXTURE_MIN_LOD:
|
|
|
|
|
case LOCAL_GL_TEXTURE_MAX_LOD:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_TEXTURE_COMPARE_MODE:
|
|
|
|
|
switch (param.AsInt()) {
|
|
|
|
|
case LOCAL_GL_NONE:
|
|
|
|
|
case LOCAL_GL_COMPARE_REF_TO_TEXTURE:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_TEXTURE_COMPARE_FUNC:
|
|
|
|
|
switch (p) {
|
|
|
|
|
case LOCAL_GL_LEQUAL:
|
|
|
|
|
case LOCAL_GL_GEQUAL:
|
|
|
|
|
case LOCAL_GL_LESS:
|
|
|
|
|
case LOCAL_GL_GREATER:
|
|
|
|
|
case LOCAL_GL_EQUAL:
|
|
|
|
|
case LOCAL_GL_NOTEQUAL:
|
|
|
|
|
case LOCAL_GL_ALWAYS:
|
|
|
|
|
case LOCAL_GL_NEVER:
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return true if format is a valid texture image format for source,
|
|
|
|
|
* taking into account enabled WebGL extensions.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func, WebGLTexDimensions dims)
|
2013-11-04 21:05:04 +00:00
|
|
|
|
{
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Core WebGL texture formats */
|
|
|
|
|
if (format == LOCAL_GL_ALPHA ||
|
|
|
|
|
format == LOCAL_GL_RGB ||
|
|
|
|
|
format == LOCAL_GL_RGBA ||
|
|
|
|
|
format == LOCAL_GL_LUMINANCE ||
|
|
|
|
|
format == LOCAL_GL_LUMINANCE_ALPHA)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
2013-11-04 21:05:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
/* WebGL2 new formats */
|
|
|
|
|
if (format == LOCAL_GL_RED ||
|
|
|
|
|
format == LOCAL_GL_RG ||
|
|
|
|
|
format == LOCAL_GL_RED_INTEGER ||
|
|
|
|
|
format == LOCAL_GL_RG_INTEGER ||
|
|
|
|
|
format == LOCAL_GL_RGB_INTEGER ||
|
|
|
|
|
format == LOCAL_GL_RGBA_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
bool valid = IsWebGL2();
|
|
|
|
|
if (!valid) {
|
|
|
|
|
ErrorInvalidEnum("%s: invalid format %s: requires WebGL version 2.0 or newer",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), EnumName(format));
|
2014-10-09 20:07:07 +00:00
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* WEBGL_depth_texture added formats */
|
|
|
|
|
if (format == LOCAL_GL_DEPTH_COMPONENT ||
|
|
|
|
|
format == LOCAL_GL_DEPTH_STENCIL)
|
|
|
|
|
{
|
2014-07-31 00:56:29 +00:00
|
|
|
|
if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), EnumName(format));
|
2014-07-31 00:56:29 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If WEBGL_depth_texture is enabled, then it is not allowed to be used with the
|
2014-10-09 20:07:07 +00:00
|
|
|
|
// copyTexImage, or copyTexSubImage methods, and it is not allowed with
|
|
|
|
|
// texSubImage in WebGL1.
|
|
|
|
|
if ((func == WebGLTexImageFunc::TexSubImage && !IsWebGL2()) ||
|
2014-07-31 00:56:29 +00:00
|
|
|
|
func == WebGLTexImageFunc::CopyTexImage ||
|
|
|
|
|
func == WebGLTexImageFunc::CopyTexSubImage)
|
|
|
|
|
{
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func, dims), EnumName(format));
|
2014-07-31 00:56:29 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Needs to be below the depth_texture check because an invalid operation
|
|
|
|
|
// error needs to be generated instead of invalid enum.
|
|
|
|
|
/* Only core formats are valid for CopyTex(Sub)?Image */
|
|
|
|
|
// TODO: Revisit this once color_buffer_(half_)?float lands
|
|
|
|
|
if (IsCopyFunc(func)) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
|
2014-07-31 00:56:29 +00:00
|
|
|
|
return false;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* EXT_sRGB added formats */
|
|
|
|
|
if (format == LOCAL_GL_SRGB ||
|
|
|
|
|
format == LOCAL_GL_SRGB_ALPHA)
|
|
|
|
|
{
|
2014-04-26 02:34:07 +00:00
|
|
|
|
bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validFormat)
|
|
|
|
|
ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validFormat;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the given texture target is valid for TexImage.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLContext::ValidateTexImageTarget(GLenum target,
|
|
|
|
|
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
switch (dims) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
case WebGLTexDimensions::Tex2D:
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (target == LOCAL_GL_TEXTURE_2D ||
|
|
|
|
|
IsTexImageCubemapTarget(target))
|
|
|
|
|
{
|
2013-11-04 21:05:04 +00:00
|
|
|
|
return true;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case WebGLTexDimensions::Tex3D:
|
|
|
|
|
if (target == LOCAL_GL_TEXTURE_3D)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
|
2013-11-04 21:05:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return true if type is a valid texture image type for source,
|
|
|
|
|
* taking into account enabled WebGL extensions.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-05 02:24:24 +00:00
|
|
|
|
WebGLContext::ValidateTexImageType(GLenum type,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2012-05-08 17:29:31 +00:00
|
|
|
|
{
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Core WebGL texture types */
|
|
|
|
|
if (type == LOCAL_GL_UNSIGNED_BYTE ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
/* WebGL2 new types */
|
|
|
|
|
if (type == LOCAL_GL_BYTE ||
|
|
|
|
|
type == LOCAL_GL_SHORT ||
|
|
|
|
|
type == LOCAL_GL_INT ||
|
|
|
|
|
type == LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV)
|
|
|
|
|
{
|
|
|
|
|
bool validType = IsWebGL2();
|
|
|
|
|
if (!validType) {
|
|
|
|
|
ErrorInvalidEnum("%s: invalid type %s: requires WebGL version 2.0 or newer",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
2014-10-09 20:07:07 +00:00
|
|
|
|
}
|
|
|
|
|
return validType;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* OES_texture_float added types */
|
|
|
|
|
if (type == LOCAL_GL_FLOAT) {
|
2014-04-26 02:34:07 +00:00
|
|
|
|
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validType)
|
|
|
|
|
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OES_texture_half_float add types */
|
2014-10-07 23:52:58 +00:00
|
|
|
|
if (type == LOCAL_GL_HALF_FLOAT) {
|
2014-04-26 02:34:07 +00:00
|
|
|
|
bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validType)
|
|
|
|
|
ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* WEBGL_depth_texture added types */
|
|
|
|
|
if (type == LOCAL_GL_UNSIGNED_SHORT ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_INT ||
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_INT_24_8)
|
|
|
|
|
{
|
2014-04-26 02:34:07 +00:00
|
|
|
|
bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validType)
|
|
|
|
|
ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(type));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validType;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Validate texture image sizing extra constraints for
|
|
|
|
|
* CompressedTex(Sub)?Image.
|
|
|
|
|
*/
|
|
|
|
|
// TODO: WebGL 2
|
|
|
|
|
bool
|
2014-10-05 02:24:24 +00:00
|
|
|
|
WebGLContext::ValidateCompTexImageSize(GLint level,
|
|
|
|
|
GLenum format,
|
2014-02-21 01:20:28 +00:00
|
|
|
|
GLint xoffset, GLint yoffset,
|
|
|
|
|
GLsizei width, GLsizei height,
|
|
|
|
|
GLsizei levelWidth, GLsizei levelHeight,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2012-05-08 17:29:31 +00:00
|
|
|
|
{
|
2014-02-21 01:20:28 +00:00
|
|
|
|
// Negative parameters must already have been handled above
|
|
|
|
|
MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
|
|
|
|
|
width >= 0 && height >= 0);
|
|
|
|
|
|
|
|
|
|
if (xoffset + width > (GLint) levelWidth) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func, dims));
|
2012-09-25 12:49:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (yoffset + height > (GLint) levelHeight) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func, dims));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLint blockWidth = 1;
|
|
|
|
|
GLint blockHeight = 1;
|
|
|
|
|
BlockSizeFor(format, &blockWidth, &blockHeight);
|
|
|
|
|
|
|
|
|
|
/* If blockWidth || blockHeight != 1, then the compressed format
|
|
|
|
|
* had block-based constraints to be checked. (For example, PVRTC is compressed but
|
|
|
|
|
* isn't a block-based format)
|
|
|
|
|
*/
|
|
|
|
|
if (blockWidth != 1 || blockHeight != 1) {
|
|
|
|
|
/* offsets must be multiple of block size */
|
|
|
|
|
if (xoffset % blockWidth != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: xoffset must be multiple of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockWidth);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (yoffset % blockHeight != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: yoffset must be multiple of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockHeight);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The size must be a multiple of blockWidth and blockHeight,
|
|
|
|
|
* or must be using offset+size that exactly hits the edge.
|
2014-02-27 00:32:17 +00:00
|
|
|
|
* Important for small mipmap levels.
|
2014-02-21 01:20:28 +00:00
|
|
|
|
*/
|
2014-02-27 00:32:17 +00:00
|
|
|
|
/* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
|
|
|
|
|
* "When level equals zero width and height must be a multiple of 4. When
|
|
|
|
|
* level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
|
|
|
|
|
* If they are not an INVALID_OPERATION error is generated."
|
|
|
|
|
*/
|
|
|
|
|
if (level == 0) {
|
|
|
|
|
if (width % blockWidth != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockWidth);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (height % blockHeight != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockHeight);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-25 22:07:17 +00:00
|
|
|
|
}
|
2014-02-27 00:32:17 +00:00
|
|
|
|
else if (level > 0) {
|
|
|
|
|
if (width % blockWidth != 0 && width > 2) {
|
|
|
|
|
ErrorInvalidOperation("%s: width of level %d must be multiple"
|
|
|
|
|
" of %d or 0, 1, 2",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), level, blockWidth);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-25 22:07:17 +00:00
|
|
|
|
|
2014-02-27 00:32:17 +00:00
|
|
|
|
if (height % blockHeight != 0 && height > 2) {
|
|
|
|
|
ErrorInvalidOperation("%s: height of level %d must be multiple"
|
|
|
|
|
" of %d or 0, 1, 2",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), level, blockHeight);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSubFunc(func)) {
|
|
|
|
|
if ((xoffset % blockWidth) != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: xoffset must be multiple of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockWidth);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (yoffset % blockHeight != 0) {
|
|
|
|
|
ErrorInvalidOperation("%s: yoffset must be multiple of %d",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), blockHeight);
|
2014-02-27 00:32:17 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
|
|
|
|
|
if (!is_pot_assuming_nonnegative(width) ||
|
|
|
|
|
!is_pot_assuming_nonnegative(height))
|
|
|
|
|
{
|
|
|
|
|
ErrorInvalidValue("%s: width and height must be powers of two",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return true if the enough data is present to satisfy compressed
|
|
|
|
|
* texture format constraints.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
|
|
|
|
|
GLsizei width, GLsizei height,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
uint32_t byteLength,
|
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
2012-09-25 12:49:28 +00:00
|
|
|
|
// negative width and height must already have been handled above
|
|
|
|
|
MOZ_ASSERT(width >= 0 && height >= 0);
|
|
|
|
|
|
2012-09-25 12:49:28 +00:00
|
|
|
|
CheckedUint32 required_byteLength = 0;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
2012-09-25 12:49:28 +00:00
|
|
|
|
case LOCAL_GL_ATC_RGB:
|
2014-03-10 22:42:58 +00:00
|
|
|
|
case LOCAL_GL_ETC1_RGB8_OES:
|
2012-05-08 17:29:31 +00:00
|
|
|
|
{
|
2012-09-25 12:49:28 +00:00
|
|
|
|
required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
2012-09-25 12:49:28 +00:00
|
|
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
|
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
2012-05-08 17:29:31 +00:00
|
|
|
|
{
|
2012-09-25 12:49:28 +00:00
|
|
|
|
required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2012-09-25 12:49:28 +00:00
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
|
|
|
|
|
{
|
2013-01-15 12:22:03 +00:00
|
|
|
|
required_byteLength = CheckedUint32(std::max(width, 8)) * CheckedUint32(std::max(height, 8)) / 2;
|
2012-09-25 12:49:28 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
|
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
|
|
|
|
|
{
|
2013-01-15 12:22:03 +00:00
|
|
|
|
required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
|
2012-09-25 12:49:28 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-25 12:49:28 +00:00
|
|
|
|
if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func, dims));
|
2012-09-25 12:49:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validate the width, height, and depth of a texture image, \return
|
|
|
|
|
* true is valid, false otherwise.
|
|
|
|
|
* Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
|
|
|
|
|
* Target and level must have been validated before calling.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-09-18 23:14:22 +00:00
|
|
|
|
WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
2014-02-21 01:20:28 +00:00
|
|
|
|
GLint width, GLint height, GLint depth,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(level >= 0, "level should already be validated");
|
|
|
|
|
|
2014-04-16 01:23:41 +00:00
|
|
|
|
/* Bug 966630: maxTextureSize >> level runs into "undefined"
|
|
|
|
|
* behaviour depending on ISA. For example, on Intel shifts
|
|
|
|
|
* amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
|
|
|
|
|
* otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
|
|
|
|
|
* what would be expected. Make the required behaviour explicit by
|
|
|
|
|
* clamping to a shift of 31 bits if level is greater than that
|
|
|
|
|
* ammount. This will give 0 that if (!maxAllowedSize) is
|
|
|
|
|
* expecting.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (level > 31)
|
|
|
|
|
level = 31;
|
|
|
|
|
|
2014-09-18 23:14:22 +00:00
|
|
|
|
const GLuint maxTexImageSize = MaxTextureSizeForTarget(TexImageTargetToTexTarget(texImageTarget)) >> level;
|
|
|
|
|
const bool isCubemapTarget = IsTexImageCubemapTarget(texImageTarget.get());
|
2014-04-22 04:09:33 +00:00
|
|
|
|
const bool isSub = IsSubFunc(func);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
|
2014-04-22 04:09:33 +00:00
|
|
|
|
if (!isSub && isCubemapTarget && (width != height)) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
|
|
|
|
* "When the target parameter to TexImage2D is one of the
|
|
|
|
|
* six cube map two-dimensional image targets, the error
|
|
|
|
|
* INVALID_VALUE is generated if the width and height
|
|
|
|
|
* parameters are not equal."
|
|
|
|
|
*/
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func, dims));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-18 23:14:22 +00:00
|
|
|
|
if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
|
|
|
|
* "If wt and ht are the specified image width and height,
|
|
|
|
|
* and if either wt or ht are less than zero, then the error
|
|
|
|
|
* INVALID_VALUE is generated."
|
|
|
|
|
*/
|
|
|
|
|
if (width < 0) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func, dims));
|
2012-09-25 12:49:28 +00:00
|
|
|
|
return false;
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
2014-02-21 01:20:28 +00:00
|
|
|
|
|
|
|
|
|
if (height < 0) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func, dims));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
|
|
|
|
* "The maximum allowable width and height of a
|
|
|
|
|
* two-dimensional texture image must be at least 2**(k−lod)
|
|
|
|
|
* for image arrays of level zero through k, where k is the
|
|
|
|
|
* log base 2 of MAX_TEXTURE_SIZE. and lod is the
|
|
|
|
|
* level-of-detail of the image array. It may be zero for
|
|
|
|
|
* image arrays of any level-of-detail greater than k. The
|
|
|
|
|
* error INVALID_VALUE is generated if the specified image
|
|
|
|
|
* is too large to be stored under any conditions.
|
|
|
|
|
*/
|
|
|
|
|
if (width > (int) maxTexImageSize) {
|
|
|
|
|
ErrorInvalidValue("%s: the maximum width for level %d is %u",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), level, maxTexImageSize);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (height > (int) maxTexImageSize) {
|
|
|
|
|
ErrorInvalidValue("%s: tex maximum height for level %d is %u",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), level, maxTexImageSize);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
|
|
|
|
* "If level is greater than zero, and either width or
|
|
|
|
|
* height is not a power-of-two, the error INVALID_VALUE is
|
|
|
|
|
* generated."
|
2014-10-15 02:10:15 +00:00
|
|
|
|
*
|
|
|
|
|
* This restriction does not apply to GL ES Version 3.0+.
|
2014-02-21 01:20:28 +00:00
|
|
|
|
*/
|
2014-10-15 02:10:15 +00:00
|
|
|
|
if (!IsWebGL2() && level > 0) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!is_pot_assuming_nonnegative(width)) {
|
|
|
|
|
ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), width);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_pot_assuming_nonnegative(height)) {
|
|
|
|
|
ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), height);
|
2012-09-25 12:49:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
// TODO: WebGL 2
|
2014-09-18 23:14:22 +00:00
|
|
|
|
if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (depth < 0) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-05-08 17:29:31 +00:00
|
|
|
|
|
2014-10-15 02:10:15 +00:00
|
|
|
|
if (!IsWebGL2() && !is_pot_assuming_nonnegative(depth)) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), depth);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-05-08 17:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2012-10-09 18:21:22 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Validate texture image sizing for Tex(Sub)?Image variants.
|
|
|
|
|
*/
|
|
|
|
|
// TODO: WebGL 2. Update this to handle 3D textures.
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
|
|
|
|
|
GLsizei width, GLsizei height, GLsizei /*depth*/,
|
|
|
|
|
GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func, WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
/* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
|
|
|
|
|
* "Taking wt and ht to be the specified width and height of the
|
|
|
|
|
* texture array, and taking x, y, w, and h to be the xoffset,
|
|
|
|
|
* yoffset, width, and height argument values, any of the
|
|
|
|
|
* following relationships generates the error INVALID_VALUE:
|
|
|
|
|
* x < 0
|
|
|
|
|
* x + w > wt
|
|
|
|
|
* y < 0
|
|
|
|
|
* y + h > ht"
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (xoffset < 0) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func, dims));
|
2012-05-08 17:29:31 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (yoffset < 0) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func, dims));
|
2012-05-08 17:29:31 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func, dims));
|
2012-05-08 17:29:31 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Perform validation of format/type combinations for TexImage variants.
|
|
|
|
|
* Returns true if the format/type is a valid combination, false otherwise.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-05 02:24:24 +00:00
|
|
|
|
WebGLContext::ValidateTexImageFormatAndType(GLenum format,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
GLenum type,
|
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2010-06-30 15:49:59 +00:00
|
|
|
|
{
|
2014-10-05 02:24:24 +00:00
|
|
|
|
if (IsCompressedFunc(func) || IsCopyFunc(func))
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-10-13 23:42:15 +00:00
|
|
|
|
if (!ValidateTexImageFormat(format, func, dims) ||
|
|
|
|
|
!ValidateTexImageType(type, func, dims))
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2012-08-14 01:17:55 +00:00
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
// Here we're reinterpreting format as an unsized internalformat;
|
|
|
|
|
// these are the same in practice and there's no point in having the
|
|
|
|
|
// same code implemented twice.
|
|
|
|
|
TexInternalFormat effective =
|
|
|
|
|
EffectiveInternalFormatFromInternalFormatAndType(format, type);
|
|
|
|
|
bool validCombo = effective != LOCAL_GL_NONE;
|
2012-08-14 01:17:55 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validCombo)
|
|
|
|
|
ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
|
2012-08-14 01:17:55 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validCombo;
|
|
|
|
|
}
|
2012-08-14 01:17:55 +00:00
|
|
|
|
|
2014-10-05 02:24:24 +00:00
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-10-05 02:24:24 +00:00
|
|
|
|
{
|
|
|
|
|
if (!IsCompressedTextureFormat(format)) {
|
|
|
|
|
ErrorInvalidEnum("%s: invalid compressed texture format: %s",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
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",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
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",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
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",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
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",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
return validFormat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-10-05 02:24:24 +00:00
|
|
|
|
{
|
|
|
|
|
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",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), WebGLContext::EnumName(format));
|
2014-10-05 02:24:24 +00:00
|
|
|
|
SynthesizeGLError(func == WebGLTexImageFunc::CopyTexImage
|
|
|
|
|
? LOCAL_GL_INVALID_ENUM
|
|
|
|
|
: LOCAL_GL_INVALID_OPERATION);
|
|
|
|
|
}
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return true if format, type and jsArrayType are a valid combination.
|
|
|
|
|
* Also returns the size for texel of format and type (in bytes) via
|
|
|
|
|
* \a texelSize.
|
|
|
|
|
*
|
|
|
|
|
* It is assumed that type has previously been validated.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-13 23:42:11 +00:00
|
|
|
|
WebGLContext::ValidateTexInputData(GLenum type,
|
|
|
|
|
js::Scalar::Type jsArrayType,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
|
|
|
|
bool validInput = false;
|
2014-01-23 21:47:37 +00:00
|
|
|
|
const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
|
2012-08-14 01:17:55 +00:00
|
|
|
|
|
2014-10-13 23:42:11 +00:00
|
|
|
|
// We're using js::Scalar::TypeMax as dummy value when the tex source wasn't a
|
|
|
|
|
// typed array.
|
|
|
|
|
if (jsArrayType == js::Scalar::TypeMax) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-23 21:47:37 +00:00
|
|
|
|
// First, we check for packed types
|
2011-05-20 19:53:53 +00:00
|
|
|
|
switch (type) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
case LOCAL_GL_UNSIGNED_BYTE:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Uint8;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
case LOCAL_GL_BYTE:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Int8;
|
2014-10-09 20:07:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-03-13 08:48:50 +00:00
|
|
|
|
case LOCAL_GL_HALF_FLOAT:
|
2014-02-21 01:20:28 +00:00
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Uint16;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
case LOCAL_GL_SHORT:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Int16;
|
2014-10-09 20:07:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
case LOCAL_GL_UNSIGNED_INT:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_24_8:
|
2014-10-09 20:07:07 +00:00
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
|
|
|
|
|
case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Uint32;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-10-09 20:07:07 +00:00
|
|
|
|
case LOCAL_GL_INT:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Int32;
|
2014-10-09 20:07:07 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
case LOCAL_GL_FLOAT:
|
2014-10-13 23:42:11 +00:00
|
|
|
|
validInput = jsArrayType == js::Scalar::Float32;
|
2014-02-21 01:20:28 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-05-20 19:53:53 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!validInput)
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
|
2011-05-20 19:53:53 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return validInput;
|
|
|
|
|
}
|
2011-05-20 19:53:53 +00:00
|
|
|
|
|
2014-08-20 20:38:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Checks specific for the CopyTex[Sub]Image2D functions.
|
|
|
|
|
* Verifies:
|
|
|
|
|
* - Framebuffer is complete and has valid read planes
|
|
|
|
|
* - Copy format is a subset of framebuffer format (i.e. all required components are available)
|
|
|
|
|
*/
|
|
|
|
|
bool
|
2014-10-05 02:24:24 +00:00
|
|
|
|
WebGLContext::ValidateCopyTexImage(GLenum format,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-08-20 20:38:42 +00:00
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(IsCopyFunc(func));
|
|
|
|
|
|
|
|
|
|
// Default framebuffer format
|
2014-10-08 23:36:33 +00:00
|
|
|
|
GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
2014-08-20 20:38:42 +00:00
|
|
|
|
|
|
|
|
|
if (mBoundFramebuffer) {
|
|
|
|
|
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func, dims));
|
2014-08-20 20:38:42 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
|
|
|
|
if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
|
|
|
|
ErrorInvalidOperation("%s: Read source attachment doesn't have the"
|
2014-10-13 23:42:15 +00:00
|
|
|
|
" correct color/depth/stencil type.", InfoFrom(func, dims));
|
2014-08-20 20:38:42 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the correct format for the framebuffer, as it's not the default one
|
|
|
|
|
const WebGLFramebuffer::Attachment& color0 = mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
|
|
|
|
|
fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make sure the format of the framebuffer is a superset of
|
|
|
|
|
// the format requested by the CopyTex[Sub]Image2D functions.
|
|
|
|
|
const GLComponents formatComps = GLComponents(format);
|
|
|
|
|
const GLComponents fboComps = GLComponents(fboFormat);
|
|
|
|
|
if (!formatComps.IsSubsetOf(fboComps)) {
|
|
|
|
|
ErrorInvalidOperation("%s: format %s is not a subset of the current framebuffer format, which is %s.",
|
2014-10-13 23:42:15 +00:00
|
|
|
|
InfoFrom(func, dims), EnumName(format), EnumName(fboFormat));
|
2014-08-20 20:38:42 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
|
|
|
|
|
* Verifies each of the parameters against the WebGL standard and enabled extensions.
|
|
|
|
|
*/
|
|
|
|
|
// TODO: Texture dims is here for future expansion in WebGL 2.0
|
|
|
|
|
bool
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLContext::ValidateTexImage(TexImageTarget texImageTarget,
|
2014-10-05 02:24:24 +00:00
|
|
|
|
GLint level,
|
|
|
|
|
GLenum internalFormat,
|
2014-02-21 01:20:28 +00:00
|
|
|
|
GLint xoffset, GLint yoffset, GLint zoffset,
|
|
|
|
|
GLint width, GLint height, GLint depth,
|
2014-10-05 02:24:24 +00:00
|
|
|
|
GLint border,
|
|
|
|
|
GLenum format,
|
|
|
|
|
GLenum type,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
WebGLTexImageFunc func,
|
|
|
|
|
WebGLTexDimensions dims)
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
2014-10-13 23:42:15 +00:00
|
|
|
|
const char* info = InfoFrom(func, dims);
|
2011-05-20 19:53:53 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Check level */
|
|
|
|
|
if (level < 0) {
|
|
|
|
|
ErrorInvalidValue("%s: level must be >= 0", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-01-23 21:47:37 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Check border */
|
|
|
|
|
if (border != 0) {
|
|
|
|
|
ErrorInvalidValue("%s: border must be 0", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check incoming image format and type */
|
2014-10-13 23:42:15 +00:00
|
|
|
|
if (!ValidateTexImageFormatAndType(format, type, func, dims))
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
2014-10-11 23:07:33 +00:00
|
|
|
|
if (!TexInternalFormat::IsValueLegal(internalFormat)) {
|
|
|
|
|
ErrorInvalidEnum("%s: invalid internalformat enum %s", info, EnumName(internalFormat));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
TexInternalFormat unsizedInternalFormat =
|
|
|
|
|
UnsizedInternalFormatFromInternalFormat(internalFormat);
|
|
|
|
|
|
2014-10-05 02:24:24 +00:00
|
|
|
|
if (IsCompressedFunc(func)) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims)) {
|
2014-10-05 02:24:24 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else if (IsCopyFunc(func)) {
|
2014-10-13 23:42:15 +00:00
|
|
|
|
if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func, dims)) {
|
2014-10-05 02:24:24 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-11 23:07:33 +00:00
|
|
|
|
} else if (format != unsizedInternalFormat) {
|
2014-10-09 20:07:07 +00:00
|
|
|
|
if (IsWebGL2()) {
|
|
|
|
|
// In WebGL2, it's OK to have internalformat != format if internalformat is the sized
|
|
|
|
|
// internal format corresponding to the (format, type) pair according to Table 3.2
|
|
|
|
|
// in the OpenGL ES 3.0.3 spec.
|
|
|
|
|
if (internalFormat != EffectiveInternalFormatFromInternalFormatAndType(format, type)) {
|
2014-10-11 23:07:33 +00:00
|
|
|
|
bool exceptionallyAllowed = false;
|
|
|
|
|
if (internalFormat == LOCAL_GL_SRGB8_ALPHA8 &&
|
|
|
|
|
format == LOCAL_GL_RGBA &&
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_BYTE)
|
|
|
|
|
{
|
|
|
|
|
exceptionallyAllowed = true;
|
|
|
|
|
}
|
|
|
|
|
else if (internalFormat == LOCAL_GL_SRGB8 &&
|
|
|
|
|
format == LOCAL_GL_RGB &&
|
|
|
|
|
type == LOCAL_GL_UNSIGNED_BYTE)
|
|
|
|
|
{
|
|
|
|
|
exceptionallyAllowed = true;
|
|
|
|
|
}
|
|
|
|
|
if (!exceptionallyAllowed) {
|
|
|
|
|
ErrorInvalidOperation("%s: internalformat does not match format and type", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-09 20:07:07 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// in WebGL 1, format must be equal to internalformat
|
|
|
|
|
ErrorInvalidOperation("%s: internalformat does not match format", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
2014-01-23 21:47:37 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Check texture image size */
|
2014-10-13 23:42:15 +00:00
|
|
|
|
if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func, dims))
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
/* 5.14.8 Texture objects - WebGL Spec.
|
|
|
|
|
* "If an attempt is made to call these functions with no
|
|
|
|
|
* WebGLTexture bound (see above), an INVALID_OPERATION error
|
|
|
|
|
* is generated."
|
|
|
|
|
*/
|
2014-09-18 23:14:22 +00:00
|
|
|
|
WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!tex) {
|
|
|
|
|
ErrorInvalidOperation("%s: no texture is bound to target %s",
|
2014-09-18 23:14:22 +00:00
|
|
|
|
info, WebGLContext::EnumName(texImageTarget.get()));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSubFunc(func)) {
|
2014-09-18 23:14:22 +00:00
|
|
|
|
if (!tex->HasImageInfoAt(texImageTarget, level)) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
|
2014-09-18 23:14:22 +00:00
|
|
|
|
info, WebGLContext::EnumName(texImageTarget.get()), level);
|
2014-01-23 21:47:37 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-18 23:14:22 +00:00
|
|
|
|
const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
|
2014-10-07 23:52:58 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
|
|
|
|
|
width, height, depth,
|
|
|
|
|
imageInfo.Width(), imageInfo.Height(), 0,
|
2014-10-13 23:42:15 +00:00
|
|
|
|
func, dims))
|
2014-02-21 01:20:28 +00:00
|
|
|
|
{
|
2014-01-23 21:47:37 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-21 01:20:28 +00:00
|
|
|
|
}
|
2014-01-23 21:47:37 +00:00
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Additional checks for depth textures */
|
2014-09-18 23:14:22 +00:00
|
|
|
|
if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
|
2014-02-21 01:20:28 +00:00
|
|
|
|
(format == LOCAL_GL_DEPTH_COMPONENT ||
|
|
|
|
|
format == LOCAL_GL_DEPTH_STENCIL))
|
|
|
|
|
{
|
|
|
|
|
ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
|
2014-06-02 20:30:00 +00:00
|
|
|
|
info, WebGLContext::EnumName(format));
|
2014-01-23 21:47:37 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Additional checks for compressed textures */
|
2014-10-05 02:24:24 +00:00
|
|
|
|
if (!IsAllowedFromSource(internalFormat, func)) {
|
2014-02-21 01:20:28 +00:00
|
|
|
|
ErrorInvalidOperation("%s: Invalid format %s for this operation",
|
2014-06-02 20:30:00 +00:00
|
|
|
|
info, WebGLContext::EnumName(format));
|
2014-02-21 01:20:28 +00:00
|
|
|
|
return false;
|
2014-01-23 21:47:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-21 01:20:28 +00:00
|
|
|
|
/* Parameters are OK */
|
|
|
|
|
return true;
|
2010-06-30 15:49:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-10-16 12:17:01 +00:00
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object)
|
|
|
|
|
{
|
|
|
|
|
if (!ValidateObjectAllowNull(info, location_object))
|
|
|
|
|
return false;
|
|
|
|
|
if (!location_object)
|
|
|
|
|
return false;
|
|
|
|
|
/* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
|
|
|
|
|
if (!mCurrentProgram) {
|
|
|
|
|
ErrorInvalidOperation("%s: no program is currently bound", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (mCurrentProgram != location_object->Program()) {
|
|
|
|
|
ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) {
|
|
|
|
|
ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-05 00:44:31 +00:00
|
|
|
|
bool
|
2013-09-04 12:14:43 +00:00
|
|
|
|
WebGLContext::ValidateSamplerUniformSetter(const char* info, WebGLUniformLocation *location, GLint value)
|
2013-03-05 00:44:31 +00:00
|
|
|
|
{
|
2014-09-19 23:35:54 +00:00
|
|
|
|
if (location->Info().type != LOCAL_GL_SAMPLER_2D &&
|
|
|
|
|
location->Info().type != LOCAL_GL_SAMPLER_CUBE)
|
2013-03-05 00:44:31 +00:00
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value >= 0 && value < mGLMaxTextureUnits)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
ErrorInvalidValue("%s: this uniform location is a sampler, but %d is not a valid texture unit",
|
|
|
|
|
info, value);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-16 12:17:01 +00:00
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
|
|
|
|
|
{
|
2013-09-04 12:14:44 +00:00
|
|
|
|
if (IsContextLost()) {
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (arrayLength < cnt) {
|
|
|
|
|
ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-23 22:10:57 +00:00
|
|
|
|
static bool
|
|
|
|
|
IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
|
2012-10-16 12:17:01 +00:00
|
|
|
|
{
|
2014-10-23 22:10:57 +00:00
|
|
|
|
switch (uniformType) {
|
|
|
|
|
case LOCAL_GL_BOOL:
|
|
|
|
|
case LOCAL_GL_BOOL_VEC2:
|
|
|
|
|
case LOCAL_GL_BOOL_VEC3:
|
|
|
|
|
case LOCAL_GL_BOOL_VEC4:
|
|
|
|
|
return true; // GLfloat(0.0) sets a bool to false.
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_INT:
|
|
|
|
|
case LOCAL_GL_SAMPLER_2D:
|
|
|
|
|
case LOCAL_GL_SAMPLER_CUBE:
|
|
|
|
|
case LOCAL_GL_INT_VEC2:
|
|
|
|
|
case LOCAL_GL_INT_VEC3:
|
|
|
|
|
case LOCAL_GL_INT_VEC4:
|
|
|
|
|
return setterType == LOCAL_GL_INT;
|
|
|
|
|
|
|
|
|
|
case LOCAL_GL_FLOAT:
|
|
|
|
|
case LOCAL_GL_FLOAT_VEC2:
|
|
|
|
|
case LOCAL_GL_FLOAT_VEC3:
|
|
|
|
|
case LOCAL_GL_FLOAT_VEC4:
|
|
|
|
|
case LOCAL_GL_FLOAT_MAT2:
|
|
|
|
|
case LOCAL_GL_FLOAT_MAT3:
|
|
|
|
|
case LOCAL_GL_FLOAT_MAT4:
|
|
|
|
|
return setterType == LOCAL_GL_FLOAT;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
MOZ_ASSERT(false); // should never get here
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
|
|
|
|
|
uint8_t setterElemSize, GLenum setterType,
|
|
|
|
|
const char* info)
|
|
|
|
|
{
|
|
|
|
|
if (setterElemSize != loc->ElementSize()) {
|
|
|
|
|
webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
|
|
|
|
|
loc->ElementSize());
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
|
|
|
|
|
webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
|
|
|
|
|
loc->Info().type);
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
|
|
|
|
|
uint8_t setterElemSize, size_t setterArraySize,
|
|
|
|
|
const char* info)
|
|
|
|
|
{
|
|
|
|
|
if (setterArraySize == 0 ||
|
|
|
|
|
setterArraySize % setterElemSize)
|
2012-10-16 12:17:01 +00:00
|
|
|
|
{
|
2014-10-23 22:10:57 +00:00
|
|
|
|
webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
|
|
|
|
|
" %d, got an array of length %d.", info,
|
|
|
|
|
setterElemSize, setterArraySize);
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!loc->Info().isArray &&
|
|
|
|
|
setterArraySize != setterElemSize)
|
|
|
|
|
{
|
|
|
|
|
webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
|
|
|
|
|
" (since this uniform is not an array"
|
|
|
|
|
" uniform), got an array of length %d.",
|
|
|
|
|
info, setterElemSize, setterArraySize);
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2014-10-23 22:10:57 +00:00
|
|
|
|
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
|
|
|
|
|
uint8_t setterElemSize, GLenum setterType,
|
|
|
|
|
const char* info, GLuint* out_rawLoc)
|
2012-10-16 12:17:01 +00:00
|
|
|
|
{
|
2013-09-04 12:14:44 +00:00
|
|
|
|
if (IsContextLost())
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!ValidateUniformLocation(info, loc))
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
*out_rawLoc = loc->Location();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
|
|
|
|
|
uint8_t setterElemSize, GLenum setterType,
|
|
|
|
|
size_t setterArraySize,
|
|
|
|
|
const char* info, GLuint* out_rawLoc,
|
|
|
|
|
GLsizei* out_numElementsToUpload)
|
|
|
|
|
{
|
|
|
|
|
if (IsContextLost())
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!ValidateUniformLocation(info, loc))
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
|
|
|
|
info))
|
|
|
|
|
{
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
*out_rawLoc = loc->Location();
|
|
|
|
|
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
|
|
|
|
setterArraySize / setterElemSize);
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2014-10-23 22:10:57 +00:00
|
|
|
|
WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
|
|
|
|
|
uint8_t setterDims,
|
|
|
|
|
GLenum setterType,
|
|
|
|
|
size_t setterArraySize,
|
|
|
|
|
bool setterTranspose,
|
|
|
|
|
const char* info,
|
|
|
|
|
GLuint* out_rawLoc,
|
|
|
|
|
GLsizei* out_numElementsToUpload)
|
2012-10-16 12:17:01 +00:00
|
|
|
|
{
|
2014-10-23 22:10:57 +00:00
|
|
|
|
uint8_t setterElemSize = setterDims * setterDims;
|
|
|
|
|
|
2013-09-04 12:14:44 +00:00
|
|
|
|
if (IsContextLost())
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
2014-10-23 22:10:57 +00:00
|
|
|
|
|
|
|
|
|
if (!ValidateUniformLocation(info, loc))
|
2012-10-16 12:17:01 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
2014-10-23 22:10:57 +00:00
|
|
|
|
if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
|
|
|
|
|
info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (setterTranspose) {
|
|
|
|
|
ErrorInvalidValue("%s: `transpose` must be false.", info);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out_rawLoc = loc->Location();
|
|
|
|
|
*out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
|
|
|
|
|
setterArraySize / setterElemSize);
|
|
|
|
|
return true;
|
2011-02-24 22:17:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool WebGLContext::ValidateStencilParamsForDrawCall()
|
2011-05-20 19:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
|
|
|
|
|
if (mStencilRefFront != mStencilRefBack) {
|
|
|
|
|
ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2011-05-20 19:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
if (mStencilValueMaskFront != mStencilValueMaskBack) {
|
|
|
|
|
ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2011-05-20 19:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
|
|
|
|
|
ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2011-05-20 19:53:53 +00:00
|
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2011-05-20 19:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-30 15:07:04 +00:00
|
|
|
|
static inline int32_t floorPOT(int32_t x)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(x > 0);
|
|
|
|
|
int32_t pot = 1;
|
|
|
|
|
while (pot < 0x40000000) {
|
|
|
|
|
if (x < pot*2)
|
|
|
|
|
break;
|
|
|
|
|
pot *= 2;
|
|
|
|
|
}
|
|
|
|
|
return pot;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
|
bool
|
2010-06-14 18:44:12 +00:00
|
|
|
|
WebGLContext::InitAndValidateGL()
|
2010-06-10 17:45:00 +00:00
|
|
|
|
{
|
2011-10-17 14:59:28 +00:00
|
|
|
|
if (!gl) return false;
|
2010-06-14 18:44:12 +00:00
|
|
|
|
|
2011-02-11 23:11:30 +00:00
|
|
|
|
GLenum error = gl->fGetError();
|
|
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
2012-05-23 16:07:29 +00:00
|
|
|
|
GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2011-02-11 23:11:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 12:09:22 +00:00
|
|
|
|
mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
|
|
|
|
|
mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
|
2014-11-11 03:31:00 +00:00
|
|
|
|
mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false);
|
2013-01-03 23:39:25 +00:00
|
|
|
|
mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
|
2014-06-22 23:16:00 +00:00
|
|
|
|
mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true);
|
2011-10-13 12:09:22 +00:00
|
|
|
|
|
2013-05-15 21:50:52 +00:00
|
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
|
mDisableFragHighP = true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-17 20:15:41 +00:00
|
|
|
|
// These are the default values, see 6.2 State tables in the
|
|
|
|
|
// OpenGL ES 2.0.25 spec.
|
|
|
|
|
mColorWriteMask[0] = 1;
|
|
|
|
|
mColorWriteMask[1] = 1;
|
|
|
|
|
mColorWriteMask[2] = 1;
|
|
|
|
|
mColorWriteMask[3] = 1;
|
|
|
|
|
mDepthWriteMask = 1;
|
|
|
|
|
mColorClearValue[0] = 0.f;
|
|
|
|
|
mColorClearValue[1] = 0.f;
|
|
|
|
|
mColorClearValue[2] = 0.f;
|
|
|
|
|
mColorClearValue[3] = 0.f;
|
|
|
|
|
mDepthClearValue = 1.f;
|
|
|
|
|
mStencilClearValue = 0;
|
|
|
|
|
mStencilRefFront = 0;
|
|
|
|
|
mStencilRefBack = 0;
|
2014-05-22 02:03:09 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// Technically, we should be setting mStencil[...] values to
|
|
|
|
|
// `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
|
|
|
|
|
GLuint stencilBits = 0;
|
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
|
|
|
|
|
GLuint allOnes = ~(UINT32_MAX << stencilBits);
|
|
|
|
|
mStencilValueMaskFront = allOnes;
|
|
|
|
|
mStencilValueMaskBack = allOnes;
|
|
|
|
|
mStencilWriteMaskFront = allOnes;
|
|
|
|
|
mStencilWriteMaskBack = allOnes;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
|
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
|
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
|
|
|
|
|
gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
mDitherEnabled = true;
|
|
|
|
|
mRasterizerDiscardEnabled = false;
|
|
|
|
|
mScissorTestEnabled = false;
|
2014-04-17 20:15:41 +00:00
|
|
|
|
|
|
|
|
|
// Bindings, etc.
|
2010-06-14 18:44:12 +00:00
|
|
|
|
mActiveTexture = 0;
|
2014-03-07 21:16:34 +00:00
|
|
|
|
mEmitContextLostErrorOnce = true;
|
2011-07-08 00:01:16 +00:00
|
|
|
|
mWebGLError = LOCAL_GL_NO_ERROR;
|
2014-03-07 21:16:34 +00:00
|
|
|
|
mUnderlyingGLError = LOCAL_GL_NO_ERROR;
|
2010-06-14 18:44:12 +00:00
|
|
|
|
|
|
|
|
|
mBound2DTextures.Clear();
|
|
|
|
|
mBoundCubeMapTextures.Clear();
|
2014-10-13 23:42:20 +00:00
|
|
|
|
mBound3DTextures.Clear();
|
2010-06-14 18:44:12 +00:00
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
|
mBoundArrayBuffer = nullptr;
|
2013-08-20 15:36:20 +00:00
|
|
|
|
mBoundTransformFeedbackBuffer = nullptr;
|
2012-07-30 14:20:58 +00:00
|
|
|
|
mCurrentProgram = nullptr;
|
2010-06-14 18:44:12 +00:00
|
|
|
|
|
2012-07-30 14:20:58 +00:00
|
|
|
|
mBoundFramebuffer = nullptr;
|
|
|
|
|
mBoundRenderbuffer = nullptr;
|
2010-06-14 18:44:12 +00:00
|
|
|
|
|
2010-07-19 05:01:14 +00:00
|
|
|
|
MakeContextCurrent();
|
2010-06-10 17:45:00 +00:00
|
|
|
|
|
2010-09-02 14:34:08 +00:00
|
|
|
|
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
|
2014-03-31 09:10:49 +00:00
|
|
|
|
if (!gl->IsGLES()) {
|
2010-09-02 14:34:08 +00:00
|
|
|
|
gl->fEnableVertexAttribArray(0);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-13 12:09:22 +00:00
|
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
|
mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
|
|
|
|
|
} else {
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
|
|
|
|
|
}
|
2010-07-15 03:52:34 +00:00
|
|
|
|
if (mGLMaxVertexAttribs < 8) {
|
2012-05-23 16:07:29 +00:00
|
|
|
|
GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
|
2011-10-13 12:09:22 +00:00
|
|
|
|
return false;
|
2010-06-10 17:45:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
|
|
|
|
|
// even though the hardware supports much more. The
|
2010-07-15 03:52:34 +00:00
|
|
|
|
// GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
|
2011-10-13 12:09:22 +00:00
|
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
|
mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
|
|
|
|
|
} else {
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
|
|
|
|
|
}
|
2010-07-15 03:52:34 +00:00
|
|
|
|
if (mGLMaxTextureUnits < 8) {
|
2012-05-23 16:07:29 +00:00
|
|
|
|
GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
|
2011-10-13 12:09:22 +00:00
|
|
|
|
return false;
|
2010-06-10 17:45:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-07-15 03:52:34 +00:00
|
|
|
|
mBound2DTextures.SetLength(mGLMaxTextureUnits);
|
|
|
|
|
mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
|
2014-10-13 23:42:20 +00:00
|
|
|
|
mBound3DTextures.SetLength(mGLMaxTextureUnits);
|
2010-07-15 03:52:34 +00:00
|
|
|
|
|
2011-10-13 12:09:22 +00:00
|
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
|
mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
|
|
|
|
|
mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
|
2012-12-11 21:57:30 +00:00
|
|
|
|
mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
|
2011-10-13 12:09:22 +00:00
|
|
|
|
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
|
|
|
|
|
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
|
|
|
|
|
} else {
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
|
2012-12-11 21:57:30 +00:00
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
|
2011-10-13 12:09:22 +00:00
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
|
|
|
|
|
}
|
2010-07-15 03:52:34 +00:00
|
|
|
|
|
2014-09-03 19:17:18 +00:00
|
|
|
|
// Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize
|
|
|
|
|
mGLMaxTextureSizeLog2 = 0;
|
|
|
|
|
int32_t tempSize = mGLMaxTextureSize;
|
|
|
|
|
while (tempSize >>= 1) {
|
|
|
|
|
++mGLMaxTextureSizeLog2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mGLMaxCubeMapTextureSizeLog2 = 0;
|
|
|
|
|
tempSize = mGLMaxCubeMapTextureSize;
|
|
|
|
|
while (tempSize >>= 1) {
|
|
|
|
|
++mGLMaxCubeMapTextureSizeLog2;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-30 15:07:04 +00:00
|
|
|
|
mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
|
|
|
|
|
mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);
|
|
|
|
|
|
2011-10-13 12:09:22 +00:00
|
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
|
mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
|
|
|
|
|
mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
|
|
|
|
|
mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
|
2010-07-28 21:24:09 +00:00
|
|
|
|
} else {
|
2013-08-22 17:42:05 +00:00
|
|
|
|
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
2011-10-13 12:09:22 +00:00
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
|
|
|
|
|
} else {
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
|
|
|
|
|
mGLMaxFragmentUniformVectors /= 4;
|
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
|
|
|
|
|
mGLMaxVertexUniformVectors /= 4;
|
|
|
|
|
|
|
|
|
|
// we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
|
|
|
|
|
// however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
|
|
|
|
|
// and check OpenGL error for INVALID_ENUM.
|
|
|
|
|
|
|
|
|
|
// On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
|
|
|
|
|
// mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
|
2014-10-24 01:55:49 +00:00
|
|
|
|
GLint maxVertexOutputComponents = 0;
|
|
|
|
|
GLint maxFragmentInputComponents = 0;
|
|
|
|
|
|
|
|
|
|
const bool ok = (gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS,
|
|
|
|
|
&maxVertexOutputComponents) &&
|
|
|
|
|
gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS,
|
|
|
|
|
&maxFragmentInputComponents));
|
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
mGLMaxVaryingVectors = std::min(maxVertexOutputComponents,
|
|
|
|
|
maxFragmentInputComponents) / 4;
|
|
|
|
|
} else {
|
|
|
|
|
mGLMaxVaryingVectors = 16;
|
|
|
|
|
// = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
|
2013-08-20 15:36:20 +00:00
|
|
|
|
}
|
2011-02-11 23:11:30 +00:00
|
|
|
|
}
|
2010-07-28 21:24:09 +00:00
|
|
|
|
}
|
2010-06-10 17:45:00 +00:00
|
|
|
|
|
2010-07-28 21:24:09 +00:00
|
|
|
|
// Always 1 for GLES2
|
2011-06-27 17:27:04 +00:00
|
|
|
|
mMaxFramebufferColorAttachments = 1;
|
2010-06-10 17:45:00 +00:00
|
|
|
|
|
2014-03-31 09:10:49 +00:00
|
|
|
|
if (!gl->IsGLES()) {
|
2010-07-28 21:24:09 +00:00
|
|
|
|
// gl_PointSize is always available in ES2 GLSL, but has to be
|
|
|
|
|
// specifically enabled on desktop GLSL.
|
|
|
|
|
gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
|
2010-09-27 20:20:15 +00:00
|
|
|
|
|
2013-07-02 20:50:34 +00:00
|
|
|
|
// gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
|
|
|
|
|
// not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
|
|
|
|
|
// http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
|
|
|
|
|
// Note that this used to cause crashes on old ATI drivers... hopefully not a significant
|
|
|
|
|
// problem anymore. See bug 602183.
|
|
|
|
|
gl->fEnable(LOCAL_GL_POINT_SPRITE);
|
2010-07-28 21:24:09 +00:00
|
|
|
|
}
|
2010-07-15 03:52:34 +00:00
|
|
|
|
|
2012-07-05 14:13:46 +00:00
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
|
if (gl->WorkAroundDriverBugs() &&
|
2014-10-22 20:57:53 +00:00
|
|
|
|
gl->Vendor() == gl::GLVendor::ATI &&
|
2014-11-11 03:15:22 +00:00
|
|
|
|
!nsCocoaFeatures::IsAtLeastVersion(10,9))
|
2014-10-22 20:57:53 +00:00
|
|
|
|
{
|
2012-07-05 14:13:46 +00:00
|
|
|
|
// The Mac ATI driver, in all known OSX version up to and including 10.8,
|
|
|
|
|
// renders points sprites upside-down. Apple bug 11778921
|
|
|
|
|
gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN, LOCAL_GL_LOWER_LEFT);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2010-08-20 02:50:38 +00:00
|
|
|
|
// Check the shader validator pref
|
2011-10-17 14:59:28 +00:00
|
|
|
|
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
2010-08-10 06:51:56 +00:00
|
|
|
|
|
2011-07-07 02:00:02 +00:00
|
|
|
|
mShaderValidation =
|
|
|
|
|
Preferences::GetBool("webgl.shader_validator", mShaderValidation);
|
2010-08-10 06:51:56 +00:00
|
|
|
|
|
2010-08-20 02:50:38 +00:00
|
|
|
|
// initialize shader translator
|
|
|
|
|
if (mShaderValidation) {
|
|
|
|
|
if (!ShInitialize()) {
|
2012-05-23 16:07:29 +00:00
|
|
|
|
GenerateWarning("GLSL translator initialization failed!");
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-07-15 03:52:34 +00:00
|
|
|
|
}
|
2010-08-10 06:51:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-10 02:30:17 +00:00
|
|
|
|
// Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
|
|
|
|
|
mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
|
|
|
|
|
|
2014-10-24 23:52:35 +00:00
|
|
|
|
// Notice that the point of calling fGetError here is not only to check for
|
|
|
|
|
// errors, but also to reset the error flags so that a subsequent WebGL
|
|
|
|
|
// getError call will give the correct result.
|
|
|
|
|
error = gl->fGetError();
|
2010-09-16 16:45:01 +00:00
|
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
2012-05-23 16:07:29 +00:00
|
|
|
|
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return false;
|
2010-09-16 16:45:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-17 16:13:38 +00:00
|
|
|
|
if (IsWebGL2() &&
|
2013-08-26 21:12:54 +00:00
|
|
|
|
!InitWebGL2())
|
2013-07-17 16:13:38 +00:00
|
|
|
|
{
|
2013-08-06 21:23:46 +00:00
|
|
|
|
// Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
|
2013-07-17 16:13:38 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-12 20:27:19 +00:00
|
|
|
|
// Default value for all disabled vertex attributes is [0, 0, 0, 1]
|
|
|
|
|
for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
|
|
|
|
|
VertexAttrib4f(index, 0, 0, 0, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 23:38:27 +00:00
|
|
|
|
mDefaultVertexArray = WebGLVertexArray::Create(this);
|
2013-10-11 13:16:44 +00:00
|
|
|
|
mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
|
2013-06-27 21:07:21 +00:00
|
|
|
|
mBoundVertexArray = mDefaultVertexArray;
|
|
|
|
|
|
2014-06-22 23:16:00 +00:00
|
|
|
|
if (mLoseContextOnMemoryPressure) {
|
|
|
|
|
mContextObserver->RegisterMemoryPressureEvent();
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
|
return true;
|
2010-06-10 17:45:00 +00:00
|
|
|
|
}
|