From 20a02b0b66a9483d88af6043abbc7507d256d18f Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Mon, 15 Dec 2014 10:31:24 +1000 Subject: [PATCH] Bug 1048747 - [WebGL2] Implement uniform block/buffer. r=jgilbert, r=smaug --HG-- extra : rebase_source : cdd24494397c9b6ce9f7103c78b8432107ddc20f extra : source : dadf008b2b7a14d0c308ab4c8eae6001fb5f7492 extra : histedit_source : 90b49de9e294dd8e89a666fa9b3025892a6cf4e6 --- dom/canvas/WebGL2Context.h | 25 +- dom/canvas/WebGL2ContextUniforms.cpp | 303 +++++++++++++++++++---- dom/webidl/WebGL2RenderingContext.webidl | 8 +- 3 files changed, 284 insertions(+), 52 deletions(-) diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index 55baf3aa1b1..41eb93b52cc 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -14,6 +14,10 @@ class WebGLSampler; class WebGLSync; class WebGLTransformFeedback; class WebGLVertexArrayObject; +namespace dom { +class OwningUnsignedLongOrUint32ArrayOrBoolean; +class OwningWebGLBufferOrLongLong; +} class WebGL2Context : public WebGLContext @@ -231,14 +235,23 @@ public: void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer); void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size); */ - void GetIndexedParameter(JSContext*, GLenum target, GLuint index, JS::MutableHandleValue retval); - void GetUniformIndices(WebGLProgram* program, const dom::Sequence& uniformNames, dom::Nullable< nsTArray >& retval); - void GetActiveUniforms(WebGLProgram* program, const dom::Sequence& uniformIndices, GLenum pname, + void GetIndexedParameter(GLenum target, GLuint index, + dom::Nullable& retval); + void GetUniformIndices(WebGLProgram* program, + const dom::Sequence& uniformNames, + dom::Nullable< nsTArray >& retval); + void GetActiveUniforms(WebGLProgram* program, + const dom::Sequence& uniformIndices, GLenum pname, dom::Nullable< nsTArray >& retval); GLuint GetUniformBlockIndex(WebGLProgram* program, const nsAString& uniformBlockName); - void GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, GLuint uniformBlockIndex, GLenum pname, JS::MutableHandleValue retval); - void GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, dom::DOMString& retval); - void UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); + void GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, + GLuint uniformBlockIndex, GLenum pname, + dom::Nullable& retval, + ErrorResult& rv); + void GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, + nsAString& retval); + void UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding); // ------------------------------------------------------------------------- diff --git a/dom/canvas/WebGL2ContextUniforms.cpp b/dom/canvas/WebGL2ContextUniforms.cpp index b803bddf6c7..a555e12d766 100644 --- a/dom/canvas/WebGL2ContextUniforms.cpp +++ b/dom/canvas/WebGL2ContextUniforms.cpp @@ -5,8 +5,11 @@ #include "WebGL2Context.h" #include "GLContext.h" +#include "WebGLContext.h" +#include "WebGLProgram.h" #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" +#include "mozilla/dom/WebGL2RenderingContextBinding.h" using namespace mozilla; using namespace mozilla::dom; @@ -30,38 +33,39 @@ GLfloat PuntToFloat(GLuint u) } bool -WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) +WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, + GLsizei* out_alignment, const char* info) { - MOZ_ASSERT(alignment); + MOZ_ASSERT(out_alignment); switch (type) { case LOCAL_GL_BYTE: case LOCAL_GL_UNSIGNED_BYTE: - *alignment = 1; + *out_alignment = 1; return true; case LOCAL_GL_SHORT: case LOCAL_GL_UNSIGNED_SHORT: - *alignment = 2; + *out_alignment = 2; return true; case LOCAL_GL_INT: case LOCAL_GL_UNSIGNED_INT: - *alignment = 4; + *out_alignment = 4; return true; } if (!integerMode) { switch (type) { case LOCAL_GL_HALF_FLOAT: - *alignment = 2; + *out_alignment = 2; return true; case LOCAL_GL_FLOAT: case LOCAL_GL_FIXED: case LOCAL_GL_INT_2_10_10_10_REV: case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV: - *alignment = 4; + *out_alignment = 4; return true; } } @@ -74,7 +78,8 @@ WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* // Uniforms and attributes void -WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset) +WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, + GLintptr offset) { if (IsContextLost()) return; @@ -82,8 +87,11 @@ WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsiz if (!ValidateAttribIndex(index, "vertexAttribIPointer")) return; - if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer")) + if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, + "vertexAttribIPointer")) + { return; + } MOZ_ASSERT(mBoundVertexArray); mBoundVertexArray->EnsureAttrib(index); @@ -123,103 +131,120 @@ WebGL2Context::Uniform3ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, } void -WebGL2Context::Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) +WebGL2Context::Uniform4ui(WebGLUniformLocation* location, GLuint v0, GLuint v1, + GLuint v2, GLuint v3) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform1uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform1uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform2uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform2uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform3uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform3uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::Uniform4uiv(WebGLUniformLocation* location, const dom::Sequence& value) +WebGL2Context::Uniform4uiv(WebGLUniformLocation* location, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix2x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix3x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value) +WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Float32Array& value) { MOZ_CRASH("Not Implemented."); } void -WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence& value) +WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, + const dom::Sequence& value) { MOZ_CRASH("Not Implemented."); } @@ -309,13 +334,51 @@ WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence& v) // TODO(djg): Implemented in WebGLContext /* void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer); - void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size); + void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, + GLintptr offset, GLsizeiptr size); */ +/* This doesn't belong here. It's part of state querying */ void -WebGL2Context::GetIndexedParameter(JSContext*, GLenum target, GLuint index, JS::MutableHandleValue retval) +WebGL2Context::GetIndexedParameter(GLenum target, GLuint index, + dom::Nullable& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + GLint64 data = 0; + + MakeContextCurrent(); + + switch (target) { + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: + if (index >= mGLMaxTransformFeedbackSeparateAttribs) + return ErrorInvalidValue("getIndexedParameter: index should be less than " + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + + retval.SetValue().SetAsWebGLBuffer() = + mBoundTransformFeedbackBuffers[index].get(); + return; + + case LOCAL_GL_UNIFORM_BUFFER_BINDING: + if (index >= mGLMaxUniformBufferBindings) + return ErrorInvalidValue("getIndexedParameter: index should be than " + "MAX_UNIFORM_BUFFER_BINDINGS"); + + retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get(); + return; + + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START: + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE: + case LOCAL_GL_UNIFORM_BUFFER_START: + case LOCAL_GL_UNIFORM_BUFFER_SIZE: + gl->fGetInteger64i_v(target, index, &data); + retval.SetValue().SetAsLongLong() = data; + return; + } + + ErrorInvalidEnumInfo("getIndexedParameter: target", target); } void @@ -323,7 +386,32 @@ WebGL2Context::GetUniformIndices(WebGLProgram* program, const dom::Sequence& uniformNames, dom::Nullable< nsTArray >& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getUniformIndices: program", program)) + return; + + if (!uniformNames.Length()) + return; + + GLuint progname = program->GLName(); + size_t count = uniformNames.Length(); + nsTArray& arr = retval.SetValue(); + + MakeContextCurrent(); + + for (size_t n = 0; n < count; n++) { + NS_LossyConvertUTF16toASCII name(uniformNames[n]); + // const GLchar* glname = name.get(); + const GLchar* glname = nullptr; + name.BeginReading(glname); + + GLuint index = 0; + gl->fGetUniformIndices(progname, 1, &glname, &index); + arr.AppendElement(index); + } } void @@ -332,32 +420,159 @@ WebGL2Context::GetActiveUniforms(WebGLProgram* program, GLenum pname, dom::Nullable< nsTArray >& retval) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniforms: program", program)) + return; + + size_t count = uniformIndices.Length(); + if (!count) + return; + + GLuint progname = program->GLName(); + nsTArray& arr = retval.SetValue(); + arr.SetLength(count); + + MakeContextCurrent(); + gl->fGetActiveUniformsiv(progname, count, uniformIndices.Elements(), pname, + arr.Elements()); } GLuint -WebGL2Context::GetUniformBlockIndex(WebGLProgram* program, const nsAString& uniformBlockName) +WebGL2Context::GetUniformBlockIndex(WebGLProgram* program, + const nsAString& uniformBlockName) { - MOZ_CRASH("Not Implemented."); - return 0; + if (IsContextLost()) + return 0; + + if (!ValidateObject("getUniformBlockIndex: program", program)) + return 0; + + if (!ValidateGLSLVariableName(uniformBlockName, "getUniformBlockIndex")) + return 0; + + NS_LossyConvertUTF16toASCII cname(uniformBlockName); + nsCString mappedName; + program->MapIdentifier(cname, &mappedName); + + GLuint progname = program->GLName(); + + MakeContextCurrent(); + return gl->fGetUniformBlockIndex(progname, mappedName.get()); +} + +static bool +GetUniformBlockActiveUniforms(gl::GLContext* gl, JSContext* cx, + WebGL2Context* owner, GLuint progname, + GLuint uniformBlockIndex, + JS::MutableHandleObject out_array) +{ + GLint length = 0; + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, + LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &length); + JS::RootedObject obj(cx, Uint32Array::Create(cx, owner, length, nullptr)); + if (!obj) + return false; + + JS::AutoCheckCannotGC nogc; + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, + LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, + (GLint*) JS_GetUint32ArrayData(obj, nogc)); + + out_array.set(obj); + return true; } void -WebGL2Context::GetActiveUniformBlockParameter(JSContext*, WebGLProgram* program, +WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* program, GLuint uniformBlockIndex, GLenum pname, - JS::MutableHandleValue retval) + Nullable& retval, + ErrorResult& rv) { - MOZ_CRASH("Not Implemented."); + retval.SetNull(); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniformBlockParameter: program", program)) + return; + + GLuint progname = program->GLName(); + GLint param = 0; + JS::RootedObject array(cx); + + MakeContextCurrent(); + + switch(pname) { + case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER: + case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, ¶m); + retval.SetValue().SetAsBoolean() = (param != 0); + return; + + case LOCAL_GL_UNIFORM_BLOCK_BINDING: + case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE: + case LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH: + case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: + gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, ¶m); + retval.SetValue().SetAsUnsignedLong() = param; + return; + + case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: + if (!GetUniformBlockActiveUniforms(gl, cx, this, progname, uniformBlockIndex, + &array)) + { + rv = NS_ERROR_OUT_OF_MEMORY; + return; + } + + DebugOnly inited = retval.SetValue().SetAsUint32Array().Init(array); + MOZ_ASSERT(inited); + + return; + } + + ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname); } -void -WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, dom::DOMString& retval) -{ - MOZ_CRASH("Not Implemented."); -} +#define WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH 256 void -WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) +WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex, + nsAString& retval) { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + if (!ValidateObject("getActiveUniformBlockName: program", program)) + return; + + GLuint progname = program->GLName(); + GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH]; + GLsizei length = 0; + + MakeContextCurrent(); + gl->fGetActiveUniformBlockName(progname, uniformBlockIndex, + WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH, &length, + nameBuffer); + retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(nameBuffer))); +} + +#undef WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH + +void +WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex, + GLuint uniformBlockBinding) +{ + if (IsContextLost()) + return; + + if (!ValidateObject("uniformBlockBinding: program", program)) + return; + + GLuint progname = program->GLName(); + + MakeContextCurrent(); + gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding); } diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl index b981883d714..93719a627a5 100644 --- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -454,11 +454,15 @@ interface WebGL2RenderingContext : WebGLRenderingContext /* Uniform Buffer Objects and Transform Feedback Buffers */ void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer); void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size); - any getIndexedParameter(GLenum target, GLuint index); + // Return from getIndexedParameter is WebGLBuffer or GLintptr or GLsizeiptr) but + // GLintptr and GLsizeiptr are the same underlying type of long long, so only specify + // GLintptr here, otherwise interface generator returns error. + (WebGLBuffer or GLintptr)? getIndexedParameter(GLenum target, GLuint index); sequence? getUniformIndices(WebGLProgram? program, sequence uniformNames); sequence? getActiveUniforms(WebGLProgram? program, sequence uniformIndices, GLenum pname); GLuint getUniformBlockIndex(WebGLProgram? program, DOMString uniformBlockName); - any getActiveUniformBlockParameter(WebGLProgram? program, GLuint uniformBlockIndex, GLenum pname); + [Throws] + (GLuint or Uint32Array or GLboolean)? getActiveUniformBlockParameter(WebGLProgram? program, GLuint uniformBlockIndex, GLenum pname); DOMString? getActiveUniformBlockName(WebGLProgram? program, GLuint uniformBlockIndex); void uniformBlockBinding(WebGLProgram? program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);