Bug 1048745 - [WebGL2] Integer vertex attributes. r=jgilbert

--HG--
extra : rebase_source : 590eaef6f7582701607e48f7e67bbe7100ff7199
This commit is contained in:
Dan Glastonbury 2014-06-24 10:56:21 +10:00
parent 1f58996302
commit d8e705ef5e
12 changed files with 325 additions and 98 deletions

View File

@ -28,6 +28,9 @@ public:
// nsWrapperCache
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla

View File

@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGL1Context.h"
using namespace mozilla;
bool
WebGL1Context::ValidateAttribPointerType(bool /*integerMode*/, GLenum type, GLsizei* out_alignment, const char* info)
{
MOZ_ASSERT(out_alignment);
if (!out_alignment)
return false;
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
*out_alignment = 1;
return true;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
*out_alignment = 2;
return true;
// XXX case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
*out_alignment = 4;
return true;
}
ErrorInvalidEnumInfo(info, type);
return false;
}

View File

@ -35,7 +35,6 @@ public:
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
// -------------------------------------------------------------------------
// Buffer objects - WebGL2ContextBuffers.cpp
@ -126,6 +125,12 @@ public:
void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value);
void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
private:
void VertexAttribI4iv(GLuint index, size_t length, const GLint* v);
void VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v);
public:
// GL 3.0 & ES 3.0
void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
void VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v);
void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
@ -250,11 +255,14 @@ public:
private:
WebGL2Context();
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla

View File

@ -5,17 +5,103 @@
#include "WebGL2Context.h"
#include "GLContext.h"
#include "WebGLVertexArray.h"
#include "WebGLVertexAttribData.h"
using namespace mozilla;
using namespace mozilla::dom;
typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
static inline
GLfloat PuntToFloat(GLint i)
{
fi_t tmp;
tmp.i = i;
return tmp.f;
}
static inline
GLfloat PuntToFloat(GLuint u)
{
fi_t tmp;
tmp.u = u;
return tmp.f;
}
bool
WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info)
{
MOZ_ASSERT(alignment);
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
*alignment = 1;
return true;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
*alignment = 2;
return true;
case LOCAL_GL_INT:
case LOCAL_GL_UNSIGNED_INT:
*alignment = 4;
return true;
}
if (!integerMode) {
switch (type) {
case LOCAL_GL_HALF_FLOAT:
*alignment = 2;
return true;
case LOCAL_GL_FLOAT:
case LOCAL_GL_FIXED:
case LOCAL_GL_INT_2_10_10_10_REV:
case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
*alignment = 4;
return true;
}
}
ErrorInvalidEnum("%s: invalid enum value 0x%x", info, type);
return false;
}
// -------------------------------------------------------------------------
// Uniforms and attributes
void
WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (!ValidateAttribIndex(index, "vertexAttribIPointer"))
return;
if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer"))
return;
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->EnsureAttrib(index);
InvalidateBufferFetching();
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
vd.buf = mBoundArrayBuffer;
vd.stride = stride;
vd.size = size;
vd.byteOffset = offset;
vd.type = type;
vd.normalized = false;
vd.integer = true;
MakeContextCurrent();
gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
}
void
@ -141,25 +227,81 @@ WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose
void
WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4i(index, x, y, z, w);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(x);
mVertexAttrib0Vector[1] = PuntToFloat(y);
mVertexAttrib0Vector[2] = PuntToFloat(z);
mVertexAttrib0Vector[3] = PuntToFloat(w);
}
}
void
WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
{
if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4iv(index, v);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
}
}
void
WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
{
MOZ_CRASH("Not Implemented.");
VertexAttribI4iv(index, v.Length(), v.Elements());
}
void
WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
{
MOZ_CRASH("Not Implemented.");
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4ui(index, x, y, z, w);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(x);
mVertexAttrib0Vector[1] = PuntToFloat(y);
mVertexAttrib0Vector[2] = PuntToFloat(z);
mVertexAttrib0Vector[3] = PuntToFloat(w);
}
}
void
WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
{
if (IsContextLost())
return;
if (index || gl->IsGLES()) {
MakeContextCurrent();
gl->fVertexAttribI4uiv(index, v);
} else {
mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
}
}
void
WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
{
MOZ_CRASH("Not Implemented.");
VertexAttribI4uiv(index, v.Length(), v.Elements());
}
// -------------------------------------------------------------------------

View File

@ -52,7 +52,7 @@ class nsIDocShell;
*
* Exceptions: some of the following values are set to higher values than in the spec because
* the values in the spec are ridiculously low. They are explicitly marked below
*/
*/
#define MINVALUE_GL_MAX_TEXTURE_SIZE 1024 // Different from the spec, which sets it to 64 on page 162
#define MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE 512 // Different from the spec, which sets it to 16 on page 162
#define MINVALUE_GL_MAX_VERTEX_ATTRIBS 8 // Page 164
@ -134,11 +134,13 @@ TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
class WebGLIntOrFloat {
enum {
Int,
Float
Float,
Uint
} mType;
union {
GLint i;
GLfloat f;
GLuint u;
} mValue;
public:
@ -158,6 +160,7 @@ class WebGLContext
, public nsWrapperCache
, public SupportsWeakPtr<WebGLContext>
{
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureATC;
friend class WebGLExtensionCompressedTextureETC1;
@ -1006,6 +1009,7 @@ private:
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
protected:
inline void InvalidateBufferFetching() {
mBufferFetchingIsVerified = false;
mBufferFetchingHasPerVertex = false;
@ -1192,6 +1196,10 @@ protected:
bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
WebGLTexImageFunc func, WebGLTexDimensions dims);
bool ValidateDrawModeEnum(GLenum mode, const char* info);
bool ValidateAttribIndex(GLuint index, const char* info);
bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
WebGLboolean normalized, GLsizei stride,
WebGLintptr byteOffset, const char* info);
bool ValidateStencilParamsForDrawCall();
bool ValidateGLSLVariableName(const nsAString& name, const char* info);
@ -1329,6 +1337,11 @@ private:
template<class ObjectType>
bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
private:
// -------------------------------------------------------------------------
// Context customization points
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
protected:
int32_t MaxTextureSizeForTarget(TexTarget target) const {
return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize

View File

@ -621,12 +621,20 @@ WebGLContext::UndoFakeVertexAttrib0()
if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
if (attrib0.integer) {
gl->fVertexAttribIPointer(0,
attrib0.size,
attrib0.type,
attrib0.stride,
reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
} else {
gl->fVertexAttribPointer(0,
attrib0.size,
attrib0.type,
attrib0.normalized,
attrib0.stride,
reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
}
} else {
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}

View File

@ -1718,6 +1718,78 @@ WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
return true;
}
bool
WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
{
bool valid = (index < MaxVertexAttribs());
if (!valid) {
if (index == GLuint(-1)) {
ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
" probably comes from a getAttribLocation()"
" call, where this return value -1 means"
" that the passed name didn't correspond to"
" an active attribute in the specified"
" program.", info);
} else {
ErrorInvalidValue("%s: `index` must be less than"
" MAX_VERTEX_ATTRIBS.", info);
}
}
return valid;
}
bool
WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
WebGLboolean normalized, GLsizei stride,
WebGLintptr byteOffset, const char* info)
{
WebGLBuffer* buffer = mBoundArrayBuffer;
if (!buffer) {
ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info);
return false;
}
GLsizei requiredAlignment = 0;
if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info))
return false;
// requiredAlignment should always be a power of two
MOZ_ASSERT(IsPOTAssumingNonnegative(requiredAlignment));
GLsizei requiredAlignmentMask = requiredAlignment - 1;
if (size < 1 || size > 4) {
ErrorInvalidValue("%s: invalid element size", info);
return false;
}
// see WebGL spec section 6.6 "Vertex Attribute Data Stride"
if (stride < 0 || stride > 255) {
ErrorInvalidValue("%s: negative or too large stride", info);
return false;
}
if (byteOffset < 0) {
ErrorInvalidValue("%s: negative offset", info);
return false;
}
if (stride & requiredAlignmentMask) {
ErrorInvalidOperation("%s: stride doesn't satisfy the alignment "
"requirement of given type", info);
return false;
}
if (byteOffset & requiredAlignmentMask) {
ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment "
"requirement of given type", info);
return false;
}
return true;
}
bool
WebGLContext::ValidateStencilParamsForDrawCall()
{

View File

@ -20,34 +20,13 @@
using namespace mozilla;
using namespace dom;
static bool
CheckAttribIndex(WebGLContext& webgl, GLuint index, const char* info)
{
if (index >= webgl.MaxVertexAttribs()) {
if (index == GLuint(-1)) {
webgl.ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
" probably comes from a getAttribLocation()"
" call, where this return value -1 means"
" that the passed name didn't correspond to"
" an active attribute in the specified"
" program.", info);
} else {
webgl.ErrorInvalidValue("%s: `index` must be less than"
" MAX_VERTEX_ATTRIBS.", info);
}
return false;
}
return true;
}
void
WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
{
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib1f"))
if (!ValidateAttribIndex(index, "vertexAttrib1f"))
return;
MakeContextCurrent();
@ -70,7 +49,7 @@ WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib2f"))
if (!ValidateAttribIndex(index, "vertexAttrib2f"))
return;
MakeContextCurrent();
@ -93,7 +72,7 @@ WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib3f"))
if (!ValidateAttribIndex(index, "vertexAttrib3f"))
return;
MakeContextCurrent();
@ -117,7 +96,7 @@ WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib4f"))
if (!ValidateAttribIndex(index, "vertexAttrib4f"))
return;
MakeContextCurrent();
@ -142,7 +121,7 @@ WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib1fv"))
if (!ValidateAttribIndex(index, "vertexAttrib1fv"))
return;
MakeContextCurrent();
@ -165,7 +144,7 @@ WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib2fv"))
if (!ValidateAttribIndex(index, "vertexAttrib2fv"))
return;
MakeContextCurrent();
@ -188,7 +167,7 @@ WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib3fv"))
if (!ValidateAttribIndex(index, "vertexAttrib3fv"))
return;
MakeContextCurrent();
@ -211,7 +190,7 @@ WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
return;
if (!CheckAttribIndex(*this, index, "vertexAttrib4fv"))
if (!ValidateAttribIndex(index, "vertexAttrib4fv"))
return;
MakeContextCurrent();
@ -233,7 +212,7 @@ WebGLContext::EnableVertexAttribArray(GLuint index)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "enableVertexAttribArray"))
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
return;
MakeContextCurrent();
@ -252,7 +231,7 @@ WebGLContext::DisableVertexAttribArray(GLuint index)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "disableVertexAttribArray"))
if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
return;
MakeContextCurrent();
@ -273,7 +252,7 @@ WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
if (IsContextLost())
return JS::NullValue();
if (!CheckAttribIndex(*this, index, "getVertexAttrib"))
if (!ValidateAttribIndex(index, "getVertexAttrib"))
return JS::NullValue();
MOZ_ASSERT(mBoundVertexArray);
@ -359,7 +338,7 @@ WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
if (IsContextLost())
return 0;
if (!CheckAttribIndex(*this, index, "getVertexAttribOffset"))
if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
return 0;
if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
@ -380,56 +359,15 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttribPointer"))
if (!ValidateAttribIndex(index, "vertexAttribPointer"))
return;
if (mBoundArrayBuffer == nullptr)
return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
GLsizei requiredAlignment = 1;
switch (type) {
case LOCAL_GL_BYTE:
case LOCAL_GL_UNSIGNED_BYTE:
requiredAlignment = 1;
break;
case LOCAL_GL_SHORT:
case LOCAL_GL_UNSIGNED_SHORT:
requiredAlignment = 2;
break;
// XXX case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
requiredAlignment = 4;
break;
default:
return ErrorInvalidEnumInfo("vertexAttribPointer: type", type);
}
// requiredAlignment should always be a power of two.
GLsizei requiredAlignmentMask = requiredAlignment - 1;
if (!ValidateAttribPointer(false, index, size, type, normalized, stride, byteOffset, "vertexAttribPointer"))
return;
MOZ_ASSERT(mBoundVertexArray);
mBoundVertexArray->EnsureAttrib(index);
if (size < 1 || size > 4)
return ErrorInvalidValue("vertexAttribPointer: invalid element size");
if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
return ErrorInvalidValue("vertexAttribPointer: negative or too large stride");
if (byteOffset < 0)
return ErrorInvalidValue("vertexAttribPointer: negative offset");
if (stride & requiredAlignmentMask) {
return ErrorInvalidOperation("vertexAttribPointer: stride doesn't satisfy the alignment "
"requirement of given type");
}
if (byteOffset & requiredAlignmentMask) {
return ErrorInvalidOperation("vertexAttribPointer: byteOffset doesn't satisfy the alignment "
"requirement of given type");
}
InvalidateBufferFetching();
/* XXX make work with bufferSubData & heterogeneous types
@ -445,11 +383,10 @@ WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
vd.byteOffset = byteOffset;
vd.type = type;
vd.normalized = normalized;
vd.integer = false;
MakeContextCurrent();
gl->fVertexAttribPointer(index, size, type, normalized,
stride,
gl->fVertexAttribPointer(index, size, type, normalized, stride,
reinterpret_cast<void*>(byteOffset));
}
@ -459,7 +396,7 @@ WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
if (IsContextLost())
return;
if (!CheckAttribIndex(*this, index, "vertexAttribDivisor"))
if (!ValidateAttribIndex(index, "vertexAttribDivisor"))
return;
MOZ_ASSERT(mBoundVertexArray);

View File

@ -74,6 +74,7 @@ protected:
friend class WebGLContext;
friend class WebGLVertexArrayFake;
friend class WebGL2Context;
};
} // namespace mozilla

View File

@ -29,8 +29,13 @@ WebGLVertexArrayFake::BindVertexArrayImpl()
mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, vd.buf);
gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
reinterpret_cast<void*>(vd.byteOffset));
if (vd.integer) {
gl->fVertexAttribIPointer(i, vd.size, vd.type, vd.stride,
reinterpret_cast<const GLvoid*>(vd.byteOffset));
} else {
gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
reinterpret_cast<const GLvoid*>(vd.byteOffset));
}
if (vd.enabled)
gl->fEnableVertexAttribArray(i);

View File

@ -25,6 +25,7 @@ struct WebGLVertexAttribData
, type(LOCAL_GL_FLOAT)
, enabled(false)
, normalized(false)
, integer(false)
{}
WebGLRefPtr<WebGLBuffer> buf;
@ -35,6 +36,7 @@ struct WebGLVertexAttribData
GLenum type;
bool enabled;
bool normalized;
bool integer;
GLuint componentSize() const {
switch(type) {

View File

@ -42,6 +42,7 @@ UNIFIED_SOURCES += [
UNIFIED_SOURCES += [
'MurmurHash3.cpp',
'WebGL1Context.cpp',
'WebGL1ContextUniforms.cpp',
'WebGL2Context.cpp',
'WebGL2ContextBuffers.cpp',
'WebGL2ContextDraw.cpp',