2009-09-02 17:47:49 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2012-05-21 04:12:37 -07: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-17 23:01:12 -07:00
|
|
|
|
2009-09-02 17:47:49 -07:00
|
|
|
#include "WebGLContext.h"
|
2013-06-10 13:00:35 -07:00
|
|
|
#include "WebGLBuffer.h"
|
|
|
|
#include "WebGLVertexAttribData.h"
|
|
|
|
#include "WebGLShader.h"
|
|
|
|
#include "WebGLProgram.h"
|
|
|
|
#include "WebGLUniformLocation.h"
|
|
|
|
#include "WebGLFramebuffer.h"
|
|
|
|
#include "WebGLRenderbuffer.h"
|
|
|
|
#include "WebGLTexture.h"
|
2013-06-27 14:07:21 -07:00
|
|
|
#include "WebGLVertexArray.h"
|
2013-09-04 05:14:52 -07:00
|
|
|
#include "GLContext.h"
|
2009-09-02 17:47:49 -07:00
|
|
|
|
2012-05-14 12:50:20 -07:00
|
|
|
#include "mozilla/CheckedInt.h"
|
2012-06-06 00:40:02 -07:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/Services.h"
|
2010-07-03 15:32:19 -07:00
|
|
|
|
2012-01-14 09:43:00 -08:00
|
|
|
#include "jsfriendapi.h"
|
2011-05-20 12:53:53 -07:00
|
|
|
|
2010-07-14 20:52:34 -07:00
|
|
|
#include "angle/ShaderLang.h"
|
|
|
|
|
2012-03-02 12:42:49 -08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2012-07-01 16:45:59 -07:00
|
|
|
#include "mozilla/Services.h"
|
2012-04-21 13:48:22 -07:00
|
|
|
#include "nsIObserverService.h"
|
|
|
|
|
2009-09-02 17:47:49 -07:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2010-06-10 10:45:00 -07:00
|
|
|
/*
|
2012-03-02 12:42:49 -08:00
|
|
|
* Pull data out of the program, post-linking
|
2010-06-10 10:45:00 -07:00
|
|
|
*/
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2012-03-02 12:42:49 -08:00
|
|
|
WebGLProgram::UpdateInfo()
|
2010-06-10 10:45:00 -07:00
|
|
|
{
|
2012-07-30 07:20:58 -07:00
|
|
|
mIdentifierMap = nullptr;
|
|
|
|
mIdentifierReverseMap = nullptr;
|
|
|
|
mUniformInfoMap = nullptr;
|
2012-03-02 12:42:49 -08:00
|
|
|
|
|
|
|
mAttribMaxNameLength = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < mAttachedShaders.Length(); i++)
|
2013-01-15 04:22:03 -08:00
|
|
|
mAttribMaxNameLength = std::max(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
|
2012-03-02 12:42:49 -08:00
|
|
|
|
|
|
|
GLint attribCount;
|
|
|
|
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
|
|
|
|
|
2012-12-08 12:41:02 -08:00
|
|
|
if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
|
|
|
|
mContext->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext->mGLMaxVertexAttribs);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < mAttribsInUse.Length(); i++)
|
|
|
|
mAttribsInUse[i] = false;
|
2010-06-10 10:45:00 -07:00
|
|
|
|
|
|
|
nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
|
|
|
|
|
2012-03-02 12:42:49 -08:00
|
|
|
for (int i = 0; i < attribCount; ++i) {
|
2010-06-10 10:45:00 -07:00
|
|
|
GLint attrnamelen;
|
|
|
|
GLint attrsize;
|
|
|
|
GLenum attrtype;
|
2012-03-02 12:42:49 -08:00
|
|
|
mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
|
2010-06-10 10:45:00 -07:00
|
|
|
if (attrnamelen > 0) {
|
2012-03-02 12:42:49 -08:00
|
|
|
GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
|
2013-10-11 06:16:43 -07:00
|
|
|
MOZ_ASSERT(loc >= 0, "major oops in managing the attributes of a WebGL program");
|
2012-03-02 12:42:49 -08:00
|
|
|
if (loc < mContext->mGLMaxVertexAttribs) {
|
|
|
|
mAttribsInUse[loc] = true;
|
|
|
|
} else {
|
2012-05-29 11:44:31 -07:00
|
|
|
mContext->GenerateWarning("program exceeds MAX_VERTEX_ATTRIBS");
|
2012-03-02 12:42:49 -08:00
|
|
|
return false;
|
|
|
|
}
|
2010-06-10 10:45:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-04 17:51:58 -07:00
|
|
|
if (!mUniformInfoMap) {
|
|
|
|
mUniformInfoMap = new CStringToUniformInfoMap;
|
|
|
|
for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
|
|
|
|
for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
|
|
|
|
const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
|
|
|
|
const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
|
|
|
|
mUniformInfoMap->Put(uniform.mapped, info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 06:01:44 -07:00
|
|
|
mActiveAttribMap.clear();
|
|
|
|
|
|
|
|
GLint numActiveAttrs = 0;
|
|
|
|
mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
|
|
|
|
|
|
|
|
// Spec says the maximum attrib name length is 256 chars, so this is
|
|
|
|
// sufficient to hold any attrib name.
|
|
|
|
char attrName[257];
|
|
|
|
|
|
|
|
GLint dummySize;
|
|
|
|
GLenum dummyType;
|
|
|
|
for (GLint i = 0; i < numActiveAttrs; i++) {
|
|
|
|
mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
|
|
|
|
&dummyType, attrName);
|
|
|
|
GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
|
|
|
|
MOZ_ASSERT(attrLoc >= 0);
|
|
|
|
mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
|
|
|
|
}
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-10 10:45:00 -07:00
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char *info)
|
2010-06-19 07:48:44 -07:00
|
|
|
{
|
|
|
|
switch (mode) {
|
|
|
|
case LOCAL_GL_FUNC_ADD:
|
|
|
|
case LOCAL_GL_FUNC_SUBTRACT:
|
|
|
|
case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2013-07-18 08:24:23 -07:00
|
|
|
case LOCAL_GL_MIN:
|
|
|
|
case LOCAL_GL_MAX:
|
|
|
|
if (IsWebGL2()) {
|
|
|
|
// http://www.opengl.org/registry/specs/EXT/blend_minmax.txt
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
2010-06-19 07:48:44 -07:00
|
|
|
default:
|
2013-07-18 08:24:23 -07:00
|
|
|
break;
|
2010-06-19 07:48:44 -07:00
|
|
|
}
|
2013-07-18 08:24:23 -07:00
|
|
|
|
|
|
|
ErrorInvalidEnumInfo(info, mode);
|
|
|
|
return false;
|
2010-06-19 07:48:44 -07:00
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char *info)
|
2010-06-19 07:48:44 -07: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 07:59:28 -07:00
|
|
|
return true;
|
2010-06-19 07:48:44 -07:00
|
|
|
default:
|
2010-07-16 07:31:48 -07:00
|
|
|
ErrorInvalidEnumInfo(info, factor);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-19 07:48:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char *info)
|
2010-06-19 07:48:44 -07:00
|
|
|
{
|
2010-06-30 08:49:59 -07:00
|
|
|
if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-19 07:48:44 -07:00
|
|
|
else
|
2010-06-30 08:49:59 -07:00
|
|
|
return ValidateBlendFuncDstEnum(factor, info);
|
2010-06-19 07:48:44 -07:00
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info)
|
2010-12-06 03:34:35 -08:00
|
|
|
{
|
2011-09-28 23:19:26 -07:00
|
|
|
bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
|
2010-12-06 03:34:35 -08:00
|
|
|
sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
|
2010-12-06 03:34:35 -08:00
|
|
|
sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
|
2010-12-06 03:34:35 -08:00
|
|
|
dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
|
2011-09-28 23:19:26 -07:00
|
|
|
bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
|
2010-12-06 03:34:35 -08: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 07:59:28 -07:00
|
|
|
return false;
|
2010-12-06 03:34:35 -08:00
|
|
|
} else {
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-12-06 03:34:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
|
2010-06-30 08:48:30 -07:00
|
|
|
{
|
|
|
|
switch (target) {
|
|
|
|
case LOCAL_GL_TEXTURE_2D:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:48:30 -07:00
|
|
|
default:
|
2010-07-16 07:31:48 -07:00
|
|
|
ErrorInvalidEnumInfo(info, target);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-30 08:48:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateComparisonEnum(GLenum target, const char *info)
|
2010-06-30 08:48:30 -07: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 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:48:30 -07:00
|
|
|
default:
|
2010-07-16 07:31:48 -07:00
|
|
|
ErrorInvalidEnumInfo(info, target);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-30 08:48:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char *info)
|
2010-06-30 08:48:30 -07: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 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:48:30 -07:00
|
|
|
default:
|
2010-07-16 07:31:48 -07:00
|
|
|
ErrorInvalidEnumInfo(info, action);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-30 08:48:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateFaceEnum(GLenum face, const char *info)
|
2010-06-30 08:48:30 -07:00
|
|
|
{
|
2010-07-16 07:31:48 -07:00
|
|
|
switch (face) {
|
2010-06-30 08:48:30 -07:00
|
|
|
case LOCAL_GL_FRONT:
|
|
|
|
case LOCAL_GL_BACK:
|
|
|
|
case LOCAL_GL_FRONT_AND_BACK:
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:48:30 -07:00
|
|
|
default:
|
2010-07-16 07:31:48 -07:00
|
|
|
ErrorInvalidEnumInfo(info, face);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-30 08:48:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char *info)
|
2010-07-16 07:31:48 -07: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 07:59:28 -07:00
|
|
|
return true;
|
2010-07-16 07:31:48 -07:00
|
|
|
default:
|
|
|
|
ErrorInvalidEnumInfo(info, mode);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-07-03 15:34:07 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-07 14:17:44 -07:00
|
|
|
bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
|
2011-07-28 14:12:31 -07:00
|
|
|
{
|
2012-06-15 14:39:21 -07:00
|
|
|
if (name.IsEmpty())
|
|
|
|
return false;
|
|
|
|
|
2012-05-23 09:07:01 -07:00
|
|
|
const uint32_t maxSize = 256;
|
2011-07-28 14:12:31 -07: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 14:17:44 -07:00
|
|
|
|
|
|
|
if (!ValidateGLSLString(name, info)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-03-05 13:36:06 -08: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 14:17:44 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
|
|
|
|
{
|
2012-05-23 09:07:01 -07:00
|
|
|
for (uint32_t i = 0; i < string.Length(); ++i) {
|
2011-09-07 14:17:44 -07:00
|
|
|
if (!ValidateGLSLCharacter(string.CharAt(i))) {
|
|
|
|
ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-28 14:12:31 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateTexImage2DTarget(GLenum target, GLsizei width, GLsizei height,
|
2012-05-08 10:29:31 -07:00
|
|
|
const char* info)
|
|
|
|
{
|
|
|
|
switch (target) {
|
|
|
|
case LOCAL_GL_TEXTURE_2D:
|
|
|
|
break;
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
|
|
|
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
|
|
|
if (width != height) {
|
|
|
|
ErrorInvalidValue("%s: with cube map targets, width and height must be equal", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ErrorInvalidEnum("%s: invalid target enum 0x%x", info, target);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateCompressedTextureSize(GLenum target, GLint level,
|
|
|
|
GLenum format,
|
|
|
|
GLsizei width, GLsizei height, uint32_t byteLength, const char* info)
|
2012-05-08 10:29:31 -07:00
|
|
|
{
|
2012-09-25 05:49:28 -07:00
|
|
|
if (!ValidateLevelWidthHeightForTarget(target, level, width, height, info)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// negative width and height must already have been handled above
|
|
|
|
MOZ_ASSERT(width >= 0 && height >= 0);
|
|
|
|
|
2012-09-25 05:49:28 -07:00
|
|
|
CheckedUint32 required_byteLength = 0;
|
2012-05-08 10:29:31 -07:00
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_ATC_RGB:
|
2012-05-08 10:29:31 -07:00
|
|
|
{
|
2012-09-25 05:49:28 -07:00
|
|
|
required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
|
2012-05-08 10:29:31 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
2012-05-08 10:29:31 -07:00
|
|
|
{
|
2012-09-25 05:49:28 -07:00
|
|
|
required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
|
2012-05-08 10:29:31 -07:00
|
|
|
break;
|
|
|
|
}
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
|
|
|
|
{
|
2013-01-15 04:22:03 -08:00
|
|
|
required_byteLength = CheckedUint32(std::max(width, 8)) * CheckedUint32(std::max(height, 8)) / 2;
|
2012-09-25 05:49:28 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
|
|
|
|
{
|
2013-01-15 04:22:03 -08:00
|
|
|
required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
|
2012-09-25 05:49:28 -07:00
|
|
|
break;
|
|
|
|
}
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
|
|
|
|
2012-09-25 05:49:28 -07:00
|
|
|
if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
|
|
|
|
ErrorInvalidValue("%s: data size does not match dimensions", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-08 10:29:31 -07:00
|
|
|
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:
|
|
|
|
{
|
|
|
|
if (level == 0 && width % 4 == 0 && height % 4 == 0) {
|
2012-09-25 05:49:28 -07:00
|
|
|
break;
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
|
|
|
if (level > 0
|
|
|
|
&& (width == 0 || width == 1 || width == 2 || width % 4 == 0)
|
|
|
|
&& (height == 0 || height == 1 || height == 2 || height % 4 == 0))
|
|
|
|
{
|
2012-09-25 05:49:28 -07:00
|
|
|
break;
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
2012-09-25 05:49:28 -07:00
|
|
|
ErrorInvalidOperation("%s: level parameter does not match width and height", info);
|
|
|
|
return false;
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
2012-09-25 05:49:28 -07:00
|
|
|
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", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
|
|
|
|
2012-09-25 05:49:28 -07:00
|
|
|
return true;
|
2012-05-08 10:29:31 -07:00
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateLevelWidthHeightForTarget(GLenum target, GLint level, GLsizei width,
|
|
|
|
GLsizei height, const char* info)
|
2012-05-08 10:29:31 -07:00
|
|
|
{
|
2013-09-04 05:14:43 -07:00
|
|
|
GLsizei maxTextureSize = MaxTextureSizeForTarget(target);
|
2012-05-08 10:29:31 -07:00
|
|
|
|
|
|
|
if (level < 0) {
|
|
|
|
ErrorInvalidValue("%s: level must be >= 0", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
GLsizei maxAllowedSize = maxTextureSize >> level;
|
2012-10-09 11:21:22 -07:00
|
|
|
|
|
|
|
if (!maxAllowedSize) {
|
2012-05-23 15:05:48 -07:00
|
|
|
ErrorInvalidValue("%s: 2^level exceeds maximum texture size", info);
|
2012-05-08 10:29:31 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (width < 0 || height < 0) {
|
2012-05-23 15:05:48 -07:00
|
|
|
ErrorInvalidValue("%s: width and height must be >= 0", info);
|
2012-05-08 10:29:31 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-09 11:21:22 -07:00
|
|
|
if (width > maxAllowedSize || height > maxAllowedSize) {
|
|
|
|
ErrorInvalidValue("%s: the maximum texture size for level %d is %d", info, level, maxAllowedSize);
|
2012-05-08 10:29:31 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
uint32_t WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
|
2011-07-07 17:01:12 -07:00
|
|
|
{
|
2012-06-27 16:11:00 -07:00
|
|
|
// If there is no defined format or type, we're not taking up any memory
|
|
|
|
if (!format || !type) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-13 18:17:55 -07:00
|
|
|
if (format == LOCAL_GL_DEPTH_COMPONENT) {
|
|
|
|
if (type == LOCAL_GL_UNSIGNED_SHORT)
|
|
|
|
return 2;
|
|
|
|
else if (type == LOCAL_GL_UNSIGNED_INT)
|
|
|
|
return 4;
|
|
|
|
} else if (format == LOCAL_GL_DEPTH_STENCIL) {
|
|
|
|
if (type == LOCAL_GL_UNSIGNED_INT_24_8_EXT)
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
|
2011-07-07 17:01:12 -07:00
|
|
|
if (type == LOCAL_GL_UNSIGNED_BYTE || type == LOCAL_GL_FLOAT) {
|
2012-05-08 10:29:31 -07:00
|
|
|
int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
|
2011-07-07 17:01:12 -07:00
|
|
|
switch (format) {
|
|
|
|
case LOCAL_GL_ALPHA:
|
|
|
|
case LOCAL_GL_LUMINANCE:
|
|
|
|
return 1 * multiplier;
|
|
|
|
case LOCAL_GL_LUMINANCE_ALPHA:
|
|
|
|
return 2 * multiplier;
|
|
|
|
case LOCAL_GL_RGB:
|
|
|
|
return 3 * multiplier;
|
|
|
|
case LOCAL_GL_RGBA:
|
|
|
|
return 4 * multiplier;
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
|
|
|
|
return 2;
|
2012-05-08 10:29:31 -07:00
|
|
|
case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_ATC_RGB:
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
|
2012-05-08 10:29:31 -07:00
|
|
|
return 4;
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
|
|
|
|
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
|
2012-09-25 05:49:28 -07:00
|
|
|
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
|
|
|
|
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
|
2012-05-08 10:29:31 -07:00
|
|
|
return 8;
|
2011-07-07 17:01:12 -07:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
|
|
|
|
type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
|
|
|
|
type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
|
|
|
|
{
|
2012-05-08 10:29:31 -07:00
|
|
|
return 16;
|
2011-07-07 17:01:12 -07:00
|
|
|
}
|
|
|
|
|
2013-10-11 06:16:43 -07:00
|
|
|
MOZ_ASSERT(false);
|
2011-07-07 17:01:12 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateTexFormatAndType(GLenum format, GLenum type, int jsArrayType,
|
2012-05-23 09:07:01 -07:00
|
|
|
uint32_t *texelSize, const char *info)
|
2010-06-30 08:49:59 -07:00
|
|
|
{
|
2012-08-13 18:17:55 -07:00
|
|
|
if (IsExtensionEnabled(WEBGL_depth_texture)) {
|
|
|
|
if (format == LOCAL_GL_DEPTH_COMPONENT) {
|
|
|
|
if (jsArrayType != -1) {
|
|
|
|
if ((type == LOCAL_GL_UNSIGNED_SHORT && jsArrayType != js::ArrayBufferView::TYPE_UINT16) ||
|
|
|
|
(type == LOCAL_GL_UNSIGNED_INT && jsArrayType != js::ArrayBufferView::TYPE_UINT32)) {
|
|
|
|
ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT:
|
|
|
|
*texelSize = 2;
|
|
|
|
break;
|
|
|
|
case LOCAL_GL_UNSIGNED_INT:
|
|
|
|
*texelSize = 4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ErrorInvalidOperation("%s: invalid type 0x%x", info, type);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} else if (format == LOCAL_GL_DEPTH_STENCIL) {
|
|
|
|
if (type != LOCAL_GL_UNSIGNED_INT_24_8_EXT) {
|
|
|
|
ErrorInvalidOperation("%s: invalid format 0x%x", info, format);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (jsArrayType != -1) {
|
|
|
|
if (jsArrayType != js::ArrayBufferView::TYPE_UINT32) {
|
|
|
|
ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*texelSize = 4;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-20 12:53:53 -07:00
|
|
|
if (type == LOCAL_GL_UNSIGNED_BYTE ||
|
2012-06-15 22:12:30 -07:00
|
|
|
(IsExtensionEnabled(OES_texture_float) && type == LOCAL_GL_FLOAT))
|
2010-06-30 08:49:59 -07:00
|
|
|
{
|
2011-05-20 12:53:53 -07:00
|
|
|
if (jsArrayType != -1) {
|
2012-01-14 09:43:00 -08:00
|
|
|
if ((type == LOCAL_GL_UNSIGNED_BYTE && jsArrayType != js::ArrayBufferView::TYPE_UINT8) ||
|
|
|
|
(type == LOCAL_GL_FLOAT && jsArrayType != js::ArrayBufferView::TYPE_FLOAT32))
|
2011-05-20 12:53:53 -07:00
|
|
|
{
|
2012-01-14 09:43:00 -08:00
|
|
|
ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int texMultiplier = type == LOCAL_GL_FLOAT ? 4 : 1;
|
2010-06-30 08:49:59 -07:00
|
|
|
switch (format) {
|
|
|
|
case LOCAL_GL_ALPHA:
|
|
|
|
case LOCAL_GL_LUMINANCE:
|
2011-05-20 12:53:53 -07:00
|
|
|
*texelSize = 1 * texMultiplier;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:49:59 -07:00
|
|
|
case LOCAL_GL_LUMINANCE_ALPHA:
|
2011-05-20 12:53:53 -07:00
|
|
|
*texelSize = 2 * texMultiplier;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:49:59 -07:00
|
|
|
case LOCAL_GL_RGB:
|
2011-05-20 12:53:53 -07:00
|
|
|
*texelSize = 3 * texMultiplier;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:49:59 -07:00
|
|
|
case LOCAL_GL_RGBA:
|
2011-05-20 12:53:53 -07:00
|
|
|
*texelSize = 4 * texMultiplier;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-30 08:49:59 -07:00
|
|
|
default:
|
2011-05-20 12:53:53 -07:00
|
|
|
break;
|
2010-06-30 08:49:59 -07:00
|
|
|
}
|
2011-05-20 12:53:53 -07:00
|
|
|
|
|
|
|
ErrorInvalidEnum("%s: invalid format 0x%x", info, format);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
2012-01-14 09:43:00 -08:00
|
|
|
if (jsArrayType != -1 && jsArrayType != js::ArrayBufferView::TYPE_UINT16) {
|
|
|
|
ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (format == LOCAL_GL_RGBA) {
|
|
|
|
*texelSize = 2;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
ErrorInvalidOperation("%s: mutually incompatible format and type", info);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
|
|
|
|
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
2012-01-14 09:43:00 -08:00
|
|
|
if (jsArrayType != -1 && jsArrayType != js::ArrayBufferView::TYPE_UINT16) {
|
|
|
|
ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (format == LOCAL_GL_RGB) {
|
|
|
|
*texelSize = 2;
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
ErrorInvalidOperation("%s: mutually incompatible format and type", info);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2010-06-30 08:49:59 -07:00
|
|
|
}
|
2011-05-20 12:53:53 -07:00
|
|
|
|
|
|
|
ErrorInvalidEnum("%s: invalid type 0x%x", info, type);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-06-30 08:49:59 -07:00
|
|
|
}
|
|
|
|
|
2012-10-16 05:17:01 -07: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-04 16:44:31 -08:00
|
|
|
bool
|
2013-09-04 05:14:43 -07:00
|
|
|
WebGLContext::ValidateSamplerUniformSetter(const char* info, WebGLUniformLocation *location, GLint value)
|
2013-03-04 16:44:31 -08:00
|
|
|
{
|
|
|
|
if (location->Info().type != SH_SAMPLER_2D &&
|
|
|
|
location->Info().type != SH_SAMPLER_CUBE)
|
|
|
|
{
|
|
|
|
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 05:17:01 -07:00
|
|
|
bool
|
|
|
|
WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
|
|
|
|
{
|
2013-09-04 05:14:44 -07:00
|
|
|
if (IsContextLost()) {
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (arrayLength < cnt) {
|
|
|
|
ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
|
|
|
|
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
|
|
|
|
{
|
2013-09-04 05:14:44 -07:00
|
|
|
if (IsContextLost())
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
2013-01-25 10:40:38 -08:00
|
|
|
if (!ValidateUniformLocation(name, location_object))
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
|
|
|
location = location_object->Location();
|
|
|
|
uint32_t uniformElemSize = location_object->ElementSize();
|
|
|
|
if (expectedElemSize != uniformElemSize) {
|
|
|
|
ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
|
|
|
|
" got a uniform of element size %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
uniformElemSize);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (arrayLength == 0 ||
|
|
|
|
arrayLength % expectedElemSize)
|
|
|
|
{
|
|
|
|
ErrorInvalidValue("%s: expected an array of length a multiple"
|
|
|
|
" of %d, got an array of length %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
arrayLength);
|
|
|
|
return false;
|
|
|
|
}
|
2013-01-25 10:40:38 -08:00
|
|
|
const WebGLUniformInfo& info = location_object->Info();
|
2012-10-16 05:17:01 -07:00
|
|
|
if (!info.isArray &&
|
|
|
|
arrayLength != expectedElemSize) {
|
|
|
|
ErrorInvalidOperation("%s: expected an array of length exactly"
|
|
|
|
" %d (since this uniform is not an array"
|
|
|
|
" uniform), got an array of length %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
arrayLength);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
numElementsToUpload =
|
2013-01-15 04:22:03 -08:00
|
|
|
std::min(info.arraySize, arrayLength / expectedElemSize);
|
2012-10-16 05:17:01 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
|
|
|
|
GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
|
|
|
|
WebGLboolean aTranspose)
|
|
|
|
{
|
|
|
|
uint32_t expectedElemSize = (dim)*(dim);
|
2013-09-04 05:14:44 -07:00
|
|
|
if (IsContextLost())
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
2013-01-25 10:40:38 -08:00
|
|
|
if (!ValidateUniformLocation(name, location_object))
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
|
|
|
location = location_object->Location();
|
|
|
|
uint32_t uniformElemSize = location_object->ElementSize();
|
|
|
|
if (expectedElemSize != uniformElemSize) {
|
|
|
|
ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
|
|
|
|
" got a uniform of element size %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
uniformElemSize);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (arrayLength == 0 ||
|
|
|
|
arrayLength % expectedElemSize)
|
|
|
|
{
|
|
|
|
ErrorInvalidValue("%s: expected an array of length a multiple"
|
|
|
|
" of %d, got an array of length %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
arrayLength);
|
|
|
|
return false;
|
|
|
|
}
|
2013-01-25 10:40:38 -08:00
|
|
|
const WebGLUniformInfo& info = location_object->Info();
|
2012-10-16 05:17:01 -07:00
|
|
|
if (!info.isArray &&
|
|
|
|
arrayLength != expectedElemSize) {
|
|
|
|
ErrorInvalidOperation("%s: expected an array of length exactly"
|
|
|
|
" %d (since this uniform is not an array"
|
|
|
|
" uniform), got an array of length %d", name,
|
|
|
|
expectedElemSize,
|
|
|
|
arrayLength);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (aTranspose) {
|
|
|
|
ErrorInvalidValue("%s: transpose must be FALSE as per the "
|
|
|
|
"OpenGL ES 2.0 spec", name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
numElementsToUpload =
|
2013-01-15 04:22:03 -08:00
|
|
|
std::min(info.arraySize, arrayLength / (expectedElemSize));
|
2012-10-16 05:17:01 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
|
|
|
|
{
|
2013-09-04 05:14:44 -07:00
|
|
|
if (IsContextLost())
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
2013-01-25 10:40:38 -08:00
|
|
|
if (!ValidateUniformLocation(name, location_object))
|
2012-10-16 05:17:01 -07:00
|
|
|
return false;
|
|
|
|
location = location_object->Location();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-04 05:14:43 -07:00
|
|
|
bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
|
2011-02-24 14:17:34 -08:00
|
|
|
{
|
2013-06-27 14:07:21 -07:00
|
|
|
return mBoundVertexArray->EnsureAttribIndex(index, info);
|
2011-02-24 14:17:34 -08:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool WebGLContext::ValidateStencilParamsForDrawCall()
|
2011-05-20 12:53:53 -07: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 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
if (mStencilValueMaskFront != mStencilValueMaskBack) {
|
|
|
|
ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
|
|
|
|
ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2011-05-20 12:53:53 -07:00
|
|
|
}
|
|
|
|
|
2013-07-30 08:07:04 -07: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-28 23:19:26 -07:00
|
|
|
bool
|
2010-06-14 11:44:12 -07:00
|
|
|
WebGLContext::InitAndValidateGL()
|
2010-06-10 10:45:00 -07:00
|
|
|
{
|
2011-10-17 07:59:28 -07:00
|
|
|
if (!gl) return false;
|
2010-06-14 11:44:12 -07:00
|
|
|
|
2011-02-11 15:11:30 -08:00
|
|
|
GLenum error = gl->fGetError();
|
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-02-11 15:11:30 -08:00
|
|
|
}
|
|
|
|
|
2011-10-13 05:09:22 -07:00
|
|
|
mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
|
|
|
|
mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
|
2012-12-07 18:00:42 -08:00
|
|
|
mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
|
2013-01-03 15:39:25 -08:00
|
|
|
mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
|
2011-10-13 05:09:22 -07:00
|
|
|
|
2013-05-15 14:50:52 -07:00
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
mDisableFragHighP = true;
|
|
|
|
}
|
|
|
|
|
2010-06-14 11:44:12 -07:00
|
|
|
mActiveTexture = 0;
|
2011-07-07 17:01:16 -07:00
|
|
|
mWebGLError = LOCAL_GL_NO_ERROR;
|
2010-06-14 11:44:12 -07:00
|
|
|
|
|
|
|
mBound2DTextures.Clear();
|
|
|
|
mBoundCubeMapTextures.Clear();
|
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mBoundArrayBuffer = nullptr;
|
2013-08-20 08:36:20 -07:00
|
|
|
mBoundTransformFeedbackBuffer = nullptr;
|
2012-07-30 07:20:58 -07:00
|
|
|
mCurrentProgram = nullptr;
|
2010-06-14 11:44:12 -07:00
|
|
|
|
2012-07-30 07:20:58 -07:00
|
|
|
mBoundFramebuffer = nullptr;
|
|
|
|
mBoundRenderbuffer = nullptr;
|
2010-06-14 11:44:12 -07:00
|
|
|
|
2010-07-18 22:01:14 -07:00
|
|
|
MakeContextCurrent();
|
2010-06-10 10:45:00 -07:00
|
|
|
|
2010-09-02 07:34:08 -07:00
|
|
|
// on desktop OpenGL, we always keep vertex attrib 0 array enabled
|
|
|
|
if (!gl->IsGLES2()) {
|
|
|
|
gl->fEnableVertexAttribArray(0);
|
|
|
|
}
|
|
|
|
|
2011-10-13 05:09:22 -07:00
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
|
|
|
|
} else {
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
|
|
|
|
}
|
2010-07-14 20:52:34 -07:00
|
|
|
if (mGLMaxVertexAttribs < 8) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
|
2011-10-13 05:09:22 -07:00
|
|
|
return false;
|
2010-06-10 10:45:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
|
|
|
|
// even though the hardware supports much more. The
|
2010-07-14 20:52:34 -07:00
|
|
|
// GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
|
2011-10-13 05:09:22 -07:00
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
|
|
|
|
} else {
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
|
|
|
|
}
|
2010-07-14 20:52:34 -07:00
|
|
|
if (mGLMaxTextureUnits < 8) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
|
2011-10-13 05:09:22 -07:00
|
|
|
return false;
|
2010-06-10 10:45:00 -07:00
|
|
|
}
|
|
|
|
|
2010-07-14 20:52:34 -07:00
|
|
|
mBound2DTextures.SetLength(mGLMaxTextureUnits);
|
|
|
|
mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
|
|
|
|
|
2011-10-13 05:09:22 -07:00
|
|
|
if (MinCapabilityMode()) {
|
|
|
|
mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
|
|
|
|
mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
|
2012-12-11 13:57:30 -08:00
|
|
|
mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
|
2011-10-13 05:09:22 -07: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 13:57:30 -08:00
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
|
2011-10-13 05:09:22 -07:00
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
|
|
|
|
}
|
2010-07-14 20:52:34 -07:00
|
|
|
|
2013-07-30 08:07:04 -07:00
|
|
|
mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
|
|
|
|
mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);
|
|
|
|
|
2011-10-13 05:09:22 -07: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 14:24:09 -07:00
|
|
|
} else {
|
2013-08-22 10:42:05 -07:00
|
|
|
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
2011-10-13 05:09:22 -07: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.
|
|
|
|
|
|
|
|
// before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
|
|
|
|
error = gl->GetAndClearError();
|
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
2011-10-13 05:09:22 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
GLint maxVertexOutputComponents,
|
|
|
|
minFragmentInputComponents;
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
|
|
|
|
gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
|
|
|
|
|
|
|
|
error = gl->GetAndClearError();
|
|
|
|
switch (error) {
|
|
|
|
case LOCAL_GL_NO_ERROR:
|
2013-01-15 04:22:03 -08:00
|
|
|
mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
|
2011-10-13 05:09:22 -07:00
|
|
|
break;
|
|
|
|
case LOCAL_GL_INVALID_ENUM:
|
|
|
|
mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
|
|
|
|
break;
|
|
|
|
default:
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
2011-10-13 05:09:22 -07:00
|
|
|
return false;
|
2013-08-20 08:36:20 -07:00
|
|
|
}
|
2011-02-11 15:11:30 -08:00
|
|
|
}
|
2010-07-28 14:24:09 -07:00
|
|
|
}
|
2010-06-10 10:45:00 -07:00
|
|
|
|
2010-07-28 14:24:09 -07:00
|
|
|
// Always 1 for GLES2
|
2011-06-27 10:27:04 -07:00
|
|
|
mMaxFramebufferColorAttachments = 1;
|
2010-06-10 10:45:00 -07:00
|
|
|
|
2010-07-28 14:24:09 -07:00
|
|
|
if (!gl->IsGLES2()) {
|
|
|
|
// 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 13:20:15 -07:00
|
|
|
|
2013-07-02 13:50:34 -07: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 14:24:09 -07:00
|
|
|
}
|
2010-07-14 20:52:34 -07:00
|
|
|
|
2012-07-05 07:13:46 -07:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
if (gl->WorkAroundDriverBugs() &&
|
|
|
|
gl->Vendor() == gl::GLContext::VendorATI) {
|
|
|
|
// 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-19 19:50:38 -07:00
|
|
|
// Check the shader validator pref
|
2011-10-17 07:59:28 -07:00
|
|
|
NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
|
2010-08-09 23:51:56 -07:00
|
|
|
|
2011-07-06 19:00:02 -07:00
|
|
|
mShaderValidation =
|
|
|
|
Preferences::GetBool("webgl.shader_validator", mShaderValidation);
|
2010-08-09 23:51:56 -07:00
|
|
|
|
2010-08-19 19:50:38 -07:00
|
|
|
// initialize shader translator
|
|
|
|
if (mShaderValidation) {
|
|
|
|
if (!ShInitialize()) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GLSL translator initialization failed!");
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-07-14 20:52:34 -07:00
|
|
|
}
|
2010-08-09 23:51:56 -07:00
|
|
|
}
|
|
|
|
|
2012-08-09 19:30:17 -07: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");
|
|
|
|
|
2011-07-07 17:01:16 -07:00
|
|
|
// notice that the point of calling GetAndClearError here is not only to check for error,
|
|
|
|
// it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
|
|
|
|
error = gl->GetAndClearError();
|
2010-09-16 09:45:01 -07:00
|
|
|
if (error != LOCAL_GL_NO_ERROR) {
|
2012-05-23 09:07:29 -07:00
|
|
|
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-09-16 09:45:01 -07:00
|
|
|
}
|
|
|
|
|
2013-07-17 09:13:38 -07:00
|
|
|
if (IsWebGL2() &&
|
2013-08-26 14:12:54 -07:00
|
|
|
!InitWebGL2())
|
2013-07-17 09:13:38 -07:00
|
|
|
{
|
2013-08-06 14:23:46 -07:00
|
|
|
// Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
|
2013-07-17 09:13:38 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-04-21 13:48:22 -07:00
|
|
|
mMemoryPressureObserver
|
|
|
|
= new WebGLMemoryPressureObserver(this);
|
|
|
|
nsCOMPtr<nsIObserverService> observerService
|
|
|
|
= mozilla::services::GetObserverService();
|
|
|
|
if (observerService) {
|
|
|
|
observerService->AddObserver(mMemoryPressureObserver,
|
|
|
|
"memory-pressure",
|
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2013-06-27 14:07:21 -07:00
|
|
|
mDefaultVertexArray = new WebGLVertexArray(this);
|
|
|
|
mDefaultVertexArray->mAttribBuffers.SetLength(mGLMaxVertexAttribs);
|
|
|
|
mBoundVertexArray = mDefaultVertexArray;
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-06-10 10:45:00 -07:00
|
|
|
}
|