--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -158,16 +158,18 @@ WebGLContext::InitWebGL2(FailureReason*
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
mIndexedUniformBufferBindings.resize(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
+ gl->fGenTransformFeedbacks(1, &mEmptyTFO);
+
////
if (!gl->IsGLES()) {
// Desktop OpenGL requires the following to be enabled in order to
// support sRGB operations on framebuffers.
gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
}
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -127,17 +127,32 @@ WebGL2Context::GetBufferSubData(GLenum t
const GLsizeiptr glByteLen(byteLen);
////
gl->MakeCurrent();
const ScopedLazyBind readBind(gl, target, buffer);
if (byteLen) {
- const auto mappedBytes = gl->fMapBufferRange(target, srcByteOffset, glByteLen,
+ const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
+ GLenum mapTarget = target;
+ if (isTF) {
+ gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
+ gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
+ mapTarget = LOCAL_GL_ARRAY_BUFFER;
+ }
+
+ const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
LOCAL_GL_MAP_READ_BIT);
- // Warning: Possibly shared memory. See bug 1225033.
memcpy(bytes, mappedBytes, byteLen);
- gl->fUnmapBuffer(target);
+ gl->fUnmapBuffer(mapTarget);
+
+ if (isTF) {
+ const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
+ gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
+ const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
+ : 0);
+ gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
+ }
}
}
} // namespace mozilla
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -76,20 +76,28 @@ WebGL2Context::BindTransformFeedback(GLe
ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
" paused.",
funcName);
return;
}
////
+ if (mBoundTransformFeedback) {
+ mBoundTransformFeedback->AddBufferBindCounts(-1);
+ }
+
mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
MakeContextCurrent();
gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
+
+ if (mBoundTransformFeedback) {
+ mBoundTransformFeedback->AddBufferBindCounts(+1);
+ }
}
void
WebGL2Context::BeginTransformFeedback(GLenum primMode)
{
if (IsContextLost())
return;
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -13,16 +13,18 @@
namespace mozilla {
WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
: WebGLRefCountedObject(webgl)
, mGLName(buf)
, mContent(Kind::Undefined)
, mUsage(LOCAL_GL_STATIC_DRAW)
, mByteLength(0)
+ , mTFBindCount(0)
+ , mNonTFBindCount(0)
{
mContext->mBuffers.insertBack(this);
}
WebGLBuffer::~WebGLBuffer()
{
DeleteOnce();
}
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -21,17 +21,16 @@ class WebGLElementArrayCache;
class WebGLBuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLBuffer>
, public LinkedListElement<WebGLBuffer>
{
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLTexture;
- friend class WebGLTransformFeedback;
public:
enum class Kind {
Undefined,
ElementArray,
OtherData
};
@@ -61,25 +60,56 @@ public:
return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
bool ValidateCanBindToTarget(const char* funcName, GLenum target);
void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
+ ////
+
+ static void AddBindCount(GLenum target, WebGLBuffer* buffer, int8_t addVal) {
+ if (!buffer)
+ return;
+
+ if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
+ MOZ_ASSERT_IF(addVal < 0, buffer->mTFBindCount >= size_t(-addVal));
+ buffer->mTFBindCount += addVal;
+ } else {
+ MOZ_ASSERT_IF(addVal < 0, buffer->mNonTFBindCount >= size_t(-addVal));
+ buffer->mNonTFBindCount += addVal;
+ }
+ }
+
+ static void SetSlot(GLenum target, WebGLBuffer* newBuffer,
+ WebGLRefPtr<WebGLBuffer>* const out_slot)
+ {
+ WebGLBuffer* const oldBuffer = *out_slot;
+ AddBindCount(target, oldBuffer, -1);
+ AddBindCount(target, newBuffer, +1);
+ *out_slot = newBuffer;
+ }
+
+ bool IsBoundForTF() const { return bool(mTFBindCount); }
+ bool IsBoundForNonTF() const { return bool(mNonTFBindCount); }
+
+ ////
+
const GLenum mGLName;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
protected:
~WebGLBuffer();
Kind mContent;
GLenum mUsage;
size_t mByteLength;
UniquePtr<WebGLElementArrayCache> mCache;
+ size_t mTFBindCount;
+ size_t mNonTFBindCount;
};
} // namespace mozilla
#endif // WEBGL_BUFFER_H_
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -115,17 +115,17 @@ WebGLContextOptions::WebGLContextOptions
WebGLContext::WebGLContext()
: WebGLContextUnchecked(nullptr)
, mBufferFetchingIsVerified(false)
, mBufferFetchingHasPerVertex(false)
, mMaxFetchedVertices(0)
, mMaxFetchedInstances(0)
, mLayerIsMirror(false)
, mBypassShaderValidation(false)
- , mBuffersForUB_Dirty(true)
+ , mEmptyTFO(0)
, mContextLossHandler(this)
, mNeedsFakeNoAlpha(false)
, mNeedsFakeNoDepth(false)
, mNeedsFakeNoStencil(false)
, mNeedsEmulatedLoneDepthStencil(false)
, mAllowFBInvalidation(gfxPrefs::WebGLFBInvalidation())
{
mGeneration = 0;
@@ -245,17 +245,16 @@ WebGLContext::DestroyResourcesAndContext
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
mQuerySlot_SamplesPassed = nullptr;
mQuerySlot_TFPrimsWritten = nullptr;
mQuerySlot_TimeElapsed = nullptr;
mIndexedUniformBufferBindings.clear();
- OnUBIndexedBindingsChanged();
//////
ClearLinkedList(mBuffers);
ClearLinkedList(mFramebuffers);
ClearLinkedList(mPrograms);
ClearLinkedList(mQueries);
ClearLinkedList(mRenderbuffers);
@@ -263,16 +262,23 @@ WebGLContext::DestroyResourcesAndContext
ClearLinkedList(mShaders);
ClearLinkedList(mSyncs);
ClearLinkedList(mTextures);
ClearLinkedList(mTransformFeedbacks);
ClearLinkedList(mVertexArrays);
//////
+ if (mEmptyTFO) {
+ gl->fDeleteTransformFeedbacks(1, &mEmptyTFO);
+ mEmptyTFO = 0;
+ }
+
+ //////
+
mFakeBlack_2D_0000 = nullptr;
mFakeBlack_2D_0001 = nullptr;
mFakeBlack_CubeMap_0000 = nullptr;
mFakeBlack_CubeMap_0001 = nullptr;
mFakeBlack_3D_0000 = nullptr;
mFakeBlack_3D_0001 = nullptr;
mFakeBlack_2D_Array_0000 = nullptr;
mFakeBlack_2D_Array_0001 = nullptr;
@@ -2380,52 +2386,16 @@ WebGLContext::ValidateArrayBufferView(co
elemCount = elemCountOverride;
}
*out_bytes = bytes + (elemOffset * elemSize);
*out_byteLen = elemCount * elemSize;
return true;
}
-////
-
-const decltype(WebGLContext::mBuffersForUB)&
-WebGLContext::BuffersForUB() const
-{
- if (mBuffersForUB_Dirty) {
- mBuffersForUB.clear();
- for (const auto& cur : mIndexedUniformBufferBindings) {
- if (cur.mBufferBinding) {
- mBuffersForUB.insert(cur.mBufferBinding.get());
- }
- }
- mBuffersForUB_Dirty = false;
- }
- return mBuffersForUB;
-}
-
-////
-
-bool
-WebGLContext::ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer)
-{
- if (!mBoundTransformFeedback)
- return true;
-
- const auto& buffersForTF = mBoundTransformFeedback->BuffersForTF();
- if (buffersForTF.count(buffer)) {
- ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for transform"
- " feedback.",
- funcName);
- return false;
- }
-
- return true;
-}
-
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
const std::vector<IndexedBufferBinding>& field,
const char* name, uint32_t flags)
{
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1649,18 +1649,16 @@ protected:
bool ValidateNonNegative(const char* funcName, const char* argName, int64_t val) {
if (MOZ_UNLIKELY(val < 0)) {
ErrorInvalidValue("%s: `%s` must be non-negative.", funcName, argName);
return false;
}
return true;
}
- bool ValidateForNonTransformFeedback(const char* funcName, WebGLBuffer* buffer);
-
public:
template<typename T>
bool ValidateNonNull(const char* funcName, const dom::Nullable<T>& maybe) {
if (maybe.IsNull()) {
ErrorInvalidValue("%s: `null` is invalid.", funcName);
return false;
}
return true;
@@ -1877,27 +1875,19 @@ protected:
UniquePtr<FakeBlackTexture> mFakeBlack_3D_0001;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0000;
UniquePtr<FakeBlackTexture> mFakeBlack_2D_Array_0001;
bool BindFakeBlack(uint32_t texUnit, TexTarget target, FakeBlackType fakeBlack);
////////////////////////////////////
-private:
- mutable bool mBuffersForUB_Dirty;
- mutable std::set<const WebGLBuffer*> mBuffersForUB;
+protected:
+ GLuint mEmptyTFO;
-public:
- void OnUBIndexedBindingsChanged() const { mBuffersForUB_Dirty = true; }
- const decltype(mBuffersForUB)& BuffersForUB() const;
-
- ////////////////////////////////////
-
-protected:
// Generic Vertex Attributes
// Though CURRENT_VERTEX_ATTRIB is listed under "Vertex Shader State" in the spec
// state tables, this isn't vertex shader /object/ state. This array is merely state
// useful to vertex shaders, but is global state.
UniquePtr<GLenum[]> mGenericVertexAttribTypes;
uint8_t mGenericVertexAttrib0Data[sizeof(float) * 4];
GLuint mFakeVertexAttrib0BufferObject;
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -70,18 +70,37 @@ WebGLContext::ValidateBufferSelection(co
return nullptr;
const auto& buffer = *slot;
if (!buffer) {
ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
return nullptr;
}
- if (!ValidateForNonTransformFeedback(funcName, buffer.get()))
- return nullptr;
+ if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER) {
+ if (mBoundTransformFeedback->IsActiveAndNotPaused()) {
+ ErrorInvalidOperation("%s: Cannot select TRANSFORM_FEEDBACK_BUFFER when"
+ " transform feedback is active and unpaused.",
+ funcName);
+ return nullptr;
+ }
+ if (buffer->IsBoundForNonTF()) {
+ ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
+ " non-transform-feedback.",
+ funcName);
+ return nullptr;
+ }
+ } else {
+ if (buffer->IsBoundForTF()) {
+ ErrorInvalidOperation("%s: Specified WebGLBuffer is currently bound for"
+ " transform feedback.",
+ funcName);
+ return nullptr;
+ }
+ }
return buffer.get();
}
IndexedBufferBinding*
WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
{
decltype(mIndexedUniformBufferBindings)* bindings;
@@ -127,17 +146,17 @@ WebGLContext::BindBuffer(GLenum target,
return;
if (buffer && !buffer->ValidateCanBindToTarget(funcName, target))
return;
gl->MakeCurrent();
gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
- *slot = buffer;
+ WebGLBuffer::SetSlot(target, buffer, slot);
if (buffer) {
buffer->SetContentAfterBind(target);
}
switch (target) {
case LOCAL_GL_PIXEL_PACK_BUFFER:
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
gl->fBindBuffer(target, 0);
@@ -196,33 +215,24 @@ WebGLContext::BindBufferBase(GLenum targ
////
gl->MakeCurrent();
gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
////
- *genericBinding = buffer;
- indexedBinding->mBufferBinding = buffer;
+ WebGLBuffer::SetSlot(target, buffer, genericBinding);
+ WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
indexedBinding->mRangeStart = 0;
indexedBinding->mRangeSize = 0;
if (buffer) {
buffer->SetContentAfterBind(target);
}
-
- switch (target) {
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- mBoundTransformFeedback->OnIndexedBindingsChanged();
- break;
- case LOCAL_GL_UNIFORM:
- OnUBIndexedBindingsChanged();
- break;
- }
}
void
WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size)
{
const char funcName[] = "bindBufferRange";
if (IsContextLost())
@@ -291,33 +301,24 @@ WebGLContext::BindBufferRange(GLenum tar
gl->fBindBuffer(target, buffer->mGLName);
}
#endif
gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
////
- *genericBinding = buffer;
- indexedBinding->mBufferBinding = buffer;
+ WebGLBuffer::SetSlot(target, buffer, genericBinding);
+ WebGLBuffer::SetSlot(target, buffer, &indexedBinding->mBufferBinding);
indexedBinding->mRangeStart = offset;
indexedBinding->mRangeSize = size;
if (buffer) {
buffer->SetContentAfterBind(target);
}
-
- switch (target) {
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- mBoundTransformFeedback->OnIndexedBindingsChanged();
- break;
- case LOCAL_GL_UNIFORM:
- OnUBIndexedBindingsChanged();
- break;
- }
}
////////////////////////////////////////
void
WebGLContext::BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data,
GLenum usage)
{
@@ -472,49 +473,51 @@ WebGLContext::CreateBuffer()
void
WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
{
if (!ValidateDeleteObject("deleteBuffer", buffer))
return;
////
- const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
+ const auto fnClearIfBuffer = [&](GLenum target, WebGLRefPtr<WebGLBuffer>& bindPoint) {
if (bindPoint == buffer) {
- bindPoint = nullptr;
+ WebGLBuffer::SetSlot(target, nullptr, &bindPoint);
}
};
- fnClearIfBuffer(mBoundArrayBuffer);
- fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);
+ fnClearIfBuffer(0, mBoundArrayBuffer);
+ fnClearIfBuffer(0, mBoundVertexArray->mElementArrayBuffer);
+
+ for (auto& cur : mBoundVertexArray->mAttribs) {
+ fnClearIfBuffer(0, cur.mBuf);
+ }
// WebGL binding points
if (IsWebGL2()) {
- fnClearIfBuffer(mBoundCopyReadBuffer);
- fnClearIfBuffer(mBoundCopyWriteBuffer);
- fnClearIfBuffer(mBoundPixelPackBuffer);
- fnClearIfBuffer(mBoundPixelUnpackBuffer);
- fnClearIfBuffer(mBoundUniformBuffer);
- fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);
+ fnClearIfBuffer(0, mBoundCopyReadBuffer);
+ fnClearIfBuffer(0, mBoundCopyWriteBuffer);
+ fnClearIfBuffer(0, mBoundPixelPackBuffer);
+ fnClearIfBuffer(0, mBoundPixelUnpackBuffer);
+ fnClearIfBuffer(0, mBoundUniformBuffer);
+ fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
+ mBoundTransformFeedback->mGenericBufferBinding);
if (!mBoundTransformFeedback->mIsActive) {
for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
- fnClearIfBuffer(binding.mBufferBinding);
+ fnClearIfBuffer(LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER,
+ binding.mBufferBinding);
}
}
for (auto& binding : mIndexedUniformBufferBindings) {
- fnClearIfBuffer(binding.mBufferBinding);
+ fnClearIfBuffer(0, binding.mBufferBinding);
}
}
- for (auto& cur : mBoundVertexArray->mAttribs) {
- fnClearIfBuffer(cur.mBuf);
- }
-
////
buffer->RequestDelete();
}
bool
WebGLContext::IsBuffer(WebGLBuffer* buffer)
{
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -351,16 +351,17 @@ public:
return;
}
mDidFake = true;
////
// Check UBO sizes.
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
+
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
if (!binding) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is null.",
funcName);
*out_error = true;
return;
@@ -369,46 +370,77 @@ public:
const auto availByteCount = binding->ByteCount();
if (dataSize > availByteCount) {
mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is smaller"
" than UNIFORM_BLOCK_DATA_SIZE.",
funcName);
*out_error = true;
return;
}
- }
- ////
-
- const auto& tfo = mWebGL->mBoundTransformFeedback;
- if (tfo) {
- const auto& buffersForTF = tfo->BuffersForTF();
- const auto& buffersForUB = mWebGL->BuffersForUB();
- if (DoSetsIntersect(buffersForTF, buffersForUB)) {
- mWebGL->ErrorInvalidOperation("%s: At least one WebGLBuffer is bound for"
- " both transform feedback and as a uniform"
- " buffer.",
+ if (binding->mBufferBinding->IsBoundForTF()) {
+ mWebGL->ErrorInvalidOperation("%s: Buffer for uniform block is bound or"
+ " in use for transform feedback.",
funcName);
*out_error = true;
return;
}
}
////
- for (const auto& progAttrib : mWebGL->mActiveProgramLinkInfo->attribs) {
+ const auto& tfo = mWebGL->mBoundTransformFeedback;
+ if (tfo && tfo->IsActiveAndNotPaused()) {
+ uint32_t numUsed;
+ switch (linkInfo->transformFeedbackBufferMode) {
+ case LOCAL_GL_INTERLEAVED_ATTRIBS:
+ numUsed = 1;
+ break;
+
+ case LOCAL_GL_SEPARATE_ATTRIBS:
+ numUsed = linkInfo->transformFeedbackVaryings.size();
+ break;
+
+ default:
+ MOZ_CRASH();
+ }
+
+ for (uint32_t i = 0; i < numUsed; ++i) {
+ const auto& buffer = tfo->mIndexedBindings[i].mBufferBinding;
+ if (buffer->IsBoundForNonTF()) {
+ mWebGL->ErrorInvalidOperation("%s: Transform feedback varying %u's"
+ " buffer is bound for"
+ " non-transform-feedback.",
+ funcName, i);
+ *out_error = true;
+ return;
+ }
+ }
+ }
+
+ ////
+
+ for (const auto& progAttrib : linkInfo->attribs) {
const auto& loc = progAttrib.mLoc;
if (loc == -1)
continue;
const auto& attribData = mWebGL->mBoundVertexArray->mAttribs[loc];
GLenum attribDataBaseType;
if (attribData.mEnabled) {
attribDataBaseType = attribData.BaseType();
+
+ if (attribData.mBuf->IsBoundForTF()) {
+ mWebGL->ErrorInvalidOperation("%s: Vertex attrib %u's buffer is bound"
+ " or in use for transform feedback.",
+ funcName, loc);
+ *out_error = true;
+ return;
+ }
} else {
attribDataBaseType = mWebGL->mGenericVertexAttribTypes[loc];
}
if (attribDataBaseType != progAttrib.mBaseType) {
nsCString progType, dataType;
WebGLContext::EnumName(progAttrib.mBaseType, &progType);
WebGLContext::EnumName(attribDataBaseType, &dataType);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -587,22 +587,29 @@ WebGLContext::GetAttribLocation(const We
return -1;
return prog.GetAttribLocation(name);
}
JS::Value
WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
{
+ const char funcName[] = "getBufferParameter";
if (IsContextLost())
return JS::NullValue();
- const auto& buffer = ValidateBufferSelection("getBufferParameter", target);
- if (!buffer)
+ const auto& slot = ValidateBufferSlot(funcName, target);
+ if (!slot)
return JS::NullValue();
+ const auto& buffer = *slot;
+
+ if (!buffer) {
+ ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
+ return JS::NullValue();
+ }
switch (pname) {
case LOCAL_GL_BUFFER_SIZE:
return JS::NumberValue(buffer->ByteLength());
case LOCAL_GL_BUFFER_USAGE:
return JS::NumberValue(buffer->Usage());
--- a/dom/canvas/WebGLContextVertexArray.cpp
+++ b/dom/canvas/WebGLContextVertexArray.cpp
@@ -20,23 +20,30 @@ WebGLContext::BindVertexArray(WebGLVerte
if (array && !ValidateObject("bindVertexArrayObject", *array))
return;
InvalidateBufferFetching();
MakeContextCurrent();
+ if (mBoundVertexArray) {
+ mBoundVertexArray->AddBufferBindCounts(-1);
+ }
+
if (array == nullptr) {
array = mDefaultVertexArray;
}
array->BindVertexArray();
MOZ_ASSERT(mBoundVertexArray == array);
+ if (mBoundVertexArray) {
+ mBoundVertexArray->AddBufferBindCounts(+1);
+ }
}
already_AddRefed<WebGLVertexArray>
WebGLContext::CreateVertexArray()
{
if (IsContextLost())
return nullptr;
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -430,16 +430,17 @@ QueryProgramInfo(WebGLProgram* prog, gl:
return info.forget();
}
////////////////////////////////////////////////////////////////////////////////
webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
: prog(prog)
+ , transformFeedbackBufferMode(prog->mNextLink_TransformFeedbackBufferMode)
{ }
webgl::LinkedProgramInfo::~LinkedProgramInfo()
{
for (auto& cur : uniforms) {
delete cur;
}
for (auto& cur : uniformBlocks) {
@@ -692,44 +693,59 @@ JS::Value
WebGLProgram::GetProgramParameter(GLenum pname) const
{
gl::GLContext* gl = mContext->gl;
gl->MakeCurrent();
if (mContext->IsWebGL2()) {
switch (pname) {
case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
- return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
+ if (!IsLinked())
+ return JS::NumberValue(0);
+ return JS::NumberValue(LinkInfo()->uniformBlocks.size());
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
- return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
+ if (!IsLinked())
+ return JS::NumberValue(0);
+ return JS::NumberValue(LinkInfo()->transformFeedbackVaryings.size());
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
- return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
+ if (!IsLinked())
+ return JS::NumberValue(LOCAL_GL_INTERLEAVED_ATTRIBS);
+ return JS::NumberValue(LinkInfo()->transformFeedbackBufferMode);
}
}
switch (pname) {
case LOCAL_GL_ATTACHED_SHADERS:
+ return JS::NumberValue( int(bool(mVertShader.get())) + int(bool(mFragShader)) );
+
case LOCAL_GL_ACTIVE_UNIFORMS:
+ if (!IsLinked())
+ return JS::NumberValue(0);
+ return JS::NumberValue(LinkInfo()->uniforms.size());
+
case LOCAL_GL_ACTIVE_ATTRIBUTES:
- return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
+ if (!IsLinked())
+ return JS::NumberValue(0);
+ return JS::NumberValue(LinkInfo()->attribs.size());
case LOCAL_GL_DELETE_STATUS:
return JS::BooleanValue(IsDeleteRequested());
case LOCAL_GL_LINK_STATUS:
return JS::BooleanValue(IsLinked());
case LOCAL_GL_VALIDATE_STATUS:
#ifdef XP_MACOSX
// See comment in ValidateProgram.
if (gl->WorkAroundDriverBugs())
return JS::BooleanValue(true);
#endif
+ // Todo: Implement this in our code.
return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
default:
mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
pname);
return JS::NullValue();
}
}
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -82,16 +82,17 @@ struct LinkedProgramInfo final
friend class WebGLProgram;
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
//////
WebGLProgram* const prog;
+ const GLenum transformFeedbackBufferMode;
std::vector<AttribInfo> attribs;
std::vector<UniformInfo*> uniforms; // Owns its contents.
std::vector<UniformBlockInfo*> uniformBlocks; // Owns its contents.
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
// Needed for draw call validation.
std::vector<UniformInfo*> uniformSamplers;
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -12,17 +12,16 @@
namespace mozilla {
WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
: WebGLRefCountedObject(webgl)
, mGLName(tf)
, mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
, mIsPaused(false)
, mIsActive(false)
- , mBuffersForTF_Dirty(true)
{
mContext->mTransformFeedbacks.insertBack(this);
}
WebGLTransformFeedback::~WebGLTransformFeedback()
{
DeleteOnce();
}
@@ -32,38 +31,16 @@ WebGLTransformFeedback::Delete()
{
if (mGLName) {
mContext->MakeContextCurrent();
mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
}
removeFrom(mContext->mTransformFeedbacks);
}
-////
-
-const decltype(WebGLTransformFeedback::mBuffersForTF)&
-WebGLTransformFeedback::BuffersForTF() const
-{
- // The generic bind point cannot incur undefined read/writes because otherwise it
- // would be impossible to read back from this. The spec implies that readback from
- // the TRANSFORM_FEEDBACK target is possible, just not simultaneously with being
- // "bound or in use for transform feedback".
- // Therefore, only the indexed bindings of the TFO count.
- if (mBuffersForTF_Dirty) {
- mBuffersForTF.clear();
- for (const auto& cur : mIndexedBindings) {
- if (cur.mBufferBinding) {
- mBuffersForTF.insert(cur.mBufferBinding.get());
- }
- }
- mBuffersForTF_Dirty = false;
- }
- return mBuffersForTF;
-}
-
////////////////////////////////////////
void
WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
{
const char funcName[] = "beginTransformFeedback";
if (mIsActive)
@@ -204,16 +181,28 @@ WebGLTransformFeedback::ResumeTransformF
////
MOZ_ASSERT(mIsActive);
mIsPaused = false;
}
////////////////////////////////////////
+void
+WebGLTransformFeedback::AddBufferBindCounts(int8_t addVal) const
+{
+ const GLenum target = LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER;
+ WebGLBuffer::AddBindCount(target, mGenericBufferBinding.get(), addVal);
+ for (const auto& binding : mIndexedBindings) {
+ WebGLBuffer::AddBindCount(target, binding.mBufferBinding.get(), addVal);
+ }
+}
+
+////////////////////////////////////////
+
JSObject*
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLTransformFeedbackBinding::Wrap(cx, this, givenProto);
}
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTransformFeedback, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTransformFeedback, Release)
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -12,16 +12,17 @@
namespace mozilla {
class WebGLTransformFeedback final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLTransformFeedback>
, public LinkedListElement<WebGLTransformFeedback>
{
+ friend class ScopedDrawHelper;
friend class ScopedDrawWithTransformFeedback;
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLProgram;
public:
const GLuint mGLName;
private:
@@ -31,36 +32,32 @@ private:
bool mIsPaused;
bool mIsActive;
// Not in state tables:
WebGLRefPtr<WebGLProgram> mActive_Program;
MOZ_INIT_OUTSIDE_CTOR GLenum mActive_PrimMode;
MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertPosition;
MOZ_INIT_OUTSIDE_CTOR size_t mActive_VertCapacity;
- mutable bool mBuffersForTF_Dirty;
- mutable std::set<const WebGLBuffer*> mBuffersForTF;
-
public:
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
private:
~WebGLTransformFeedback();
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
void Delete();
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
- ////
+ bool IsActiveAndNotPaused() const { return mIsActive && !mIsPaused; }
- void OnIndexedBindingsChanged() const { mBuffersForTF_Dirty = true; }
- const decltype(mBuffersForTF)& BuffersForTF() const;
+ void AddBufferBindCounts(int8_t addVal) const;
// GL Funcs
void BeginTransformFeedback(GLenum primMode);
void EndTransformFeedback();
void PauseTransformFeedback();
void ResumeTransformFeedback();
};
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -23,16 +23,31 @@ WebGLVertexArray::WrapObject(JSContext*
WebGLVertexArray::WebGLVertexArray(WebGLContext* webgl)
: WebGLRefCountedObject(webgl)
, mGLName(0)
{
mAttribs.SetLength(mContext->mGLMaxVertexAttribs);
mContext->mVertexArrays.insertBack(this);
}
+WebGLVertexArray::~WebGLVertexArray()
+{
+ MOZ_ASSERT(IsDeleted());
+}
+
+void
+WebGLVertexArray::AddBufferBindCounts(int8_t addVal) const
+{
+ const GLenum target = 0; // Anything non-TF is fine.
+ WebGLBuffer::AddBindCount(target, mElementArrayBuffer.get(), addVal);
+ for (const auto& attrib : mAttribs) {
+ WebGLBuffer::AddBindCount(target, attrib.mBuf.get(), addVal);
+ }
+}
+
WebGLVertexArray*
WebGLVertexArray::Create(WebGLContext* webgl)
{
WebGLVertexArray* array;
if (webgl->gl->IsSupported(gl::GLFeature::vertex_array_object)) {
array = new WebGLVertexArrayGL(webgl);
} else {
array = new WebGLVertexArrayFake(webgl);
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -5,17 +5,16 @@
#ifndef WEBGL_VERTEX_ARRAY_H_
#define WEBGL_VERTEX_ARRAY_H_
#include "nsTArray.h"
#include "mozilla/LinkedList.h"
#include "nsWrapperCache.h"
-#include "WebGLBuffer.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
#include "WebGLVertexAttribData.h"
namespace mozilla {
class WebGLVertexArrayFake;
@@ -43,22 +42,21 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLVertexArray)
GLuint GLName() const { return mGLName; }
+ void AddBufferBindCounts(int8_t addVal) const;
+
protected:
explicit WebGLVertexArray(WebGLContext* webgl);
-
- virtual ~WebGLVertexArray() {
- MOZ_ASSERT(IsDeleted());
- }
+ virtual ~WebGLVertexArray();
virtual void GenVertexArray() = 0;
virtual void BindVertexArrayImpl() = 0;
virtual void DeleteImpl() = 0;
virtual bool IsVertexArrayImpl() const = 0;
GLuint mGLName;
nsTArray<WebGLVertexAttribData> mAttribs;
--- a/dom/canvas/WebGLVertexAttribData.cpp
+++ b/dom/canvas/WebGLVertexAttribData.cpp
@@ -1,16 +1,17 @@
/* -*- 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 "WebGLVertexAttribData.h"
#include "GLContext.h"
+#include "WebGLBuffer.h"
namespace mozilla {
static uint8_t
CalcBytesPerVertex(GLenum type, uint8_t size)
{
uint8_t bytesPerType;
switch (type) {
@@ -66,17 +67,17 @@ AttribPointerBaseType(bool integerFunc,
}
void
WebGLVertexAttribData::VertexAttribPointer(bool integerFunc, WebGLBuffer* buf,
uint8_t size, GLenum type, bool normalized,
uint32_t stride, uint64_t byteOffset)
{
mIntegerFunc = integerFunc;
- mBuf = buf;
+ WebGLBuffer::SetSlot(0, buf, &mBuf);
mType = type;
mBaseType = AttribPointerBaseType(integerFunc, type);
mSize = size;
mBytesPerVertex = CalcBytesPerVertex(mType, mSize);
mNormalized = normalized;
mStride = stride;
mExplicitStride = (mStride ? mStride : mBytesPerVertex);
mByteOffset = byteOffset;