mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
bug 893180 - [WebGL 2.0] gl.vertexAttribDivisor (GL_ARB_instanced_array) - r=jgilbert
This commit is contained in:
parent
ea783aac7d
commit
25e763c7a5
@ -197,8 +197,9 @@ WebGLContext::WebGLContext()
|
||||
|
||||
mLastUseIndex = 0;
|
||||
|
||||
mMinInUseAttribArrayLengthCached = false;
|
||||
mMinInUseAttribArrayLength = 0;
|
||||
mBufferFetchingIsVerified = false;
|
||||
mMaxFetchedVertices = 0;
|
||||
mMaxFetchedInstances = 0;
|
||||
|
||||
mIsScreenCleared = false;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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, ¤tProgram);
|
||||
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))
|
||||
))
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ WebGLContext::BindVertexArray(WebGLVertexArray *array)
|
||||
return;
|
||||
}
|
||||
|
||||
InvalidateCachedMinInUseAttribArrayLength();
|
||||
InvalidateBufferFetching();
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
|
@ -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, ¤tProgram);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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[] = {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user