mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
b=1010371, code fixes for new ANGLE version; r=jrmuizel
This commit is contained in:
parent
f1e3bb166d
commit
997131305a
341
content/canvas/src/MurmurHash3.cpp
Normal file
341
content/canvas/src/MurmurHash3.cpp
Normal file
@ -0,0 +1,341 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
// Note - The x86 and x64 versions do _not_ produce the same results, as the
|
||||
// algorithms are optimized for their respective platforms. You can still
|
||||
// compile and run any of them on any platform, but your performance with the
|
||||
// non-native version will be less than optimal.
|
||||
|
||||
#include "MurmurHash3.h"
|
||||
|
||||
namespace {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Platform-specific functions and macros
|
||||
|
||||
// Microsoft Visual Studio
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#define FORCE_INLINE __forceinline
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ROTL32(x,y) _rotl(x,y)
|
||||
#define ROTL64(x,y) _rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else // defined(_MSC_VER)
|
||||
|
||||
// We can't do always_inline, becasue -Werror -Wattribute will trigger
|
||||
// a "might not be able to inline" warning.
|
||||
//#define FORCE_INLINE __attribute__((always_inline))
|
||||
#define FORCE_INLINE inline
|
||||
|
||||
inline uint32_t rotl32 ( uint32_t x, int8_t r )
|
||||
{
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
inline uint64_t rotl64 ( uint64_t x, int8_t r )
|
||||
{
|
||||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
#define ROTL32(x,y) rotl32(x,y)
|
||||
#define ROTL64(x,y) rotl64(x,y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
FORCE_INLINE uint32_t getblock ( const uint32_t * p, int i )
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
FORCE_INLINE uint64_t getblock ( const uint64_t * p, int i )
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
FORCE_INLINE uint32_t fmix ( uint32_t h )
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//----------
|
||||
|
||||
FORCE_INLINE uint64_t fmix ( uint64_t k )
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_32 ( const void * key, int len,
|
||||
uint32_t seed, void * out )
|
||||
{
|
||||
const uint8_t * data = (const uint8_t*)key;
|
||||
const int nblocks = len / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
|
||||
|
||||
for(int i = -nblocks; i; i++)
|
||||
{
|
||||
uint32_t k1 = getblock(blocks,i);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1,15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROTL32(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch(len & 3)
|
||||
{
|
||||
case 3: k1 ^= tail[2] << 16;
|
||||
case 2: k1 ^= tail[1] << 8;
|
||||
case 1: k1 ^= tail[0];
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 = fmix(h1);
|
||||
|
||||
*(uint32_t*)out = h1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_128 ( const void * key, const int len,
|
||||
uint32_t seed, void * out )
|
||||
{
|
||||
const uint8_t * data = (const uint8_t*)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
uint32_t h2 = seed;
|
||||
uint32_t h3 = seed;
|
||||
uint32_t h4 = seed;
|
||||
|
||||
const uint32_t c1 = 0x239b961b;
|
||||
const uint32_t c2 = 0xab0e9789;
|
||||
const uint32_t c3 = 0x38b34ae5;
|
||||
const uint32_t c4 = 0xa1e38b93;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32_t * blocks = (const uint32_t *)(data + nblocks*16);
|
||||
|
||||
for(int i = -nblocks; i; i++)
|
||||
{
|
||||
uint32_t k1 = getblock(blocks,i*4+0);
|
||||
uint32_t k2 = getblock(blocks,i*4+1);
|
||||
uint32_t k3 = getblock(blocks,i*4+2);
|
||||
uint32_t k4 = getblock(blocks,i*4+3);
|
||||
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
|
||||
h1 = ROTL32(h1,19); h1 += h2; h1 = h1*5+0x561ccd1b;
|
||||
|
||||
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||
|
||||
h2 = ROTL32(h2,17); h2 += h3; h2 = h2*5+0x0bcaa747;
|
||||
|
||||
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||
|
||||
h3 = ROTL32(h3,15); h3 += h4; h3 = h3*5+0x96cd1c35;
|
||||
|
||||
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||
|
||||
h4 = ROTL32(h4,13); h4 += h1; h4 = h4*5+0x32ac3b17;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
uint32_t k2 = 0;
|
||||
uint32_t k3 = 0;
|
||||
uint32_t k4 = 0;
|
||||
|
||||
switch(len & 15)
|
||||
{
|
||||
case 15: k4 ^= tail[14] << 16;
|
||||
case 14: k4 ^= tail[13] << 8;
|
||||
case 13: k4 ^= tail[12] << 0;
|
||||
k4 *= c4; k4 = ROTL32(k4,18); k4 *= c1; h4 ^= k4;
|
||||
|
||||
case 12: k3 ^= tail[11] << 24;
|
||||
case 11: k3 ^= tail[10] << 16;
|
||||
case 10: k3 ^= tail[ 9] << 8;
|
||||
case 9: k3 ^= tail[ 8] << 0;
|
||||
k3 *= c3; k3 = ROTL32(k3,17); k3 *= c4; h3 ^= k3;
|
||||
|
||||
case 8: k2 ^= tail[ 7] << 24;
|
||||
case 7: k2 ^= tail[ 6] << 16;
|
||||
case 6: k2 ^= tail[ 5] << 8;
|
||||
case 5: k2 ^= tail[ 4] << 0;
|
||||
k2 *= c2; k2 = ROTL32(k2,16); k2 *= c3; h2 ^= k2;
|
||||
|
||||
case 4: k1 ^= tail[ 3] << 24;
|
||||
case 3: k1 ^= tail[ 2] << 16;
|
||||
case 2: k1 ^= tail[ 1] << 8;
|
||||
case 1: k1 ^= tail[ 0] << 0;
|
||||
k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
|
||||
|
||||
h1 += h2; h1 += h3; h1 += h4;
|
||||
h2 += h1; h3 += h1; h4 += h1;
|
||||
|
||||
h1 = fmix(h1);
|
||||
h2 = fmix(h2);
|
||||
h3 = fmix(h3);
|
||||
h4 = fmix(h4);
|
||||
|
||||
h1 += h2; h1 += h3; h1 += h4;
|
||||
h2 += h1; h3 += h1; h4 += h1;
|
||||
|
||||
((uint32_t*)out)[0] = h1;
|
||||
((uint32_t*)out)[1] = h2;
|
||||
((uint32_t*)out)[2] = h3;
|
||||
((uint32_t*)out)[3] = h4;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x64_128 ( const void * key, const int len,
|
||||
const uint32_t seed, void * out )
|
||||
{
|
||||
const uint8_t * data = (const uint8_t*)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint64_t h1 = seed;
|
||||
uint64_t h2 = seed;
|
||||
|
||||
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint64_t * blocks = (const uint64_t *)(data);
|
||||
|
||||
for(int i = 0; i < nblocks; i++)
|
||||
{
|
||||
uint64_t k1 = getblock(blocks,i*2+0);
|
||||
uint64_t k2 = getblock(blocks,i*2+1);
|
||||
|
||||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
|
||||
h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||
|
||||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
|
||||
h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t * tail = (const uint8_t*)(data + nblocks*16);
|
||||
|
||||
uint64_t k1 = 0;
|
||||
uint64_t k2 = 0;
|
||||
|
||||
switch(len & 15)
|
||||
{
|
||||
case 15: k2 ^= uint64_t(tail[14]) << 48;
|
||||
case 14: k2 ^= uint64_t(tail[13]) << 40;
|
||||
case 13: k2 ^= uint64_t(tail[12]) << 32;
|
||||
case 12: k2 ^= uint64_t(tail[11]) << 24;
|
||||
case 11: k2 ^= uint64_t(tail[10]) << 16;
|
||||
case 10: k2 ^= uint64_t(tail[ 9]) << 8;
|
||||
case 9: k2 ^= uint64_t(tail[ 8]) << 0;
|
||||
k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
|
||||
case 8: k1 ^= uint64_t(tail[ 7]) << 56;
|
||||
case 7: k1 ^= uint64_t(tail[ 6]) << 48;
|
||||
case 6: k1 ^= uint64_t(tail[ 5]) << 40;
|
||||
case 5: k1 ^= uint64_t(tail[ 4]) << 32;
|
||||
case 4: k1 ^= uint64_t(tail[ 3]) << 24;
|
||||
case 3: k1 ^= uint64_t(tail[ 2]) << 16;
|
||||
case 2: k1 ^= uint64_t(tail[ 1]) << 8;
|
||||
case 1: k1 ^= uint64_t(tail[ 0]) << 0;
|
||||
k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len; h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix(h1);
|
||||
h2 = fmix(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
((uint64_t*)out)[0] = h1;
|
||||
((uint64_t*)out)[1] = h2;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
23
content/canvas/src/MurmurHash3.h
Normal file
23
content/canvas/src/MurmurHash3.h
Normal file
@ -0,0 +1,23 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
#ifndef _MURMURHASH3_H_
|
||||
#define _MURMURHASH3_H_
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Platform-specific functions and macros
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
|
||||
|
||||
void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
|
||||
|
||||
void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // _MURMURHASH3_H_
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
@ -137,9 +138,16 @@ WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location,
|
||||
if (!ValidateAttribIndex(location, "bindAttribLocation"))
|
||||
return;
|
||||
|
||||
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_")))
|
||||
return ErrorInvalidOperation("bindAttribLocation: can't set the location of a name that starts with 'gl_'");
|
||||
|
||||
NS_LossyConvertUTF16toASCII cname(name);
|
||||
nsCString mappedName;
|
||||
prog->MapIdentifier(cname, &mappedName);
|
||||
if (mShaderValidation) {
|
||||
WebGLProgram::HashMapIdentifier(cname, &mappedName);
|
||||
} else {
|
||||
mappedName.Assign(cname);
|
||||
}
|
||||
|
||||
MakeContextCurrent();
|
||||
gl->fBindAttribLocation(progname, location, mappedName.get());
|
||||
@ -2996,286 +3004,295 @@ WebGLContext::CompileShader(WebGLShader *shader)
|
||||
|
||||
shader->SetCompileStatus(false);
|
||||
|
||||
// nothing to do if the validator is disabled
|
||||
if (!mShaderValidation)
|
||||
return;
|
||||
|
||||
// nothing to do if translation was already done
|
||||
if (!shader->NeedsTranslation())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
|
||||
bool useShaderSourceTranslation = true;
|
||||
|
||||
if (shader->NeedsTranslation() && mShaderValidation) {
|
||||
ShHandle compiler = 0;
|
||||
ShBuiltInResources resources;
|
||||
memset(&resources, 0, sizeof(ShBuiltInResources));
|
||||
ShHandle compiler = 0;
|
||||
ShBuiltInResources resources;
|
||||
|
||||
resources.MaxVertexAttribs = mGLMaxVertexAttribs;
|
||||
resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
|
||||
resources.MaxVaryingVectors = mGLMaxVaryingVectors;
|
||||
resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
|
||||
resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
|
||||
resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
|
||||
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
|
||||
resources.MaxDrawBuffers = mGLMaxDrawBuffers;
|
||||
memset(&resources, 0, sizeof(ShBuiltInResources));
|
||||
|
||||
if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
|
||||
resources.EXT_frag_depth = 1;
|
||||
ShInitBuiltInResources(&resources);
|
||||
|
||||
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
|
||||
resources.OES_standard_derivatives = 1;
|
||||
resources.MaxVertexAttribs = mGLMaxVertexAttribs;
|
||||
resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
|
||||
resources.MaxVaryingVectors = mGLMaxVaryingVectors;
|
||||
resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
|
||||
resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
|
||||
resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
|
||||
resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
|
||||
resources.MaxDrawBuffers = mGLMaxDrawBuffers;
|
||||
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
|
||||
resources.EXT_draw_buffers = 1;
|
||||
if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
|
||||
resources.EXT_frag_depth = 1;
|
||||
|
||||
// Tell ANGLE to allow highp in frag shaders. (unless disabled)
|
||||
// If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
|
||||
resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
|
||||
if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
|
||||
resources.OES_standard_derivatives = 1;
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
|
||||
resources.EXT_draw_buffers = 1;
|
||||
|
||||
// Tell ANGLE to allow highp in frag shaders. (unless disabled)
|
||||
// If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
|
||||
resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
|
||||
|
||||
resources.HashFunction = WebGLProgram::IdentifierHashFunction;
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->Vendor() == gl::GLVendor::NVIDIA) {
|
||||
// Work around bug 890432
|
||||
resources.MaxExpressionComplexity = 1000;
|
||||
}
|
||||
if (gl->Vendor() == gl::GLVendor::NVIDIA) {
|
||||
// Work around bug 890432
|
||||
resources.MaxExpressionComplexity = 1000;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// We're storing an actual instance of StripComments because, if we don't, the
|
||||
// cleanSource nsAString instance will be destroyed before the reference is
|
||||
// actually used.
|
||||
StripComments stripComments(shader->Source());
|
||||
const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
|
||||
if (!ValidateGLSLString(cleanSource, "compileShader"))
|
||||
return;
|
||||
// We're storing an actual instance of StripComments because, if we don't, the
|
||||
// cleanSource nsAString instance will be destroyed before the reference is
|
||||
// actually used.
|
||||
StripComments stripComments(shader->Source());
|
||||
const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
|
||||
if (!ValidateGLSLString(cleanSource, "compileShader"))
|
||||
return;
|
||||
|
||||
// shaderSource() already checks that the source stripped of comments is in the
|
||||
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
|
||||
NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
|
||||
// shaderSource() already checks that the source stripped of comments is in the
|
||||
// 7-bit ASCII range, so we can skip the NS_IsAscii() check.
|
||||
NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
|
||||
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
const uint32_t maxSourceLength = 0x3ffff;
|
||||
if (sourceCString.Length() > maxSourceLength)
|
||||
return ErrorInvalidValue("compileShader: source has more than %d characters",
|
||||
maxSourceLength);
|
||||
}
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
const uint32_t maxSourceLength = 0x3ffff;
|
||||
if (sourceCString.Length() > maxSourceLength)
|
||||
return ErrorInvalidValue("compileShader: source has more than %d characters",
|
||||
maxSourceLength);
|
||||
}
|
||||
|
||||
const char *s = sourceCString.get();
|
||||
const char *s = sourceCString.get();
|
||||
|
||||
#define WEBGL2_BYPASS_ANGLE
|
||||
#ifdef WEBGL2_BYPASS_ANGLE
|
||||
/*
|
||||
* The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
|
||||
* is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
|
||||
*
|
||||
* To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
|
||||
*
|
||||
* To bypass angle, the context must be a WebGL 2 and the shader must have the
|
||||
* following line at the very top :
|
||||
* #version proto-200
|
||||
*
|
||||
* In this case, byPassANGLE == true and here is what we do :
|
||||
* We create two shader source code:
|
||||
* - one for the driver, that enable GL_EXT_gpu_shader4
|
||||
* - one for the angle compilor, to get informations about vertex attributes
|
||||
* and uniforms
|
||||
*/
|
||||
static const char *bypassPrefixSearch = "#version proto-200";
|
||||
static const char *bypassANGLEPrefix[2] = {"precision mediump float;\n"
|
||||
"#define gl_VertexID 0\n"
|
||||
"#define gl_InstanceID 0\n",
|
||||
/*
|
||||
* The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
|
||||
* is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
|
||||
*
|
||||
* To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
|
||||
*
|
||||
* To bypass angle, the context must be a WebGL 2 and the shader must have the
|
||||
* following line at the very top :
|
||||
* #version proto-200
|
||||
*
|
||||
* In this case, byPassANGLE == true and here is what we do :
|
||||
* We create two shader source code:
|
||||
* - one for the driver, that enable GL_EXT_gpu_shader4
|
||||
* - one for the angle compilor, to get informations about vertex attributes
|
||||
* and uniforms
|
||||
*/
|
||||
static const char *bypassPrefixSearch = "#version proto-200";
|
||||
static const char *bypassANGLEPrefix[2] = {"precision mediump float;\n"
|
||||
"#define gl_VertexID 0\n"
|
||||
"#define gl_InstanceID 0\n",
|
||||
|
||||
"precision mediump float;\n"
|
||||
"#extension GL_EXT_draw_buffers : enable\n"
|
||||
"#define gl_PrimitiveID 0\n"};
|
||||
"precision mediump float;\n"
|
||||
"#extension GL_EXT_draw_buffers : enable\n"
|
||||
"#define gl_PrimitiveID 0\n"};
|
||||
|
||||
const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0);
|
||||
const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0);
|
||||
|
||||
const char *angleShaderCode = s;
|
||||
nsTArray<char> bypassANGLEShaderCode;
|
||||
nsTArray<char> bypassDriverShaderCode;
|
||||
const char *angleShaderCode = s;
|
||||
nsTArray<char> bypassANGLEShaderCode;
|
||||
nsTArray<char> bypassDriverShaderCode;
|
||||
|
||||
if (bypassANGLE) {
|
||||
const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0;
|
||||
const char *originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch);
|
||||
int originalShaderSize = strlen(s) - (originalShader - s);
|
||||
int bypassShaderCodeSize = originalShaderSize + 4096 + 1;
|
||||
if (bypassANGLE) {
|
||||
const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0;
|
||||
const char *originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch);
|
||||
int originalShaderSize = strlen(s) - (originalShader - s);
|
||||
int bypassShaderCodeSize = originalShaderSize + 4096 + 1;
|
||||
|
||||
bypassANGLEShaderCode.SetLength(bypassShaderCodeSize);
|
||||
strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]);
|
||||
strcat(bypassANGLEShaderCode.Elements(), originalShader);
|
||||
bypassANGLEShaderCode.SetLength(bypassShaderCodeSize);
|
||||
strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]);
|
||||
strcat(bypassANGLEShaderCode.Elements(), originalShader);
|
||||
|
||||
bypassDriverShaderCode.SetLength(bypassShaderCodeSize);
|
||||
strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
|
||||
strcat(bypassDriverShaderCode.Elements(), originalShader);
|
||||
bypassDriverShaderCode.SetLength(bypassShaderCodeSize);
|
||||
strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
|
||||
strcat(bypassDriverShaderCode.Elements(), originalShader);
|
||||
|
||||
angleShaderCode = bypassANGLEShaderCode.Elements();
|
||||
}
|
||||
angleShaderCode = bypassANGLEShaderCode.Elements();
|
||||
}
|
||||
#endif
|
||||
|
||||
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
|
||||
SH_WEBGL_SPEC,
|
||||
targetShaderSourceLanguage,
|
||||
&resources);
|
||||
compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
|
||||
SH_WEBGL_SPEC,
|
||||
targetShaderSourceLanguage,
|
||||
&resources);
|
||||
|
||||
int compileOptions = SH_ATTRIBUTES_UNIFORMS |
|
||||
SH_ENFORCE_PACKING_RESTRICTIONS;
|
||||
int compileOptions = SH_VARIABLES |
|
||||
SH_ENFORCE_PACKING_RESTRICTIONS |
|
||||
SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
|
||||
SH_OBJECT_CODE;
|
||||
|
||||
if (resources.MaxExpressionComplexity > 0) {
|
||||
compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
|
||||
}
|
||||
if (resources.MaxExpressionComplexity > 0) {
|
||||
compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
|
||||
}
|
||||
|
||||
// We want to do this everywhere, but:
|
||||
#ifndef XP_MACOSX // To do this on Mac, we need to do it only on Mac OSX > 10.6 as this
|
||||
// causes the shader compiler in 10.6 to crash
|
||||
compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
|
||||
#ifndef XP_MACOSX
|
||||
// We want to do this everywhere, but to do this on Mac, we need
|
||||
// to do it only on Mac OSX > 10.6 as this causes the shader
|
||||
// compiler in 10.6 to crash
|
||||
compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
|
||||
#endif
|
||||
|
||||
if (useShaderSourceTranslation) {
|
||||
compileOptions |= SH_OBJECT_CODE
|
||||
| SH_MAP_LONG_VARIABLE_NAMES;
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
// Work around bug 665578 and bug 769810
|
||||
if (gl->Vendor() == gl::GLVendor::ATI) {
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
}
|
||||
|
||||
// Work around bug 735560
|
||||
if (gl->Vendor() == gl::GLVendor::Intel) {
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (gl->WorkAroundDriverBugs()) {
|
||||
// Work around bug 665578 and bug 769810
|
||||
if (gl->Vendor() == gl::GLVendor::ATI) {
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
}
|
||||
|
||||
// Work around bug 735560
|
||||
if (gl->Vendor() == gl::GLVendor::Intel) {
|
||||
compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
|
||||
}
|
||||
|
||||
// Work around bug 636926
|
||||
if (gl->Vendor() == gl::GLVendor::NVIDIA) {
|
||||
compileOptions |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
|
||||
}
|
||||
|
||||
// Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
|
||||
// https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
|
||||
compileOptions |= SH_UNFOLD_SHORT_CIRCUIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WEBGL2_BYPASS_ANGLE
|
||||
if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
|
||||
if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
|
||||
#else
|
||||
if (!ShCompile(compiler, &s, 1, compileOptions)) {
|
||||
if (!ShCompile(compiler, &s, 1, compileOptions)) {
|
||||
#endif
|
||||
size_t lenWithNull = 0;
|
||||
ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
|
||||
size_t lenWithNull = 0;
|
||||
ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
|
||||
|
||||
if (!lenWithNull) {
|
||||
// Error in ShGetInfo.
|
||||
shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
|
||||
} else {
|
||||
size_t len = lenWithNull - 1;
|
||||
|
||||
nsAutoCString info;
|
||||
info.SetLength(len); // Allocates len+1, for the null-term.
|
||||
ShGetInfoLog(compiler, info.BeginWriting());
|
||||
|
||||
shader->SetTranslationFailure(info);
|
||||
}
|
||||
ShDestruct(compiler);
|
||||
shader->SetCompileStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t num_attributes = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
|
||||
size_t num_uniforms = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
|
||||
size_t attrib_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
|
||||
size_t uniform_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
|
||||
size_t mapped_max_length = 0;
|
||||
ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
|
||||
|
||||
shader->mAttribMaxNameLength = attrib_max_length;
|
||||
|
||||
shader->mAttributes.Clear();
|
||||
shader->mUniforms.Clear();
|
||||
shader->mUniformInfos.Clear();
|
||||
|
||||
nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
|
||||
nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
|
||||
nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
|
||||
|
||||
for (size_t i = 0; i < num_uniforms; i++) {
|
||||
size_t length;
|
||||
int size;
|
||||
ShDataType type;
|
||||
ShGetActiveUniform(compiler, (int)i,
|
||||
&length, &size, &type,
|
||||
uniform_name,
|
||||
mapped_name);
|
||||
if (useShaderSourceTranslation) {
|
||||
shader->mUniforms.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(uniform_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
}
|
||||
|
||||
// we always query uniform info, regardless of useShaderSourceTranslation,
|
||||
// as we need it to validate uniform setter calls, and it doesn't rely on
|
||||
// shader translation.
|
||||
char mappedNameLength = strlen(mapped_name);
|
||||
char mappedNameLastChar = mappedNameLength > 1
|
||||
? mapped_name[mappedNameLength - 1]
|
||||
: 0;
|
||||
shader->mUniformInfos.AppendElement(WebGLUniformInfo(
|
||||
size,
|
||||
mappedNameLastChar == ']',
|
||||
type));
|
||||
}
|
||||
|
||||
if (useShaderSourceTranslation) {
|
||||
|
||||
for (size_t i = 0; i < num_attributes; i++) {
|
||||
size_t length;
|
||||
int size;
|
||||
ShDataType type;
|
||||
ShGetActiveAttrib(compiler, (int)i,
|
||||
&length, &size, &type,
|
||||
attribute_name,
|
||||
mapped_name);
|
||||
shader->mAttributes.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(attribute_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
}
|
||||
|
||||
size_t lenWithNull = 0;
|
||||
ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
|
||||
MOZ_ASSERT(lenWithNull >= 1);
|
||||
if (!lenWithNull) {
|
||||
// Error in ShGetInfo.
|
||||
shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
|
||||
} else {
|
||||
size_t len = lenWithNull - 1;
|
||||
|
||||
nsAutoCString translatedSrc;
|
||||
translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
|
||||
ShGetObjectCode(compiler, translatedSrc.BeginWriting());
|
||||
nsAutoCString info;
|
||||
info.SetLength(len); // Allocates len+1, for the null-term.
|
||||
ShGetInfoLog(compiler, info.BeginWriting());
|
||||
|
||||
CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
|
||||
shader->SetTranslationFailure(info);
|
||||
}
|
||||
ShDestruct(compiler);
|
||||
shader->SetCompileStatus(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const char *ts = translatedSrc.get();
|
||||
size_t num_attributes = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
|
||||
size_t num_uniforms = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
|
||||
size_t attrib_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
|
||||
size_t uniform_max_length = 0;
|
||||
ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
|
||||
size_t mapped_max_length = 0;
|
||||
ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
|
||||
|
||||
shader->mAttribMaxNameLength = attrib_max_length;
|
||||
|
||||
shader->mAttributes.Clear();
|
||||
shader->mUniforms.Clear();
|
||||
shader->mUniformInfos.Clear();
|
||||
|
||||
nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
|
||||
nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
|
||||
nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
|
||||
|
||||
for (size_t i = 0; i < num_uniforms; i++) {
|
||||
size_t length;
|
||||
int size;
|
||||
ShDataType type;
|
||||
ShPrecisionType precision;
|
||||
int staticUse;
|
||||
ShGetVariableInfo(compiler, SH_ACTIVE_UNIFORMS, (int)i,
|
||||
&length, &size, &type,
|
||||
&precision, &staticUse,
|
||||
uniform_name,
|
||||
mapped_name);
|
||||
|
||||
shader->mUniforms.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(uniform_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
|
||||
// we need uniform info to validate uniform setter calls
|
||||
char mappedNameLength = strlen(mapped_name);
|
||||
char mappedNameLastChar = mappedNameLength > 1
|
||||
? mapped_name[mappedNameLength - 1]
|
||||
: 0;
|
||||
shader->mUniformInfos.AppendElement(WebGLUniformInfo(
|
||||
size,
|
||||
mappedNameLastChar == ']',
|
||||
type));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_attributes; i++) {
|
||||
size_t length;
|
||||
int size;
|
||||
ShDataType type;
|
||||
ShPrecisionType precision;
|
||||
int staticUse;
|
||||
ShGetVariableInfo(compiler, SH_ACTIVE_ATTRIBUTES, (int)i,
|
||||
&length, &size, &type,
|
||||
&precision, &staticUse,
|
||||
attribute_name,
|
||||
mapped_name);
|
||||
shader->mAttributes.AppendElement(WebGLMappedIdentifier(
|
||||
nsDependentCString(attribute_name),
|
||||
nsDependentCString(mapped_name)));
|
||||
}
|
||||
|
||||
size_t lenWithNull = 0;
|
||||
ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
|
||||
MOZ_ASSERT(lenWithNull >= 1);
|
||||
size_t len = lenWithNull - 1;
|
||||
|
||||
nsAutoCString translatedSrc;
|
||||
translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
|
||||
ShGetObjectCode(compiler, translatedSrc.BeginWriting());
|
||||
|
||||
CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
|
||||
|
||||
const char *ts = translatedSrc.get();
|
||||
|
||||
#ifdef WEBGL2_BYPASS_ANGLE
|
||||
if (bypassANGLE) {
|
||||
const char* driverShaderCode = bypassDriverShaderCode.Elements();
|
||||
gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr);
|
||||
}
|
||||
else {
|
||||
gl->fShaderSource(shadername, 1, &ts, nullptr);
|
||||
}
|
||||
#else
|
||||
gl->fShaderSource(shadername, 1, &ts, nullptr);
|
||||
#endif
|
||||
} else { // not useShaderSourceTranslation
|
||||
// we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
|
||||
// that's really bad, as that means we can't be 100% conformant. We should work towards always
|
||||
// using ANGLE identifier mapping.
|
||||
gl->fShaderSource(shadername, 1, &s, nullptr);
|
||||
|
||||
CopyASCIItoUTF16(s, shader->mTranslatedSource);
|
||||
}
|
||||
|
||||
shader->SetTranslationSuccess();
|
||||
|
||||
ShDestruct(compiler);
|
||||
|
||||
gl->fCompileShader(shadername);
|
||||
GLint ok;
|
||||
gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
|
||||
shader->SetCompileStatus(ok);
|
||||
if (bypassANGLE) {
|
||||
const char* driverShaderCode = bypassDriverShaderCode.Elements();
|
||||
gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr);
|
||||
} else {
|
||||
gl->fShaderSource(shadername, 1, &ts, nullptr);
|
||||
}
|
||||
#else
|
||||
gl->fShaderSource(shadername, 1, &ts, nullptr);
|
||||
#endif
|
||||
|
||||
shader->SetTranslationSuccess();
|
||||
|
||||
ShDestruct(compiler);
|
||||
|
||||
gl->fCompileShader(shadername);
|
||||
GLint ok;
|
||||
gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
|
||||
shader->SetCompileStatus(ok);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "GLContext.h"
|
||||
|
||||
#include "MurmurHash3.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]" in bracketPart
|
||||
@ -237,6 +239,25 @@ WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) {
|
||||
return info;
|
||||
}
|
||||
|
||||
/* static */ uint64_t
|
||||
WebGLProgram::IdentifierHashFunction(const char *ident, size_t size)
|
||||
{
|
||||
uint64_t outhash[2];
|
||||
// NB: we use the x86 function everywhere, even though it's suboptimal perf
|
||||
// on x64. They return different results; not sure if that's a requirement.
|
||||
MurmurHash3_x86_128(ident, size, 0, &outhash[0]);
|
||||
return outhash[0];
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
WebGLProgram::HashMapIdentifier(const nsACString& name, nsCString *hashedName)
|
||||
{
|
||||
uint64_t hash = IdentifierHashFunction(name.BeginReading(), name.Length());
|
||||
hashedName->Truncate();
|
||||
// This MUST MATCH angle/src/compiler/translator/HashNames.h HASHED_NAME_PREFIX
|
||||
hashedName->AppendPrintf("webgl_%llx", hash);
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
|
||||
|
@ -110,6 +110,9 @@ public:
|
||||
// public post-link data
|
||||
std::map<GLint, nsCString> mActiveAttribMap;
|
||||
|
||||
static uint64_t IdentifierHashFunction(const char *ident, size_t size);
|
||||
static void HashMapIdentifier(const nsACString& name, nsCString *hashedName);
|
||||
|
||||
protected:
|
||||
~WebGLProgram() {
|
||||
DeleteOnce();
|
||||
|
@ -25,6 +25,7 @@ UNIFIED_SOURCES += [
|
||||
|
||||
if CONFIG['MOZ_WEBGL']:
|
||||
UNIFIED_SOURCES += [
|
||||
'MurmurHash3.cpp',
|
||||
'WebGL1Context.cpp',
|
||||
'WebGL2Context.cpp',
|
||||
'WebGLActiveInfo.cpp',
|
||||
|
@ -178,16 +178,6 @@ opus_encoder_ctl
|
||||
opus_encode
|
||||
opus_encode_float
|
||||
#endif
|
||||
ShInitialize
|
||||
ShFinalize
|
||||
ShGetObjectCode
|
||||
ShDestruct
|
||||
ShGetInfoLog
|
||||
ShCompile
|
||||
ShGetInfo
|
||||
ShConstructCompiler
|
||||
ShGetActiveAttrib
|
||||
ShGetActiveUniform
|
||||
#ifndef MOZ_NATIVE_PNG
|
||||
MOZ_APNG_get_first_frame_is_hidden
|
||||
MOZ_APNG_get_next_frame_blend_op
|
||||
|
Loading…
Reference in New Issue
Block a user