diff --git a/dom/canvas/WebGL1Context.h b/dom/canvas/WebGL1Context.h index d7d54265977c..b0c0ea7e66a1 100644 --- a/dom/canvas/WebGL1Context.h +++ b/dom/canvas/WebGL1Context.h @@ -31,6 +31,8 @@ public: private: virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE; + virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE; + virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE; }; } // namespace mozilla diff --git a/dom/canvas/WebGL1ContextBuffers.cpp b/dom/canvas/WebGL1ContextBuffers.cpp new file mode 100644 index 000000000000..0a48d0b0801a --- /dev/null +++ b/dom/canvas/WebGL1ContextBuffers.cpp @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WebGL1Context.h" +#include "WebGLBuffer.h" +#include "GLContext.h" + +using namespace mozilla; +using namespace mozilla::dom; + +// ------------------------------------------------------------------------- +// Buffer objects + +/** Target validation for BindBuffer, etc */ +bool +WebGL1Context::ValidateBufferTarget(GLenum target, const char* info) +{ + switch (target) { + case LOCAL_GL_ARRAY_BUFFER: + case LOCAL_GL_ELEMENT_ARRAY_BUFFER: + return true; + + default: + ErrorInvalidEnumInfo(info, target); + return false; + } +} + +bool +WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info) +{ + ErrorInvalidEnumInfo(info, target); + return false; +} diff --git a/dom/canvas/WebGL2Context.cpp b/dom/canvas/WebGL2Context.cpp index 0bba0aec2717..f8884eafbe6f 100644 --- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -6,6 +6,8 @@ #include "WebGL2Context.h" #include "GLContext.h" +#include "WebGLBuffer.h" +#include "WebGLTransformFeedback.h" #include "mozilla/dom/WebGL2RenderingContextBinding.h" #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" @@ -117,6 +119,11 @@ WebGLContext::InitWebGL2() gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs); + mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0); + mBoundTransformFeedback = mDefaultTransformFeedback; + auto xfBuffers = new WebGLRefPtr[mGLMaxTransformFeedbackSeparateAttribs]; + mBoundTransformFeedbackBuffers.reset(xfBuffers); + return true; } diff --git a/dom/canvas/WebGL2Context.h b/dom/canvas/WebGL2Context.h index 416390886a0a..680ab9a54bcb 100644 --- a/dom/canvas/WebGL2Context.h +++ b/dom/canvas/WebGL2Context.h @@ -215,14 +215,13 @@ public: already_AddRefed CreateTransformFeedback(); void DeleteTransformFeedback(WebGLTransformFeedback* tf); bool IsTransformFeedback(WebGLTransformFeedback* tf); - void BindTransformFeedback(GLenum target, GLuint id); + void BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf); void BeginTransformFeedback(GLenum primitiveMode); void EndTransformFeedback(); - void TransformFeedbackVaryings(WebGLProgram* program, GLsizei count, - const dom::Sequence& varyings, GLenum bufferMode); - already_AddRefed GetTransformFeedbackVarying(WebGLProgram* program, GLuint index); void PauseTransformFeedback(); void ResumeTransformFeedback(); + void TransformFeedbackVaryings(WebGLProgram* program, const dom::Sequence& varyings, GLenum bufferMode); + already_AddRefed GetTransformFeedbackVarying(WebGLProgram* program, GLuint index); // ------------------------------------------------------------------------- @@ -263,6 +262,8 @@ private: const char* info); virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE; + virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE; + virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE; }; } // namespace mozilla diff --git a/dom/canvas/WebGL2ContextBuffers.cpp b/dom/canvas/WebGL2ContextBuffers.cpp index 41e12b4af43f..8c7f75137440 100644 --- a/dom/canvas/WebGL2ContextBuffers.cpp +++ b/dom/canvas/WebGL2ContextBuffers.cpp @@ -9,6 +9,35 @@ using namespace mozilla; using namespace mozilla::dom; +bool +WebGL2Context::ValidateBufferTarget(GLenum target, const char* info) +{ + switch (target) { + case LOCAL_GL_ARRAY_BUFFER: + case LOCAL_GL_ELEMENT_ARRAY_BUFFER: + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + return true; + + default: + ErrorInvalidEnumInfo(info, target); + return false; + } +} + +bool +WebGL2Context::ValidateBufferIndexedTarget(GLenum target, const char* info) +{ + switch (target) { + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + case LOCAL_GL_UNIFORM_BUFFER: + return true; + + default: + ErrorInvalidEnumInfo(info, target); + return false; + } +} + // ------------------------------------------------------------------------- // Buffer objects diff --git a/dom/canvas/WebGL2ContextTransformFeedback.cpp b/dom/canvas/WebGL2ContextTransformFeedback.cpp index 37ced46c7891..76a960786fcd 100644 --- a/dom/canvas/WebGL2ContextTransformFeedback.cpp +++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp @@ -4,6 +4,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WebGL2Context.h" +#include "WebGLActiveInfo.h" +#include "WebGLProgram.h" +#include "WebGLTransformFeedback.h" #include "GLContext.h" using namespace mozilla; @@ -15,64 +18,237 @@ using namespace mozilla::dom; already_AddRefed WebGL2Context::CreateTransformFeedback() { - MOZ_CRASH("Not Implemented."); - return nullptr; + if (IsContextLost()) + return nullptr; + + GLuint tf = 0; + MakeContextCurrent(); + gl->fGenTransformFeedbacks(1, &tf); + + nsRefPtr globj = new WebGLTransformFeedback(this, tf); + return globj.forget(); } void WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf) { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf)) + return; + + if (!tf || tf->IsDeleted()) + return; + + if (mBoundTransformFeedback == tf) + BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tf); + + tf->RequestDelete(); } bool WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf) { - MOZ_CRASH("Not Implemented."); - return false; + if (IsContextLost()) + return false; + + if (!ValidateObjectAllowDeleted("isTransformFeedback", tf)) + return false; + + if (tf->IsDeleted()) + return false; + + MakeContextCurrent(); + return gl->fIsTransformFeedback(tf->GLName()); } void -WebGL2Context::BindTransformFeedback(GLenum target, GLuint id) +WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf) { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf)) + return; + + if (target != LOCAL_GL_TRANSFORM_FEEDBACK) + return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK"); + + WebGLRefPtr currentTF = mBoundTransformFeedback; + if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) { + return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform " + "feedback is active and not paused"); + } + + if (tf && tf->IsDeleted()) + return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id"); + + if (tf) + tf->BindTo(LOCAL_GL_TRANSFORM_FEEDBACK); + + MakeContextCurrent(); + gl->fBindTransformFeedback(target, tf ? tf->GLName() : 0); + if (tf) + mBoundTransformFeedback = tf; + else + mBoundTransformFeedback = mDefaultTransformFeedback; } void WebGL2Context::BeginTransformFeedback(GLenum primitiveMode) { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + WebGLTransformFeedback* tf = mBoundTransformFeedback; + MOZ_ASSERT(tf); + if (!tf) + return; + + if (tf->mIsActive) + return ErrorInvalidOperation("beginTransformFeedback: transform feedback is active"); + + const GLenum mode = tf->mMode; + if (mode != LOCAL_GL_POINTS && mode != LOCAL_GL_LINES && mode != LOCAL_GL_TRIANGLES) + return ErrorInvalidEnum("beginTransformFeedback: primitive must be one of POINTS, LINES, or TRIANGLES"); + + // TODO: + // GL_INVALID_OPERATION is generated by glBeginTransformFeedback + // if any binding point used in transform feedback mode does not + // have a buffer object bound. In interleaved mode, only the first + // buffer object binding point is ever written to. + + // GL_INVALID_OPERATION is generated by glBeginTransformFeedback + // if no binding points would be used, either because no program + // object is active of because the active program object has + // specified no varying variables to record. + if (!mCurrentProgram) + return ErrorInvalidOperation("beginTransformFeedback: no program is active"); + + MakeContextCurrent(); + gl->fBeginTransformFeedback(primitiveMode); + tf->mIsActive = true; + tf->mIsPaused = false; } void WebGL2Context::EndTransformFeedback() { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + WebGLTransformFeedback* tf = mBoundTransformFeedback; + MOZ_ASSERT(tf); + + if (!tf) + return; + + if (!tf->mIsActive) + return ErrorInvalidOperation("%s: transform feedback in not active", + "endTransformFeedback"); + + MakeContextCurrent(); + gl->fEndTransformFeedback(); + tf->mIsActive = false; + tf->mIsPaused = false; } void -WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program, GLsizei count, - const dom::Sequence& varyings, GLenum bufferMode) +WebGL2Context::PauseTransformFeedback() { - MOZ_CRASH("Not Implemented."); + if (IsContextLost()) + return; + + WebGLTransformFeedback* tf = mBoundTransformFeedback; + MOZ_ASSERT(tf); + if (!tf) + return; + + if (!tf->mIsActive || tf->mIsPaused) { + return ErrorInvalidOperation("%s: transform feedback is not active or is paused", + "pauseTransformFeedback"); + } + + MakeContextCurrent(); + gl->fPauseTransformFeedback(); + tf->mIsPaused = true; +} + +void +WebGL2Context::ResumeTransformFeedback() +{ + if (IsContextLost()) + return; + + WebGLTransformFeedback* tf = mBoundTransformFeedback; + MOZ_ASSERT(tf); + if (!tf) + return; + + if (!tf->mIsActive || !tf->mIsPaused) + return ErrorInvalidOperation("resumeTransformFeedback: transform feedback is not active or is not paused"); + + MakeContextCurrent(); + gl->fResumeTransformFeedback(); + tf->mIsPaused = false; +} + +void +WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program, + const dom::Sequence& varyings, + GLenum bufferMode) +{ + if (IsContextLost()) + return; + + if (!ValidateObject("transformFeedbackVaryings: program", program)) + return; + + GLsizei count = varyings.Length(); + GLchar** tmpVaryings = (GLchar**) nsMemory::Alloc(count * sizeof(GLchar*)); + + for (GLsizei n = 0; n < count; n++) { + tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]); + } + + GLuint progname = program->GLName(); + MakeContextCurrent(); + gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode); + + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings); } already_AddRefed WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index) { - MOZ_CRASH("Not Implemented."); - return nullptr; -} + if (IsContextLost()) + return nullptr; -void -WebGL2Context::PauseTransformFeedback() -{ - MOZ_CRASH("Not Implemented."); -} + if (!ValidateObject("getTransformFeedbackVarying: program", program)) + return nullptr; -void -WebGL2Context::ResumeTransformFeedback() -{ - MOZ_CRASH("Not Implemented."); + MakeContextCurrent(); + + GLint len = 0; + GLuint progname = program->GLName(); + gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len); + if (!len) + return nullptr; + + UniquePtr name(new char[len]); + GLint tfsize = 0; + GLuint tftype = 0; + + gl->fGetTransformFeedbackVarying(progname, index, len, &len, &tfsize, &tftype, name.get()); + if (len == 0 || tfsize == 0 || tftype == 0) + return nullptr; + + // TODO(djg): Reverse lookup of name + // nsCString reverseMappedName; + // prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName); + + nsRefPtr result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get())); + return result.forget(); } diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 9354bb5beb72..0bb54d2cd924 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -54,6 +54,7 @@ #include "WebGLObjectModel.h" #include "WebGLQuery.h" #include "WebGLSampler.h" +#include "WebGLTransformFeedback.h" #include "WebGLVertexArray.h" #include "WebGLVertexAttribData.h" @@ -328,6 +329,14 @@ WebGLContext::DestroyResourcesAndContext() mBoundRenderbuffer = nullptr; mBoundVertexArray = nullptr; mDefaultVertexArray = nullptr; + mBoundTransformFeedback = nullptr; + mDefaultTransformFeedback = nullptr; + + if (mBoundTransformFeedbackBuffers) { + for (GLuint i = 0; i < mGLMaxTransformFeedbackSeparateAttribs; i++) { + mBoundTransformFeedbackBuffers[i] = nullptr; + } + } while (!mTextures.isEmpty()) mTextures.getLast()->DeleteOnce(); @@ -347,6 +356,8 @@ WebGLContext::DestroyResourcesAndContext() mQueries.getLast()->DeleteOnce(); while (!mSamplers.isEmpty()) mSamplers.getLast()->DeleteOnce(); + while (!mTransformFeedbacks.isEmpty()) + mTransformFeedbacks.getLast()->DeleteOnce(); mBlackOpaqueTexture2D = nullptr; mBlackOpaqueTextureCubeMap = nullptr; diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index dbeab2963346..5c426b9ccd9b 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -80,6 +80,7 @@ class WebGLSampler; class WebGLShader; class WebGLShaderPrecisionFormat; class WebGLTexture; +class WebGLTransformFeedback; class WebGLUniformLocation; class WebGLVertexArray; struct WebGLVertexAttribData; @@ -881,19 +882,16 @@ public: void DeleteBuffer(WebGLBuffer* buf); bool IsBuffer(WebGLBuffer* buf); -private: - // ARRAY_BUFFER slot +protected: + // bound buffer state WebGLRefPtr mBoundArrayBuffer; - - // TRANSFORM_FEEDBACK_BUFFER slot WebGLRefPtr mBoundTransformFeedbackBuffer; - // these two functions emit INVALID_ENUM for invalid `target`. - WebGLRefPtr* GetBufferSlotByTarget(GLenum target, - const char* info); + UniquePtr[]> mBoundTransformFeedbackBuffers; + + WebGLRefPtr* GetBufferSlotByTarget(GLenum target); WebGLRefPtr* GetBufferSlotByTargetIndexed(GLenum target, - GLuint index, - const char* info); + GLuint index); bool ValidateBufferUsageEnum(GLenum target, const char* info); // ----------------------------------------------------------------------------- @@ -1114,7 +1112,7 @@ protected: int32_t mGLMaxVertexUniformVectors; int32_t mGLMaxColorAttachments; int32_t mGLMaxDrawBuffers; - uint32_t mGLMaxTransformFeedbackSeparateAttribs; + GLuint mGLMaxTransformFeedbackSeparateAttribs; public: GLuint MaxVertexAttribs() const { @@ -1339,6 +1337,8 @@ private: // ------------------------------------------------------------------------- // Context customization points virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0; + virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0; + virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0; protected: int32_t MaxTextureSizeForTarget(TexTarget target) const { @@ -1380,6 +1380,7 @@ protected: WebGLRefPtr mBoundFramebuffer; WebGLRefPtr mBoundRenderbuffer; + WebGLRefPtr mBoundTransformFeedback; WebGLRefPtr mBoundVertexArray; LinkedList mTextures; @@ -1393,8 +1394,10 @@ protected: // TODO(djg): Does this need a rethink? Should it be WebGL2Context? LinkedList mSamplers; + LinkedList mTransformFeedbacks; WebGLRefPtr mDefaultVertexArray; + WebGLRefPtr mDefaultTransformFeedback; // PixelStore parameters uint32_t mPixelStorePackAlignment; @@ -1518,6 +1521,7 @@ public: friend class WebGLBuffer; friend class WebGLSampler; friend class WebGLShader; + friend class WebGLTransformFeedback; friend class WebGLUniformLocation; friend class WebGLVertexArray; friend class WebGLVertexArrayFake; diff --git a/dom/canvas/WebGLContextBuffers.cpp b/dom/canvas/WebGLContextBuffers.cpp index 32013428555f..7724b7e07665 100644 --- a/dom/canvas/WebGLContextBuffers.cpp +++ b/dom/canvas/WebGLContextBuffers.cpp @@ -24,11 +24,12 @@ WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer) if (buffer && buffer->IsDeleted()) return; - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bindBuffer"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bindBuffer")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + if (buffer) { if (!buffer->HasEverBeenBound()) { buffer->BindTo(target); @@ -60,11 +61,19 @@ WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer) return; } + // ValidateBufferTarget + switch (target) { + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= mGLMaxTransformFeedbackSeparateAttribs) + return ErrorInvalidValue("bindBufferBase: index should be less than " + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + default: + return ErrorInvalidEnumInfo("bindBufferBase: target", target); + } + WebGLRefPtr* indexedBufferSlot; - indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, - "bindBufferBase"); - if (!indexedBufferSlot) - return; + indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index); + MOZ_ASSERT(indexedBufferSlot); if (buffer) { if (!buffer->HasEverBeenBound()) @@ -77,9 +86,7 @@ WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer) } } - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bindBufferBase"); - + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch"); *indexedBufferSlot = buffer; @@ -104,11 +111,20 @@ WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, if (buffer && buffer->IsDeleted()) return; + // ValidateBufferTarget + switch (target) { + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + if (index >= mGLMaxTransformFeedbackSeparateAttribs) + return ErrorInvalidValue("bindBufferRange: index should be less than " + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS"); + + default: + return ErrorInvalidEnumInfo("bindBufferRange: target", target); + } + WebGLRefPtr* indexedBufferSlot; - indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, - "bindBufferRange"); - if (!indexedBufferSlot) - return; + indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index); + MOZ_ASSERT(indexedBufferSlot); if (buffer) { if (!buffer->HasEverBeenBound()) @@ -128,9 +144,7 @@ WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, } } - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "BindBufferRange"); - + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch"); *indexedBufferSlot = buffer; @@ -148,11 +162,12 @@ WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage) if (IsContextLost()) return; - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bufferData"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bufferData")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + if (size < 0) return ErrorInvalidValue("bufferData: negative size"); @@ -201,11 +216,12 @@ WebGLContext::BufferData(GLenum target, return ErrorInvalidValue("bufferData: null object passed"); } - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bufferData"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bufferData")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + const dom::ArrayBuffer& data = maybeData.Value(); data.ComputeLengthAndData(); @@ -244,11 +260,12 @@ WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data, if (IsContextLost()) return; - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bufferSubData"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bufferData")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + if (!ValidateBufferUsageEnum(usage, "bufferData: usage")) return; @@ -290,11 +307,12 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset, return; } - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bufferSubData"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bufferSubData")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + if (byteOffset < 0) return ErrorInvalidValue("bufferSubData: negative offset"); @@ -335,11 +353,12 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset, if (IsContextLost()) return; - WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target, - "bufferSubData"); - if (!bufferSlot) + if (!ValidateBufferTarget(target, "bufferSubData")) return; + WebGLRefPtr* bufferSlot = GetBufferSlotByTarget(target); + MOZ_ASSERT(bufferSlot); + if (byteOffset < 0) return ErrorInvalidValue("bufferSubData: negative offset"); @@ -445,48 +464,35 @@ WebGLContext::ValidateBufferUsageEnum(GLenum target, const char* info) } WebGLRefPtr* -WebGLContext::GetBufferSlotByTarget(GLenum target, const char* info) +WebGLContext::GetBufferSlotByTarget(GLenum target) { + /* This function assumes that target has been validated for either WebGL1 or WebGL. */ switch (target) { - case LOCAL_GL_ARRAY_BUFFER: - return &mBoundArrayBuffer; + case LOCAL_GL_ARRAY_BUFFER: + return &mBoundArrayBuffer; - case LOCAL_GL_ELEMENT_ARRAY_BUFFER: - return &mBoundVertexArray->mElementArrayBuffer; + case LOCAL_GL_ELEMENT_ARRAY_BUFFER: + return &mBoundVertexArray->mElementArrayBuffer; - case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: - if (!IsWebGL2()) { - break; - } - return &mBoundTransformFeedbackBuffer; + case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: + return &mBoundTransformFeedbackBuffer; - default: - break; + default: + return nullptr; } - - ErrorInvalidEnum("%s: target: Invalid enum value 0x%x.", info, target); - return nullptr; } WebGLRefPtr* -WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index, - const char* info) +WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index) { + /* This function assumes that target has been validated for either WebGL1 or WebGL. */ switch (target) { case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: - if (index >= mGLMaxTransformFeedbackSeparateAttribs) { - ErrorInvalidValue("%s: `index` should be less than" - " MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.", info, - index); - return nullptr; - } - return nullptr; // See bug 903594 - - default: - break; + MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs); + return &mBoundTransformFeedbackBuffers[index]; } - ErrorInvalidEnum("%s: target: invalid enum value 0x%x", info, target); + MOZ_CRASH("Should not get here."); return nullptr; } diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 47d840908d7b..08d935a2c069 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1105,12 +1105,12 @@ WebGLContext::GetBufferParameter(GLenum target, GLenum pname) if (IsContextLost()) return JS::NullValue(); - - WebGLRefPtr* slot = GetBufferSlotByTarget(target, - "getBufferParameter"); - if (!slot) + if (!ValidateBufferTarget(target, "getBufferParameter")) return JS::NullValue(); + WebGLRefPtr* slot = GetBufferSlotByTarget(target); + MOZ_ASSERT(slot); + if (!*slot) { ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target); return JS::NullValue(); diff --git a/dom/canvas/WebGLTransformFeedback.cpp b/dom/canvas/WebGLTransformFeedback.cpp index bd950e246ae7..283c9610d7ac 100644 --- a/dom/canvas/WebGLTransformFeedback.cpp +++ b/dom/canvas/WebGLTransformFeedback.cpp @@ -11,27 +11,37 @@ namespace mozilla { -WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl) - : WebGLBindableName(0) - , WebGLContextBoundObject(webgl) +WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* context, + GLuint tf) + : WebGLBindableName(tf) + , WebGLContextBoundObject(context) + , mMode(LOCAL_GL_NONE) + , mIsActive(false) + , mIsPaused(false) { - MOZ_CRASH("Not Implemented."); + context->mTransformFeedbacks.insertBack(this); } WebGLTransformFeedback::~WebGLTransformFeedback() -{} +{ + mMode = LOCAL_GL_NONE; + mIsActive = false; + mIsPaused = false; + DeleteOnce(); +} void WebGLTransformFeedback::Delete() { - MOZ_CRASH("Not Implemented."); + mContext->MakeContextCurrent(); + mContext->gl->fDeleteTransformFeedbacks(1, &mGLName); + removeFrom(mContext->mTransformFeedbacks); } WebGLContext* WebGLTransformFeedback::GetParentObject() const { - MOZ_CRASH("Not Implemented."); - return nullptr; + return Context(); } JSObject* diff --git a/dom/canvas/WebGLTransformFeedback.h b/dom/canvas/WebGLTransformFeedback.h index cd079f10c14a..5c16276f326c 100644 --- a/dom/canvas/WebGLTransformFeedback.h +++ b/dom/canvas/WebGLTransformFeedback.h @@ -21,9 +21,10 @@ class WebGLTransformFeedback MOZ_FINAL , public WebGLContextBoundObject { friend class WebGLContext; + friend class WebGL2Context; public: - explicit WebGLTransformFeedback(WebGLContext* webgl); + explicit WebGLTransformFeedback(WebGLContext* webgl, GLuint tf); void Delete(); WebGLContext* GetParentObject() const; @@ -34,6 +35,9 @@ public: private: ~WebGLTransformFeedback(); + GLenum mMode; + bool mIsActive; + bool mIsPaused; }; } // namespace mozilla diff --git a/dom/canvas/moz.build b/dom/canvas/moz.build index 5c7d32438ae5..0c85a2c4e0b6 100644 --- a/dom/canvas/moz.build +++ b/dom/canvas/moz.build @@ -42,6 +42,7 @@ UNIFIED_SOURCES += [ UNIFIED_SOURCES += [ 'MurmurHash3.cpp', 'WebGL1Context.cpp', + 'WebGL1ContextBuffers.cpp', 'WebGL1ContextUniforms.cpp', 'WebGL2Context.cpp', 'WebGL2ContextBuffers.cpp', diff --git a/dom/webidl/WebGL2RenderingContext.webidl b/dom/webidl/WebGL2RenderingContext.webidl index 6b950dcfe462..b981883d7146 100644 --- a/dom/webidl/WebGL2RenderingContext.webidl +++ b/dom/webidl/WebGL2RenderingContext.webidl @@ -443,10 +443,10 @@ interface WebGL2RenderingContext : WebGLRenderingContext WebGLTransformFeedback? createTransformFeedback(); void deleteTransformFeedback(WebGLTransformFeedback? tf); [WebGLHandlesContextLoss] GLboolean isTransformFeedback(WebGLTransformFeedback? tf); - void bindTransformFeedback(GLenum target, GLuint id); + void bindTransformFeedback(GLenum target, WebGLTransformFeedback? tf); void beginTransformFeedback(GLenum primitiveMode); void endTransformFeedback(); - void transformFeedbackVaryings(WebGLProgram? program, GLsizei count, sequence varyings, GLenum bufferMode); + void transformFeedbackVaryings(WebGLProgram? program, sequence varyings, GLenum bufferMode); [NewObject] WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram? program, GLuint index); void pauseTransformFeedback(); void resumeTransformFeedback(); diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index dfa9ea0de674..4d6a04db1ca1 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -2730,7 +2730,7 @@ public: AFTER_GL_CALL; } - void fDeleteTransformFeedbacks(GLsizei n, GLuint* ids) + void fDeleteTransformFeedbacks(GLsizei n, const GLuint* ids) { BEFORE_GL_CALL; ASSERT_SYMBOL_PRESENT(fDeleteTransformFeedbacks); diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index d02377f2e64f..452b63e4ab79 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -487,7 +487,7 @@ struct GLContextSymbols typedef void (GLAPIENTRY * PFNGLGENTRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint* ids); PFNGLGENTRANSFORMFEEDBACKSPROC fGenTransformFeedbacks; - typedef void (GLAPIENTRY * PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, GLuint* ids); + typedef void (GLAPIENTRY * PFNGLDELETETRANSFORMFEEDBACKSPROC) (GLsizei n, const GLuint* ids); PFNGLDELETETRANSFORMFEEDBACKSPROC fDeleteTransformFeedbacks; typedef realGLboolean (GLAPIENTRY * PFNGLISTRANSFORMFEEDBACKPROC) (GLuint id); PFNGLISTRANSFORMFEEDBACKPROC fIsTransformFeedback;