bug 893180 - [WebGL 2.0] gl.vertexAttribDivisor (GL_ARB_instanced_array) - r=jgilbert

This commit is contained in:
Guillaume Abadie 2013-08-06 20:05:51 -04:00
parent be64ead4c1
commit e4fe59d4e4
14 changed files with 690 additions and 538 deletions

View File

@ -197,8 +197,9 @@ WebGLContext::WebGLContext()
mLastUseIndex = 0;
mMinInUseAttribArrayLengthCached = false;
mMinInUseAttribArrayLength = 0;
mBufferFetchingIsVerified = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
mIsScreenCleared = false;

View File

@ -390,10 +390,8 @@ public:
void DepthRange(WebGLclampf zNear, WebGLclampf zFar);
void DetachShader(WebGLProgram *program, WebGLShader *shader);
void Disable(WebGLenum cap);
void DisableVertexAttribArray(WebGLuint index);
void DrawBuffers(const dom::Sequence<GLenum>& buffers);
void Enable(WebGLenum cap);
void EnableVertexAttribArray(WebGLuint index);
void Flush() {
if (!IsContextStable())
return;
@ -463,9 +461,6 @@ public:
WebGLUniformLocation *location, ErrorResult& rv);
already_AddRefed<WebGLUniformLocation>
GetUniformLocation(WebGLProgram *prog, const nsAString& name);
JS::Value GetVertexAttrib(JSContext* cx, WebGLuint index, WebGLenum pname,
ErrorResult& rv);
WebGLsizeiptr GetVertexAttribOffset(WebGLuint index, WebGLenum pname);
void Hint(WebGLenum target, WebGLenum mode);
bool IsBuffer(WebGLBuffer *buffer);
bool IsEnabled(WebGLenum cap);
@ -746,52 +741,6 @@ public:
WebGLUniformLocation *location,
WebGLint value);
void VertexAttrib1f(WebGLuint index, WebGLfloat x0);
void VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1);
void VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2);
void VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2, WebGLfloat x3);
void VertexAttrib1fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib1fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib1fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib1fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr);
void VertexAttrib2fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib2fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib2fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib2fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr);
void VertexAttrib3fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib3fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib3fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib3fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr);
void VertexAttrib4fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib4fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib4fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib4fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr);
void VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
WebGLboolean normalized, WebGLsizei stride,
WebGLintptr byteOffset);
void Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height);
// -----------------------------------------------------------------------------
@ -818,12 +767,66 @@ public:
void DrawElementsInstanced(WebGLenum mode, WebGLsizei count, WebGLenum type,
WebGLintptr byteOffset, WebGLsizei primcount);
void EnableVertexAttribArray(WebGLuint index);
void DisableVertexAttribArray(WebGLuint index);
JS::Value GetVertexAttrib(JSContext* cx, WebGLuint index, WebGLenum pname,
ErrorResult& rv);
WebGLsizeiptr GetVertexAttribOffset(WebGLuint index, WebGLenum pname);
void VertexAttrib1f(WebGLuint index, WebGLfloat x0);
void VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1);
void VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2);
void VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2, WebGLfloat x3);
void VertexAttrib1fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib1fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib1fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib1fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib2fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib2fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib2fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib2fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib3fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib3fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib3fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib3fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttrib4fv(WebGLuint idx, const dom::Float32Array &arr) {
VertexAttrib4fv_base(idx, arr.Length(), arr.Data());
}
void VertexAttrib4fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
VertexAttrib4fv_base(idx, arr.Length(), arr.Elements());
}
void VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
WebGLboolean normalized, WebGLsizei stride,
WebGLintptr byteOffset);
void VertexAttribDivisor(WebGLuint index, WebGLuint divisor);
private:
bool DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei primcount, const char* info);
bool DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr byteOffset,
WebGLsizei primcount, const char* info);
void Draw_cleanup();
void VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength, const WebGLfloat* ptr);
void VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength, const WebGLfloat* ptr);
void VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength, const WebGLfloat* ptr);
void VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength, const WebGLfloat* ptr);
bool ValidateBufferFetching(const char *info);
// -----------------------------------------------------------------------------
// PROTECTED
protected:
@ -892,15 +895,17 @@ protected:
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
// Cache the max number of elements that can be read from bound VBOs
// (result of ValidateBuffers).
bool mMinInUseAttribArrayLengthCached;
uint32_t mMinInUseAttribArrayLength;
// Cache the max number of vertices and isntances that can be read from
// bound VBOs (result of ValidateBuffers).
bool mBufferFetchingIsVerified;
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
inline void InvalidateCachedMinInUseAttribArrayLength()
inline void InvalidateBufferFetching()
{
mMinInUseAttribArrayLengthCached = false;
mMinInUseAttribArrayLength = 0;
mBufferFetchingIsVerified = false;
mMaxFetchedVertices = 0;
mMaxFetchedInstances = 0;
}
// Represents current status, or state, of the context. That is, is it lost
@ -953,8 +958,9 @@ protected:
nsTArray<WebGLenum> mCompressedTextureFormats;
// -------------------------------------------------------------------------
// Validation functions (implemented in WebGLContextValidate.cpp)
bool InitAndValidateGL();
bool ValidateBuffers(uint32_t *maxAllowedCount, const char *info);
bool ValidateCapabilityEnum(WebGLenum cap, const char *info);
bool ValidateBlendEquationEnum(WebGLenum cap, const char *info);
bool ValidateBlendFuncDstEnum(WebGLenum mode, const char *info);

View File

@ -383,7 +383,7 @@ WebGLContext::BufferData(WebGLenum target, WebGLsizeiptr size,
return ErrorOutOfMemory("bufferData: out of memory");
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
InvalidateBufferFetching();
GLenum error = CheckedBufferData(target, size, zeroBuffer, usage);
free(zeroBuffer);
@ -431,7 +431,7 @@ WebGLContext::BufferData(WebGLenum target,
return ErrorInvalidOperation("bufferData: no buffer bound!");
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
InvalidateBufferFetching();
GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
@ -469,7 +469,7 @@ WebGLContext::BufferData(WebGLenum target, const ArrayBufferView& data,
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
InvalidateCachedMinInUseAttribArrayLength();
InvalidateBufferFetching();
MakeContextCurrent();
GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
@ -1114,24 +1114,6 @@ WebGLContext::DepthRange(WebGLfloat zNear, WebGLfloat zFar)
gl->fDepthRange(zNear, zFar);
}
void
WebGLContext::DisableVertexAttribArray(WebGLuint index)
{
if (!IsContextStable())
return;
if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
return;
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
if (index || gl->IsGLES2())
gl->fDisableVertexAttribArray(index);
mBoundVertexArray->mAttribBuffers[index].enabled = false;
}
int
WebGLContext::WhatDoesVertexAttrib0Need()
{
@ -1394,22 +1376,6 @@ WebGLContext::Disable(WebGLenum cap)
gl->fDisable(cap);
}
void
WebGLContext::EnableVertexAttribArray(WebGLuint index)
{
if (!IsContextStable())
return;
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
return;
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
gl->fEnableVertexAttribArray(index);
mBoundVertexArray->mAttribBuffers[index].enabled = true;
}
void
WebGLContext::FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, WebGLRenderbuffer *wrb)
{
@ -2671,99 +2637,6 @@ WebGLContext::GetUniformLocation(WebGLProgram *prog, const nsAString& name)
return loc.forget();
}
JS::Value
WebGLContext::GetVertexAttrib(JSContext* cx, WebGLuint index, WebGLenum pname,
ErrorResult& rv)
{
if (!IsContextStable())
return JS::NullValue();
if (!mBoundVertexArray->EnsureAttribIndex(index, "getVertexAttrib"))
return JS::NullValue();
MakeContextCurrent();
switch (pname) {
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
{
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribBuffers[index].buf.get(), rv);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].stride);
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
{
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
return JS::NullValue();
if (!mBoundVertexArray->mAttribBuffers[index].enabled)
return JS::Int32Value(4);
// Don't break; fall through.
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
{
GLint i = 0;
gl->fGetVertexAttribiv(index, pname, &i);
if (pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE)
return JS::Int32Value(i);
MOZ_ASSERT(pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE);
return JS::NumberValue(uint32_t(i));
}
case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
{
WebGLfloat vec[4] = {0, 0, 0, 1};
if (index) {
gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]);
} else {
vec[0] = mVertexAttrib0Vector[0];
vec[1] = mVertexAttrib0Vector[1];
vec[2] = mVertexAttrib0Vector[2];
vec[3] = mVertexAttrib0Vector[3];
}
JSObject* obj = Float32Array::Create(cx, this, 4, vec);
if (!obj) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
return JS::ObjectOrNullValue(obj);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
{
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].enabled);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
{
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].normalized);
}
default:
ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
}
return JS::NullValue();
}
WebGLsizeiptr
WebGLContext::GetVertexAttribOffset(WebGLuint index, WebGLenum pname)
{
if (!IsContextStable())
return 0;
if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
return 0;
if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
ErrorInvalidEnum("getVertexAttribOffset: bad parameter");
return 0;
}
return mBoundVertexArray->mAttribBuffers[index].byteOffset;
}
void
WebGLContext::Hint(WebGLenum target, WebGLenum mode)
{
@ -2873,7 +2746,7 @@ WebGLContext::LinkProgram(WebGLProgram *program)
if (!ValidateObject("linkProgram", program))
return;
InvalidateCachedMinInUseAttribArrayLength(); // we do it early in this function
InvalidateBufferFetching(); // we do it early in this function
// as some of the validation below changes program state
GLuint progname = program->GLName();
@ -3787,168 +3660,6 @@ WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
}
void
WebGLContext::VertexAttrib1f(WebGLuint index, WebGLfloat x0)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib1f(index, x0);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = 0;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib1f(index, x0);
}
}
void
WebGLContext::VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib2f(index, x0, x1);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib2f(index, x0, x1);
}
}
void
WebGLContext::VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1, WebGLfloat x2)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib3f(index, x0, x1, x2);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib3f(index, x0, x1, x2);
}
}
void
WebGLContext::VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2, WebGLfloat x3)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = x3;
if (gl->IsGLES2())
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
}
}
void
WebGLContext::VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib1fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = WebGLfloat(0);
mVertexAttrib0Vector[2] = WebGLfloat(0);
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib1fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib2fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = WebGLfloat(0);
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib2fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib3fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib3fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib4fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = ptr[3];
if (gl->IsGLES2())
gl->fVertexAttrib4fv(idx, ptr);
}
}
void
WebGLContext::UseProgram(WebGLProgram *prog)
{
@ -3959,7 +3670,8 @@ WebGLContext::UseProgram(WebGLProgram *prog)
return;
MakeContextCurrent();
InvalidateCachedMinInUseAttribArrayLength();
InvalidateBufferFetching();
WebGLuint progname = prog ? prog->GLName() : 0;
@ -4604,85 +4316,6 @@ WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source)
shader->SetNeedsTranslation();
}
void
WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
WebGLboolean normalized, WebGLsizei stride,
WebGLintptr byteOffset)
{
if (!IsContextStable())
return;
if (mBoundArrayBuffer == nullptr)
return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
WebGLsizei 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.
WebGLsizei requiredAlignmentMask = requiredAlignment - 1;
if ( !mBoundVertexArray->EnsureAttribIndex(index, "vertexAttribPointer") ) {
return;
}
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");
}
InvalidateCachedMinInUseAttribArrayLength();
/* XXX make work with bufferSubData & heterogeneous types
if (type != mBoundArrayBuffer->GLType())
return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
*/
WebGLVertexAttribData &vd = mBoundVertexArray->mAttribBuffers[index];
vd.buf = mBoundArrayBuffer;
vd.stride = stride;
vd.size = size;
vd.byteOffset = byteOffset;
vd.type = type;
vd.normalized = normalized;
MakeContextCurrent();
gl->fVertexAttribPointer(index, size, type, normalized,
stride,
reinterpret_cast<void*>(byteOffset));
}
GLenum WebGLContext::CheckedTexImage2D(GLenum target,
GLint level,
GLenum internalFormat,

View File

@ -89,87 +89,6 @@ WebGLProgram::UpdateInfo()
return true;
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
*/
bool
WebGLContext::ValidateBuffers(uint32_t *maxAllowedCount, const char *info)
{
#ifdef DEBUG
GLint currentProgram = 0;
MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
NS_ASSERTION(GLuint(currentProgram) == mCurrentProgram->GLName(),
"WebGL: current program doesn't agree with GL state");
if (GLuint(currentProgram) != mCurrentProgram->GLName())
return false;
#endif
if (mMinInUseAttribArrayLengthCached) {
*maxAllowedCount = mMinInUseAttribArrayLength;
return true;
}
uint32_t maxAllowed = UINT32_MAX;
uint32_t attribs = mBoundVertexArray->mAttribBuffers.Length();
for (uint32_t i = 0; i < attribs; ++i) {
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribBuffers[i];
// If the attrib array isn't enabled, there's nothing to check;
// it's a static value.
if (!vd.enabled)
continue;
if (vd.buf == nullptr) {
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
return false;
}
// If the attrib is not in use, then we don't have to validate
// it, just need to make sure that the binding is non-null.
if (!mCurrentProgram->IsAttribInUse(i))
continue;
// the base offset
CheckedUint32 checked_byteLength
= CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
CheckedUint32 checked_sizeOfLastElement
= CheckedUint32(vd.componentSize()) * vd.size;
if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.isValid())
{
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
maxAllowed = 0;
break;
} else {
CheckedUint32 checked_maxAllowedCount
= ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.isValid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (maxAllowed > checked_maxAllowedCount.value())
maxAllowed = checked_maxAllowedCount.value();
}
}
*maxAllowedCount = maxAllowed;
mMinInUseAttribArrayLengthCached = true;
mMinInUseAttribArrayLength = *maxAllowedCount;
return true;
}
bool WebGLContext::ValidateCapabilityEnum(WebGLenum cap, const char *info)
{
switch (cap) {
@ -1079,6 +998,7 @@ WebGLContext::InitAndValidateGL()
!gl->IsExtensionSupported(gl::GLContext::EXT_gpu_shader4) ||
!gl->IsExtensionSupported(gl::GLContext::EXT_blend_minmax) ||
!gl->IsExtensionSupported(gl::GLContext::XXX_draw_instanced) ||
!gl->IsExtensionSupported(gl::GLContext::XXX_instanced_arrays) ||
(gl->IsGLES2() && !gl->IsExtensionSupported(gl::GLContext::EXT_occlusion_query_boolean))
))
{

View File

@ -30,7 +30,7 @@ WebGLContext::BindVertexArray(WebGLVertexArray *array)
return;
}
InvalidateCachedMinInUseAttribArrayLength();
InvalidateBufferFetching();
MakeContextCurrent();

View File

@ -10,12 +10,417 @@
#include "WebGLTexture.h"
#include "WebGLRenderbuffer.h"
#include "WebGLFramebuffer.h"
#include "WebGLUniformInfo.h"
#include "WebGLShader.h"
#include "WebGLProgram.h"
using namespace mozilla;
using namespace dom;
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
void
WebGLContext::VertexAttrib1f(WebGLuint index, WebGLfloat x0)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib1f(index, x0);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = 0;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib1f(index, x0);
}
}
void
WebGLContext::VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib2f(index, x0, x1);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib2f(index, x0, x1);
}
}
void
WebGLContext::VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1, WebGLfloat x2)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib3f(index, x0, x1, x2);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = 1;
if (gl->IsGLES2())
gl->fVertexAttrib3f(index, x0, x1, x2);
}
}
void
WebGLContext::VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
WebGLfloat x2, WebGLfloat x3)
{
if (!IsContextStable())
return;
MakeContextCurrent();
if (index) {
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
} else {
mVertexAttrib0Vector[0] = x0;
mVertexAttrib0Vector[1] = x1;
mVertexAttrib0Vector[2] = x2;
mVertexAttrib0Vector[3] = x3;
if (gl->IsGLES2())
gl->fVertexAttrib4f(index, x0, x1, x2, x3);
}
}
void
WebGLContext::VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib1fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = WebGLfloat(0);
mVertexAttrib0Vector[2] = WebGLfloat(0);
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib1fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib2fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = WebGLfloat(0);
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib2fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib3fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = WebGLfloat(1);
if (gl->IsGLES2())
gl->fVertexAttrib3fv(idx, ptr);
}
}
void
WebGLContext::VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength,
const WebGLfloat* ptr)
{
if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
return;
MakeContextCurrent();
if (idx) {
gl->fVertexAttrib4fv(idx, ptr);
} else {
mVertexAttrib0Vector[0] = ptr[0];
mVertexAttrib0Vector[1] = ptr[1];
mVertexAttrib0Vector[2] = ptr[2];
mVertexAttrib0Vector[3] = ptr[3];
if (gl->IsGLES2())
gl->fVertexAttrib4fv(idx, ptr);
}
}
void
WebGLContext::EnableVertexAttribArray(WebGLuint index)
{
if (!IsContextStable())
return;
if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
return;
MakeContextCurrent();
InvalidateBufferFetching();
gl->fEnableVertexAttribArray(index);
mBoundVertexArray->mAttribBuffers[index].enabled = true;
}
void
WebGLContext::DisableVertexAttribArray(WebGLuint index)
{
if (!IsContextStable())
return;
if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
return;
MakeContextCurrent();
InvalidateBufferFetching();
if (index || gl->IsGLES2())
gl->fDisableVertexAttribArray(index);
mBoundVertexArray->mAttribBuffers[index].enabled = false;
}
JS::Value
WebGLContext::GetVertexAttrib(JSContext* cx, WebGLuint index, WebGLenum pname,
ErrorResult& rv)
{
if (!IsContextStable())
return JS::NullValue();
if (!mBoundVertexArray->EnsureAttribIndex(index, "getVertexAttrib"))
return JS::NullValue();
MakeContextCurrent();
switch (pname) {
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
{
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribBuffers[index].buf.get(), rv);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
{
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].stride);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
{
if (!ValidateAttribIndex(index, "getVertexAttrib"))
return JS::NullValue();
if (!mBoundVertexArray->mAttribBuffers[index].enabled)
return JS::Int32Value(4);
// Don't break; fall through.
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
{
GLint i = 0;
gl->fGetVertexAttribiv(index, pname, &i);
if (pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE)
return JS::Int32Value(i);
MOZ_ASSERT(pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE);
return JS::NumberValue(uint32_t(i));
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
{
if (IsWebGL2())
{
return JS::Int32Value(mBoundVertexArray->mAttribBuffers[index].divisor);
}
break;
}
case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
{
WebGLfloat vec[4] = {0, 0, 0, 1};
if (index) {
gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]);
} else {
vec[0] = mVertexAttrib0Vector[0];
vec[1] = mVertexAttrib0Vector[1];
vec[2] = mVertexAttrib0Vector[2];
vec[3] = mVertexAttrib0Vector[3];
}
JSObject* obj = Float32Array::Create(cx, this, 4, vec);
if (!obj) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
}
return JS::ObjectOrNullValue(obj);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
{
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].enabled);
}
case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
{
return JS::BooleanValue(mBoundVertexArray->mAttribBuffers[index].normalized);
}
default:
break;
}
ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
return JS::NullValue();
}
WebGLsizeiptr
WebGLContext::GetVertexAttribOffset(WebGLuint index, WebGLenum pname)
{
if (!IsContextStable())
return 0;
if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
return 0;
if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
ErrorInvalidEnum("getVertexAttribOffset: bad parameter");
return 0;
}
return mBoundVertexArray->mAttribBuffers[index].byteOffset;
}
void
WebGLContext::VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
WebGLboolean normalized, WebGLsizei stride,
WebGLintptr byteOffset)
{
if (!IsContextStable())
return;
if (mBoundArrayBuffer == nullptr)
return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
WebGLsizei 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.
WebGLsizei requiredAlignmentMask = requiredAlignment - 1;
if ( !mBoundVertexArray->EnsureAttribIndex(index, "vertexAttribPointer") ) {
return;
}
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
if (type != mBoundArrayBuffer->GLType())
return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
*/
WebGLVertexAttribData &vd = mBoundVertexArray->mAttribBuffers[index];
vd.buf = mBoundArrayBuffer;
vd.stride = stride;
vd.size = size;
vd.byteOffset = byteOffset;
vd.type = type;
vd.normalized = normalized;
MakeContextCurrent();
gl->fVertexAttribPointer(index, size, type, normalized,
stride,
reinterpret_cast<void*>(byteOffset));
}
void
WebGLContext::VertexAttribDivisor(WebGLuint index, WebGLuint divisor)
{
if (!IsContextStable())
return;
if ( !mBoundVertexArray->EnsureAttribIndex(index, "vertexAttribDivisor") ) {
return;
}
WebGLVertexAttribData& vd = mBoundVertexArray->mAttribBuffers[index];
vd.divisor = divisor;
InvalidateBufferFetching();
MakeContextCurrent();
gl->fVertexAttribDivisor(index, divisor);
}
bool WebGLContext::DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei primcount, const char* info)
{
@ -24,6 +429,11 @@ bool WebGLContext::DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
@ -39,8 +449,7 @@ bool WebGLContext::DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei
return false;
}
uint32_t maxAllowedCount = 0;
if (!ValidateBuffers(&maxAllowedCount, info)) {
if (!ValidateBufferFetching(info)) {
return false;
}
@ -51,11 +460,16 @@ bool WebGLContext::DrawArrays_check(WebGLint first, WebGLsizei count, WebGLsizei
return false;
}
if (uint32_t(checked_firstPlusCount.value()) > maxAllowedCount) {
if (uint32_t(checked_firstPlusCount.value()) > mMaxFetchedVertices) {
ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info);
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
@ -117,6 +531,11 @@ WebGLContext::DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr b
return false;
}
if (primcount < 0) {
ErrorInvalidValue("%s: negative primcount", info);
return false;
}
if (!ValidateStencilParamsForDrawCall()) {
return false;
}
@ -188,12 +607,11 @@ WebGLContext::DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr b
return false;
}
uint32_t maxAllowedCount = 0;
if (!ValidateBuffers(&maxAllowedCount, info))
if (!ValidateBufferFetching(info))
return false;
if (!maxAllowedCount ||
!mBoundVertexArray->mBoundElementArrayBuffer->Validate(type, maxAllowedCount - 1, first, count))
if (!mMaxFetchedVertices ||
!mBoundVertexArray->mBoundElementArrayBuffer->Validate(type, mMaxFetchedVertices - 1, first, count))
{
ErrorInvalidOperation(
"%s: bound vertex attribute buffers do not have sufficient "
@ -201,6 +619,11 @@ WebGLContext::DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr b
return false;
}
if (uint32_t(primcount) > mMaxFetchedInstances) {
ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
return false;
}
MakeContextCurrent();
if (mBoundFramebuffer) {
@ -210,7 +633,7 @@ WebGLContext::DrawElements_check(WebGLsizei count, WebGLenum type, WebGLintptr b
}
}
if (!DoFakeVertexAttrib0(maxAllowedCount)) {
if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
return false;
}
BindFakeBlackTextures();
@ -247,7 +670,7 @@ WebGLContext::DrawElementsInstanced(WebGLenum mode, WebGLsizei count, WebGLenum
if (!ValidateDrawModeEnum(mode, "drawElementsInstanced: mode"))
return;
if (!DrawElements_check(count, type, byteOffset, 1, "drawElementsInstanced"))
if (!DrawElements_check(count, type, byteOffset, primcount, "drawElementsInstanced"))
return;
SetupContextLossTimer();
@ -279,3 +702,82 @@ void WebGLContext::Draw_cleanup()
}
}
/*
* Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
* that will be legal to be read from bound VBOs.
*/
bool
WebGLContext::ValidateBufferFetching(const char *info)
{
#ifdef DEBUG
GLint currentProgram = 0;
MakeContextCurrent();
gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
"WebGL: current program doesn't agree with GL state");
#endif
if (mBufferFetchingIsVerified) {
return true;
}
uint32_t maxVertices = UINT32_MAX;
uint32_t maxInstances = UINT32_MAX;
uint32_t attribs = mBoundVertexArray->mAttribBuffers.Length();
for (uint32_t i = 0; i < attribs; ++i) {
const WebGLVertexAttribData& vd = mBoundVertexArray->mAttribBuffers[i];
// If the attrib array isn't enabled, there's nothing to check;
// it's a static value.
if (!vd.enabled)
continue;
if (vd.buf == nullptr) {
ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
return false;
}
// If the attrib is not in use, then we don't have to validate
// it, just need to make sure that the binding is non-null.
if (!mCurrentProgram->IsAttribInUse(i))
continue;
// the base offset
CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.isValid())
{
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (checked_byteLength.value() < checked_sizeOfLastElement.value()) {
maxVertices = 0;
maxInstances = 0;
break;
}
CheckedUint32 checked_maxAllowedCount = ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.isValid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
if (vd.divisor == 0)
maxVertices = std::min(maxVertices, checked_maxAllowedCount.value());
else
maxInstances = std::min(maxInstances, checked_maxAllowedCount.value() / vd.divisor);
}
mBufferFetchingIsVerified = true;
mMaxFetchedVertices = maxVertices;
mMaxFetchedInstances = maxInstances;
return true;
}

View File

@ -23,39 +23,63 @@ class WebGLVertexArray MOZ_FINAL
, public WebGLContextBoundObject
, public nsWrapperCache
{
// -----------------------------------------------------------------------------
// PUBLIC
public:
// -------------------------------------------------------------------------
// CONSTRUCTOR & DESTRUCTOR
WebGLVertexArray(WebGLContext *context);
~WebGLVertexArray() {
DeleteOnce();
};
void Delete();
bool HasEverBeenBound() { return mHasEverBeenBound; }
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
WebGLuint GLName() const { return mGLName; }
// -------------------------------------------------------------------------
// IMPLMENET PARENT CLASSES
void Delete();
WebGLContext* GetParentObject() const {
return Context();
}
bool EnsureAttribIndex(WebGLuint index, const char *info);
virtual JSObject* WrapObject(JSContext *cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WebGLVertexArray)
// -------------------------------------------------------------------------
// MEMBER FUNCTIONS
bool HasEverBeenBound() { return mHasEverBeenBound; }
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
WebGLuint GLName() const { return mGLName; }
bool EnsureAttribIndex(WebGLuint index, const char *info);
// -----------------------------------------------------------------------------
// PRIVATE
private:
// -------------------------------------------------------------------------
// MEMBERS
WebGLuint mGLName;
bool mHasEverBeenBound;
nsTArray<WebGLVertexAttribData> mAttribBuffers;
WebGLRefPtr<WebGLBuffer> mBoundElementArrayBuffer;
// -------------------------------------------------------------------------
// FRIENDSHIPS
friend class WebGLContext;
friend class WebGLExtensionVertexArray;
};
} // namespace mozilla

View File

@ -13,13 +13,20 @@ class WebGLBuffer;
struct WebGLVertexAttribData {
// note that these initial values are what GL initializes vertex attribs to
WebGLVertexAttribData()
: buf(0), stride(0), size(4), byteOffset(0),
type(LOCAL_GL_FLOAT), enabled(false), normalized(false)
: buf(0)
, stride(0)
, size(4)
, divisor(0) // OpenGL ES 3.0 specs paragraphe 6.2 p240
, byteOffset(0)
, type(LOCAL_GL_FLOAT)
, enabled(false)
, normalized(false)
{ }
WebGLRefPtr<WebGLBuffer> buf;
WebGLuint stride;
WebGLuint size;
WebGLuint divisor;
GLuint byteOffset;
GLenum type;
bool enabled;

View File

@ -64,6 +64,11 @@ interface WebGL2RenderingContext : WebGLRenderingContext {
const GLenum QUERY_RESULT = 0x8866;
const GLenum QUERY_RESULT_AVAILABLE = 0x8867;
/* instanced array */
const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
void vertexAttribDivisor(GLuint index, GLuint divisor);
void beginQuery(GLenum target, WebGLQuery? queryObject);
void bindVertexArray(WebGLVertexArray? arrayObject);

View File

@ -97,7 +97,9 @@ static const char *sExtensionNames[] = {
"GL_ARB_draw_instanced",
"GL_EXT_draw_instanced",
"GL_NV_draw_instanced",
"GL_ANGLE_instanced_array",
"GL_ARB_instanced_arrays",
"GL_NV_instanced_arrays",
"GL_ANGLE_instanced_arrays",
"GL_EXT_occlusion_query_boolean",
nullptr
};
@ -634,6 +636,27 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
}
}
if (IsExtensionSupported(XXX_instanced_arrays)) {
SymLoadStruct instancedArraySymbols[] = {
{ (PRFuncPtr*) &mSymbols.fVertexAttribDivisor,
{ "VertexAttribDivisor",
"VertexAttribDivisorARB",
"VertexAttribDivisorNV",
"VertexAttribDivisorANGLE",
nullptr
}
},
{ nullptr, { nullptr } },
};
if (!LoadSymbols(instancedArraySymbols, trygl, prefix)) {
NS_ERROR("GL supports array instanced without supplying it function.");
mInitialized &= MarkExtensionGroupUnsupported(XXX_instanced_arrays);
mSymbols.fVertexAttribDivisor = nullptr;
}
}
if (IsGLES2() &&
IsExtensionSupported(EXT_occlusion_query_boolean)) {
SymLoadStruct queryObjectsSymbols[] = {

View File

@ -380,7 +380,9 @@ public:
ARB_draw_instanced,
EXT_draw_instanced,
NV_draw_instanced,
ANGLE_instanced_array,
ARB_instanced_arrays,
NV_instanced_arrays,
ANGLE_instanced_arrays,
EXT_occlusion_query_boolean,
Extensions_Max,
Extensions_End
@ -480,6 +482,7 @@ public:
XXX_framebuffer_blit,
XXX_framebuffer_multisample,
XXX_framebuffer_object,
XXX_instanced_arrays,
XXX_robustness,
XXX_texture_float,
XXX_texture_non_power_of_two,
@ -2140,6 +2143,18 @@ public:
}
// -----------------------------------------------------------------------------
// Package XXX_instanced_arrays
public:
void fVertexAttribDivisor(GLuint index, GLuint divisor)
{
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fVertexAttribDivisor);
mSymbols.fVertexAttribDivisor(index, divisor);
AFTER_GL_CALL;
}
// -----------------------------------------------------------------------------
// Package XXX_vertex_array_object
public:

View File

@ -39,7 +39,7 @@ static const ExtensionGroupInfo sExtensionGroupInfoArr[] = {
GLContext::ARB_draw_instanced,
GLContext::EXT_draw_instanced,
GLContext::NV_draw_instanced,
GLContext::ANGLE_instanced_array,
GLContext::ANGLE_instanced_arrays,
GLContext::Extensions_End
}
},
@ -73,6 +73,17 @@ static const ExtensionGroupInfo sExtensionGroupInfoArr[] = {
GLContext::Extensions_End
}
},
{
"XXX_instanced_arrays",
330, // OpenGL version
300, // OpenGL ES version
{
GLContext::ARB_instanced_arrays,
GLContext::NV_instanced_arrays,
GLContext::ANGLE_instanced_arrays,
GLContext::Extensions_End
}
},
{
"XXX_robustness",
0, // OpenGL version

View File

@ -415,6 +415,10 @@ struct GLContextSymbols
PFNGLDRAWARRAYSINSTANCED fDrawArraysInstanced;
typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCED) (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei primcount);
PFNGLDRAWELEMENTSINSTANCED fDrawElementsInstanced;
// ARB_instanced_array
typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISOR) (GLuint index, GLuint divisor);
PFNGLVERTEXATTRIBDIVISOR fVertexAttribDivisor;
};
}

View File

@ -853,6 +853,7 @@ typedef uint64_t EGLTime;
#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
#define LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
#define LOCAL_GL_CURRENT_VERTEX_ATTRIB 0x8626
#define LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
#define LOCAL_GL_VERTEX_PROGRAM_TWO_SIDE 0x8643