bug 903481_- step 3 - [WebGL 2.0] implement TRANSFORM_FEEDBACK_BUFFER - r=jgilbert

This commit is contained in:
Guillaume Abadie 2013-08-20 11:36:20 -04:00
Родитель 4f2b0458e0
Коммит b34f7bed28
7 изменённых файлов: 271 добавлений и 71 удалений

Просмотреть файл

@ -170,6 +170,7 @@ WebGLContext::WebGLContext()
mGLMaxVertexUniformVectors = 0;
mGLMaxColorAttachments = 1;
mGLMaxDrawBuffers = 1;
mGLMaxTransformFeedbackSeparateAttribs = 0;
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
mPixelStorePackAlignment = 4;
@ -235,6 +236,7 @@ WebGLContext::DestroyResourcesAndContext()
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBoundArrayBuffer = nullptr;
mBoundTransformFeedbackBuffer = nullptr;
mCurrentProgram = nullptr;
mBoundFramebuffer = nullptr;
mActiveOcclusionQuery = nullptr;

Просмотреть файл

@ -744,6 +744,9 @@ private:
// Buffer Objects (WebGLContextBuffers.cpp)
public:
void BindBuffer(WebGLenum target, WebGLBuffer* buf);
void BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buffer);
void BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size);
void BufferData(WebGLenum target, WebGLsizeiptr size, WebGLenum usage);
void BufferData(WebGLenum target, const dom::ArrayBufferView &data,
WebGLenum usage);
@ -759,10 +762,15 @@ public:
bool IsBuffer(WebGLBuffer *buffer);
private:
// ARRAY_BUFFER binding point
// ARRAY_BUFFER slot
WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
bool ValidateBufferTarget(GLenum target, const char* infos);
// TRANSFORM_FEEDBACK_BUFFER slot
WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
// these two functions emit INVALID_ENUM for invalid `target`.
WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTarget(GLenum target, const char* infos);
WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos);
bool ValidateBufferUsageEnum(WebGLenum target, const char* infos);
// -----------------------------------------------------------------------------
@ -771,6 +779,7 @@ public:
void Disable(WebGLenum cap);
void Enable(WebGLenum cap);
JS::Value GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv);
JS::Value GetParameterIndexed(JSContext* cx, WebGLenum pname, WebGLuint index);
bool IsEnabled(WebGLenum cap);
private:
@ -927,6 +936,7 @@ protected:
int32_t mGLMaxVertexUniformVectors;
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
// Represents current status, or state, of the context. That is, is it lost
// or stable and what part of the context lost process are we currently at.

Просмотреть файл

@ -23,30 +23,100 @@ WebGLContext::BindBuffer(WebGLenum target, WebGLBuffer *buffer)
if (buffer && buffer->IsDeleted())
return;
if (!ValidateBufferTarget(target, "bindBuffer")) {
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
if (!bufferSlot) {
return;
}
if (buffer) {
if ((buffer->Target() != LOCAL_GL_NONE) && (target != buffer->Target()))
if (!buffer->Target()) {
buffer->SetTarget(target);
buffer->SetHasEverBeenBound(true);
} else if (target != buffer->Target()) {
return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
buffer->SetTarget(target);
buffer->SetHasEverBeenBound(true);
}
}
// we really want to do this AFTER all the validation is done, otherwise our bookkeeping could get confused.
// see bug 656752
if (target == LOCAL_GL_ARRAY_BUFFER) {
mBoundArrayBuffer = buffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
mBoundVertexArray->mBoundElementArrayBuffer = buffer;
}
*bufferSlot = buffer;
MakeContextCurrent();
gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
}
void
WebGLContext::BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buffer)
{
if (!IsContextStable())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted()) {
return;
}
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
if (!bufferSlot) {
return;
}
if (buffer) {
if (!buffer->Target()) {
buffer->SetTarget(target);
buffer->SetHasEverBeenBound(true);
} else if (target != buffer->Target()) {
return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
}
}
*bufferSlot = buffer;
MakeContextCurrent();
gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
}
void
WebGLContext::BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size)
{
if (!IsContextStable())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
if (!bufferSlot) {
return;
}
if (buffer) {
if (!buffer->Target()) {
buffer->SetTarget(target);
buffer->SetHasEverBeenBound(true);
} else if (target != buffer->Target()) {
return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
}
}
*bufferSlot = buffer;
MakeContextCurrent();
gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
}
void
WebGLContext::BufferData(WebGLenum target, WebGLsizeiptr size,
WebGLenum usage)
@ -54,14 +124,10 @@ WebGLContext::BufferData(WebGLenum target, WebGLsizeiptr size,
if (!IsContextStable())
return;
WebGLBuffer *boundBuffer = nullptr;
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
} else {
return ErrorInvalidEnumInfo("bufferData: target", target);
if (!bufferSlot) {
return;
}
if (size < 0)
@ -70,6 +136,8 @@ WebGLContext::BufferData(WebGLenum target, WebGLsizeiptr size,
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return;
WebGLBuffer* boundBuffer = bufferSlot->get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
@ -107,21 +175,19 @@ WebGLContext::BufferData(WebGLenum target,
return ErrorInvalidValue("bufferData: null object passed");
}
const ArrayBuffer& data = maybeData.Value();
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
WebGLBuffer *boundBuffer = nullptr;
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
} else {
return ErrorInvalidEnumInfo("bufferData: target", target);
if (!bufferSlot) {
return;
}
const ArrayBuffer& data = maybeData.Value();
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return;
WebGLBuffer* boundBuffer = bufferSlot->get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
@ -148,19 +214,17 @@ WebGLContext::BufferData(WebGLenum target, const ArrayBufferView& data,
if (!IsContextStable())
return;
WebGLBuffer *boundBuffer = nullptr;
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
} else {
return ErrorInvalidEnumInfo("bufferData: target", target);
if (!bufferSlot) {
return;
}
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return;
WebGLBuffer* boundBuffer = bufferSlot->get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
@ -191,21 +255,19 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
return;
}
const ArrayBuffer& data = maybeData.Value();
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
WebGLBuffer *boundBuffer = nullptr;
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
} else {
return ErrorInvalidEnumInfo("bufferSubData: target", target);
if (!bufferSlot) {
return;
}
const ArrayBuffer& data = maybeData.Value();
if (byteOffset < 0)
return ErrorInvalidValue("bufferSubData: negative offset");
WebGLBuffer* boundBuffer = bufferSlot->get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
@ -231,19 +293,17 @@ WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
if (!IsContextStable())
return;
WebGLBuffer *boundBuffer = nullptr;
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
if (target == LOCAL_GL_ARRAY_BUFFER) {
boundBuffer = mBoundArrayBuffer;
} else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
} else {
return ErrorInvalidEnumInfo("bufferSubData: target", target);
if (!bufferSlot) {
return;
}
if (byteOffset < 0)
return ErrorInvalidValue("bufferSubData: negative offset");
WebGLBuffer* boundBuffer = bufferSlot->get();
if (!boundBuffer)
return ErrorInvalidOperation("bufferSubData: no buffer bound!");
@ -312,23 +372,6 @@ WebGLContext::IsBuffer(WebGLBuffer *buffer)
buffer->HasEverBeenBound();
}
bool
WebGLContext::ValidateBufferTarget(WebGLenum target, const char* infos)
{
switch(target)
{
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
return true;
default:
break;
}
ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
return false;
}
bool
WebGLContext::ValidateBufferUsageEnum(WebGLenum target, const char *infos)
{
@ -344,3 +387,46 @@ WebGLContext::ValidateBufferUsageEnum(WebGLenum target, const char *infos)
ErrorInvalidEnumInfo(infos, target);
return false;
}
WebGLRefPtr<WebGLBuffer>*
WebGLContext::GetBufferSlotByTarget(GLenum target, const char* infos)
{
switch (target) {
case LOCAL_GL_ARRAY_BUFFER:
return &mBoundArrayBuffer;
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
return &mBoundVertexArray->mBoundElementArrayBuffer;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
if (!IsWebGL2()) {
break;
}
return &mBoundTransformFeedbackBuffer;
default:
break;
}
ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
return nullptr;
}
WebGLRefPtr<WebGLBuffer>*
WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos)
{
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
ErrorInvalidValue("%s: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", infos, index);
return nullptr;
}
return nullptr; // See bug 903594
default:
break;
}
ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
return nullptr;
}

Просмотреть файл

@ -302,6 +302,13 @@ WebGLContext::GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv)
}
return JS::ObjectOrNullValue(obj);
}
case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
{
if (!IsWebGL2()) {
break;
}
return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs);
}
// unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
// javascript integer values. We just return them as doubles and javascript doesn't care.
@ -435,6 +442,14 @@ WebGLContext::GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv)
return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
}
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
{
if (!IsWebGL2()) {
break;
}
return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
}
case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING:
{
return WebGLObjectAsJSValue(cx, mBoundVertexArray->mBoundElementArrayBuffer.get(), rv);
@ -472,6 +487,32 @@ WebGLContext::GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv)
return JS::NullValue();
}
JS::Value
WebGLContext::GetParameterIndexed(JSContext* cx, WebGLenum pname, WebGLuint index)
{
if (!IsContextStable())
return JS::NullValue();
MakeContextCurrent();
switch (pname) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
{
if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
ErrorInvalidValue("getParameterIndexed: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", index);
return JS::NullValue();
}
return JS::NullValue(); // See bug 903594
}
default:
break;
}
ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname);
return JS::NullValue();
}
bool
WebGLContext::IsEnabled(WebGLenum cap)
{

Просмотреть файл

@ -807,6 +807,7 @@ WebGLContext::InitAndValidateGL()
mBoundCubeMapTextures.Clear();
mBoundArrayBuffer = nullptr;
mBoundTransformFeedbackBuffer = nullptr;
mCurrentProgram = nullptr;
mBoundFramebuffer = nullptr;
@ -906,10 +907,14 @@ WebGLContext::InitAndValidateGL()
default:
GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
return false;
}
}
}
}
if (IsWebGL2()) {
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs);
}
// Always 1 for GLES2
mMaxFramebufferColorAttachments = 1;

Просмотреть файл

@ -613,4 +613,47 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_11(_class, \
_field1, \
_field2, \
_field3, \
_field4, \
_field5, \
_field6, \
_field7, \
_field8, \
_field9, \
_field10, \
_field11) \
NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10) \
NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11) \
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11) \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
#endif /* nsWrapperCache_h___ */

Просмотреть файл

@ -70,7 +70,20 @@ interface WebGL2RenderingContext : WebGLRenderingContext {
void vertexAttribDivisor(GLuint index, GLuint divisor);
/* transform feedback */
const GLenum RASTERIZER_DISCARD = 0x8C89;
const GLenum RASTERIZER_DISCARD = 0x8C89;
const GLenum TRANSFORM_FEEDBACK_BUFFER = 0x8C8E;
const GLenum TRANSFORM_FEEDBACK_BUFFER_BINDING = 0x8C8F;
const GLenum TRANSFORM_FEEDBACK_BUFFER_START = 0x8C84;
const GLenum TRANSFORM_FEEDBACK_BUFFER_SIZE = 0x8C85;
const GLenum MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B;
/* buffer objects */
void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer,
GLintptr offset, GLsizeiptr size);
/* state requests */
any getParameterIndexed(GLenum pname, GLuint index);
void beginQuery(GLenum target, WebGLQuery? queryObject);