--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -31,18 +31,15 @@ public:
// nsWrapperCache
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* alignment,
const char* info) override;
- virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
- virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
- virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
};
} // namespace mozilla
#endif // WEBGL_1_CONTEXT_H_
deleted file mode 100644
--- a/dom/canvas/WebGL1ContextBuffers.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- 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"
-
-namespace mozilla {
-
-// -------------------------------------------------------------------------
-// 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;
-}
-
-bool
-WebGL1Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
-{
- switch (usage) {
- case LOCAL_GL_STREAM_DRAW:
- case LOCAL_GL_STATIC_DRAW:
- case LOCAL_GL_DYNAMIC_DRAW:
- return true;
- default:
- break;
- }
-
- ErrorInvalidEnumInfo(info, usage);
- return false;
-}
-
-} // namespace mozilla
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -153,18 +153,17 @@ WebGLContext::InitWebGL2(FailureReason*
}
// we initialise WebGL 2 related stuff.
gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&mGLMaxTransformFeedbackSeparateAttribs);
gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
&mGLMaxUniformBufferBindings);
- mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
- mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
+ mIndexedUniformBufferBindings.resize(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
mBoundTransformFeedback = mDefaultTransformFeedback;
////
if (!gl->IsGLES()) {
// Desktop OpenGL requires the following to be enabled in order to
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -407,18 +407,15 @@ private:
void UpdateBoundQuery(GLenum target, WebGLQuery* query);
// CreateVertexArrayImpl is assumed to be infallible.
virtual WebGLVertexArray* CreateVertexArrayImpl() override;
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type,
uint32_t* alignment,
const char* info) override;
- virtual bool ValidateBufferTarget(GLenum target, const char* info) override;
- virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) override;
- virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) override;
virtual bool ValidateQueryTarget(GLenum target, const char* info) override;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) override;
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -6,230 +6,149 @@
#include "WebGL2Context.h"
#include "GLContext.h"
#include "WebGLBuffer.h"
#include "WebGLTransformFeedback.h"
namespace mozilla {
-bool
-WebGL2Context::ValidateBufferTarget(GLenum target, const char* funcName)
-{
- switch (target) {
- case LOCAL_GL_ARRAY_BUFFER:
- case LOCAL_GL_COPY_READ_BUFFER:
- case LOCAL_GL_COPY_WRITE_BUFFER:
- case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
- case LOCAL_GL_PIXEL_PACK_BUFFER:
- case LOCAL_GL_PIXEL_UNPACK_BUFFER:
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- case LOCAL_GL_UNIFORM_BUFFER:
- return true;
-
- default:
- ErrorInvalidEnumInfo(funcName, 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;
- }
-}
-
-bool
-WebGL2Context::ValidateBufferUsageEnum(GLenum usage, const char* info)
-{
- switch (usage) {
- case LOCAL_GL_DYNAMIC_COPY:
- case LOCAL_GL_DYNAMIC_DRAW:
- case LOCAL_GL_DYNAMIC_READ:
- case LOCAL_GL_STATIC_COPY:
- case LOCAL_GL_STATIC_DRAW:
- case LOCAL_GL_STATIC_READ:
- case LOCAL_GL_STREAM_COPY:
- case LOCAL_GL_STREAM_DRAW:
- case LOCAL_GL_STREAM_READ:
- return true;
- default:
- break;
- }
-
- ErrorInvalidEnumInfo(info, usage);
- return false;
-}
-
// -------------------------------------------------------------------------
// Buffer objects
void
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
GLintptr readOffset, GLintptr writeOffset,
GLsizeiptr size)
{
const char funcName[] = "copyBufferSubData";
if (IsContextLost())
return;
- if (!ValidateBufferTarget(readTarget, funcName) ||
- !ValidateBufferTarget(writeTarget, funcName))
+ const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
+ if (!readBuffer)
+ return;
+
+ const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
+ if (!writeBuffer)
+ return;
+
+ if (readBuffer->mNumActiveTFOs ||
+ writeBuffer->mNumActiveTFOs)
+ {
+ ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+ " object.",
+ funcName);
+ return;
+ }
+
+ if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
+ !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
+ !ValidateNonNegative(funcName, "size", size))
{
return;
}
- const WebGLRefPtr<WebGLBuffer>& readBufferSlot = GetBufferSlotByTarget(readTarget);
- const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget);
- if (!readBufferSlot || !writeBufferSlot)
- return;
+ const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
+ const WebGLBuffer* buffer)
+ {
+ const auto neededBytes = CheckedInt<size_t>(offset) + size;
+ if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
+ ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
+ return false;
+ }
+ return true;
+ };
- const WebGLBuffer* readBuffer = readBufferSlot.get();
- if (!readBuffer) {
- ErrorInvalidOperation("%s: No buffer bound to readTarget.", funcName);
+ if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
+ !fnValidateOffsetSize("write", writeOffset, writeBuffer))
+ {
return;
}
- WebGLBuffer* writeBuffer = writeBufferSlot.get();
- if (!writeBuffer) {
- ErrorInvalidOperation("%s: No buffer bound to writeTarget.", funcName);
- return;
- }
-
- if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), funcName))
- return;
-
- if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), funcName))
- return;
-
- if (readTarget == writeTarget &&
+ if (readBuffer == writeBuffer &&
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
{
return;
}
- WebGLBuffer::Kind readType = readBuffer->Content();
- WebGLBuffer::Kind writeType = writeBuffer->Content();
-
- if (readType != WebGLBuffer::Kind::Undefined &&
- writeType != WebGLBuffer::Kind::Undefined &&
- writeType != readType)
- {
+ const auto& readType = readBuffer->Content();
+ const auto& writeType = writeBuffer->Content();
+ MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
+ MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
+ if (writeType != readType) {
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
funcName,
(readType == WebGLBuffer::Kind::OtherData) ? "other"
: "element",
(writeType == WebGLBuffer::Kind::OtherData) ? "other"
: "element");
return;
}
- WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset,
- writeOffset, size);
-
- if (writeType == WebGLBuffer::Kind::Undefined) {
- writeBuffer->BindTo(
- (readType == WebGLBuffer::Kind::OtherData) ? LOCAL_GL_ARRAY_BUFFER
- : LOCAL_GL_ELEMENT_ARRAY_BUFFER);
- }
+ gl->MakeCurrent();
+ gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
}
void
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
const dom::ArrayBufferView& data)
{
const char funcName[] = "getBufferSubData";
if (IsContextLost())
return;
- // For the WebGLBuffer bound to the passed target, read
- // returnedData.byteLength bytes from the buffer starting at byte
- // offset offset and write them to returnedData.
-
- // If zero is bound to target, an INVALID_OPERATION error is
- // generated.
- if (!ValidateBufferTarget(target, funcName))
+ if (!ValidateNonNegative(funcName, "offset", offset))
return;
- // If offset is less than zero, an INVALID_VALUE error is
- // generated.
- if (offset < 0) {
- ErrorInvalidValue("%s: Offset must be non-negative.", funcName);
+ const auto& buffer = ValidateBufferSelection(funcName, target);
+ if (!buffer)
return;
- }
- WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
- WebGLBuffer* boundBuffer = bufferSlot.get();
- if (!boundBuffer) {
- ErrorInvalidOperation("%s: No buffer bound.", funcName);
- return;
- }
+ ////
// If offset + returnedData.byteLength would extend beyond the end
// of the buffer an INVALID_VALUE error is generated.
data.ComputeLengthAndData();
- CheckedInt<WebGLsizeiptr> neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + data.LengthAllowShared();
+ const auto neededByteLength = CheckedInt<size_t>(offset) + data.LengthAllowShared();
if (!neededByteLength.isValid()) {
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
funcName);
return;
}
- if (neededByteLength.value() > boundBuffer->ByteLength()) {
+ if (neededByteLength.value() > buffer->ByteLength()) {
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
" only has %d bytes.",
- funcName, neededByteLength.value(), boundBuffer->ByteLength());
+ funcName, neededByteLength.value(), buffer->ByteLength());
+ return;
+ }
+
+ ////
+
+ if (buffer->mNumActiveTFOs) {
+ ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+ " object.",
+ funcName);
return;
}
- // If target is TRANSFORM_FEEDBACK_BUFFER, and any transform
- // feedback object is currently active, an INVALID_OPERATION error
- // is generated.
- WebGLTransformFeedback* currentTF = mBoundTransformFeedback;
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
- if (currentTF->mIsActive) {
- ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
- funcName);
- return;
- }
-
- // https://github.com/NVIDIA/WebGL/commit/63aff5e58c1d79825a596f0f4aa46174b9a5f72c
- // Performing reads and writes on a buffer that is currently
- // bound for transform feedback causes undefined results in
- // GLES3.0 and OpenGL 4.5. In practice results of reads and
- // writes might be consistent as long as transform feedback
- // objects are not active, but neither GLES3.0 nor OpenGL 4.5
- // spec guarantees this - just being bound for transform
- // feedback is sufficient to cause undefined results.
-
- BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
+ if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
+ mBoundTransformFeedback->mIsActive)
+ {
+ ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
+ funcName);
+ return;
}
- /* If the buffer is written and read sequentially by other
- * operations and getBufferSubData, it is the responsibility of
- * the WebGL API to ensure that data are access
- * consistently. This applies even if the buffer is currently
- * bound to a transform feedback binding point.
- */
+ ////
- void* ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
- LOCAL_GL_MAP_READ_BIT);
+ gl->MakeCurrent();
+
+ const auto ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
+ LOCAL_GL_MAP_READ_BIT);
// Warning: Possibly shared memory. See bug 1225033.
memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
gl->fUnmapBuffer(target);
-
- ////
-
- if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER && currentTF) {
- BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, currentTF);
- }
}
} // namespace mozilla
--- a/dom/canvas/WebGL2ContextState.cpp
+++ b/dom/canvas/WebGL2ContextState.cpp
@@ -28,24 +28,27 @@ WebGL2Context::GetParameter(JSContext* c
return JS::NullValue();
MakeContextCurrent();
switch (pname) {
/* GLboolean */
case LOCAL_GL_RASTERIZER_DISCARD:
case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
- case LOCAL_GL_SAMPLE_COVERAGE:
- case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
- case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE: {
+ case LOCAL_GL_SAMPLE_COVERAGE: {
realGLboolean b = 0;
gl->fGetBooleanv(pname, &b);
return JS::BooleanValue(bool(b));
}
+ case LOCAL_GL_TRANSFORM_FEEDBACK_ACTIVE:
+ return JS::BooleanValue(mBoundTransformFeedback->mIsActive);
+ case LOCAL_GL_TRANSFORM_FEEDBACK_PAUSED:
+ return JS::BooleanValue(mBoundTransformFeedback->mIsPaused);
+
/* GLenum */
case LOCAL_GL_READ_BUFFER: {
if (mBoundReadFramebuffer)
return JS::Int32Value(mBoundReadFramebuffer->ReadBufferMode());
return JS::Int32Value(LOCAL_GL_BACK);
}
@@ -141,17 +144,20 @@ WebGL2Context::GetParameter(JSContext* c
case LOCAL_GL_PIXEL_PACK_BUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundPixelPackBuffer.get(), rv);
case LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundPixelUnpackBuffer.get(), rv);
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
- return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
+ {
+ const auto& tf = mBoundTransformFeedback;
+ return WebGLObjectAsJSValue(cx, tf->mGenericBufferBinding.get(), rv);
+ }
case LOCAL_GL_UNIFORM_BUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundUniformBuffer.get(), rv);
// DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
case LOCAL_GL_READ_FRAMEBUFFER_BINDING:
return WebGLObjectAsJSValue(cx, mBoundReadFramebuffer.get(), rv);
@@ -159,21 +165,24 @@ WebGL2Context::GetParameter(JSContext* c
return WebGLObjectAsJSValue(cx, mBoundSamplers[mActiveTexture].get(), rv);
case LOCAL_GL_TEXTURE_BINDING_2D_ARRAY:
return WebGLObjectAsJSValue(cx, mBound2DArrayTextures[mActiveTexture].get(), rv);
case LOCAL_GL_TEXTURE_BINDING_3D:
return WebGLObjectAsJSValue(cx, mBound3DTextures[mActiveTexture].get(), rv);
- case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING: {
- WebGLTransformFeedback* tf =
- (mBoundTransformFeedback != mDefaultTransformFeedback) ? mBoundTransformFeedback.get() : nullptr;
- return WebGLObjectAsJSValue(cx, tf, rv);
- }
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BINDING:
+ {
+ const WebGLTransformFeedback* tf = mBoundTransformFeedback;
+ if (tf == mDefaultTransformFeedback) {
+ tf = nullptr;
+ }
+ return WebGLObjectAsJSValue(cx, tf, rv);
+ }
case LOCAL_GL_VERTEX_ARRAY_BINDING: {
WebGLVertexArray* vao =
(mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
return WebGLObjectAsJSValue(cx, vao, rv);
}
case LOCAL_GL_VERSION:
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -15,38 +15,42 @@ namespace mozilla {
// Transform Feedback
already_AddRefed<WebGLTransformFeedback>
WebGL2Context::CreateTransformFeedback()
{
if (IsContextLost())
return nullptr;
+ MakeContextCurrent();
GLuint tf = 0;
- MakeContextCurrent();
gl->fGenTransformFeedbacks(1, &tf);
- RefPtr<WebGLTransformFeedback> globj = new WebGLTransformFeedback(this, tf);
- return globj.forget();
+ RefPtr<WebGLTransformFeedback> ret = new WebGLTransformFeedback(this, tf);
+ return ret.forget();
}
void
WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
{
+ const char funcName[] = "deleteTransformFeedback";
if (IsContextLost())
return;
- if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf))
+ if (!ValidateObject(funcName, tf))
return;
- if (!tf || tf->IsDeleted())
+ if (tf->mIsActive) {
+ ErrorInvalidOperation("%s: Cannot delete active transform feedbacks.", funcName);
return;
+ }
- if (mBoundTransformFeedback == tf)
+ if (mBoundTransformFeedback == tf) {
BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, nullptr);
+ }
tf->RequestDelete();
}
bool
WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf)
{
if (IsContextLost())
@@ -60,139 +64,77 @@ WebGL2Context::IsTransformFeedback(WebGL
MakeContextCurrent();
return gl->fIsTransformFeedback(tf->mGLName);
}
void
WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
{
+ const char funcName[] = "bindTransformFeedback";
if (IsContextLost())
return;
- if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf))
- return;
-
if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
- return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK");
+ return ErrorInvalidEnum("%s: `target` must be TRANSFORM_FEEDBACK.", funcName);
+
+ if (!ValidateObjectAllowNull(funcName, tf))
+ return;
- WebGLRefPtr<WebGLTransformFeedback> currentTF = mBoundTransformFeedback;
- if (currentTF && currentTF->mIsActive && !currentTF->mIsPaused) {
- return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform "
- "feedback is active and not paused");
+ if (mBoundTransformFeedback->mIsActive &&
+ !mBoundTransformFeedback->mIsPaused)
+ {
+ ErrorInvalidOperation("%s: Currently bound transform feedback is active and not"
+ " paused.",
+ funcName);
+ return;
}
- if (tf && tf->IsDeleted())
- return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id");
+ ////
+
+ mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
MakeContextCurrent();
- gl->fBindTransformFeedback(target, tf ? tf->mGLName : 0);
- if (tf)
- mBoundTransformFeedback = tf;
- else
- mBoundTransformFeedback = mDefaultTransformFeedback;
+ gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
}
void
-WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
+WebGL2Context::BeginTransformFeedback(GLenum primMode)
{
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;
+ mBoundTransformFeedback->BeginTransformFeedback(primMode);
}
void
WebGL2Context::EndTransformFeedback()
{
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;
+ mBoundTransformFeedback->EndTransformFeedback();
}
void
WebGL2Context::PauseTransformFeedback()
{
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;
+ mBoundTransformFeedback->PauseTransformFeedback();
}
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;
+ mBoundTransformFeedback->ResumeTransformFeedback();
}
void
WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
const dom::Sequence<nsString>& varyings,
GLenum bufferMode)
{
if (IsContextLost())
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -65,67 +65,70 @@ WebGL2Context::Uniform4ui(WebGLUniformLo
MakeContextCurrent();
gl->fUniform4ui(loc->mLoc, v0, v1, v2, v3);
}
// -------------------------------------------------------------------------
// Uniform Buffer Objects and Transform Feedback Buffers
-// 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);
-*/
-/* This doesn't belong here. It's part of state querying */
void
WebGL2Context::GetIndexedParameter(GLenum target, GLuint index,
dom::Nullable<dom::OwningWebGLBufferOrLongLong>& retval)
{
+ const char funcName[] = "getIndexedParameter";
retval.SetNull();
if (IsContextLost())
return;
- GLint64 data = 0;
+ const std::vector<IndexedBufferBinding>* bindings;
+ switch (target) {
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
+ bindings = &(mBoundTransformFeedback->mIndexedBindings);
+ break;
- MakeContextCurrent();
+ case LOCAL_GL_UNIFORM_BUFFER_BINDING:
+ case LOCAL_GL_UNIFORM_BUFFER_START:
+ case LOCAL_GL_UNIFORM_BUFFER_SIZE:
+ bindings = &mIndexedUniformBufferBindings;
+ break;
+
+ default:
+ ErrorInvalidEnumInfo("getIndexedParameter: target", target);
+ return;
+ }
+
+ if (index >= bindings->size()) {
+ ErrorInvalidValue("%s: `index` must be < %s.", funcName,
+ "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
+ return;
+ }
+ const auto& binding = (*bindings)[index];
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");
-
- if (mBoundTransformFeedbackBuffers[index].get()) {
- retval.SetValue().SetAsWebGLBuffer() =
- mBoundTransformFeedbackBuffers[index].get();
+ case LOCAL_GL_UNIFORM_BUFFER_BINDING:
+ if (binding.mBufferBinding) {
+ retval.SetValue().SetAsWebGLBuffer() = binding.mBufferBinding;
}
- return;
-
- case LOCAL_GL_UNIFORM_BUFFER_BINDING:
- if (index >= mGLMaxUniformBufferBindings)
- return ErrorInvalidValue("getIndexedParameter: index should be than "
- "MAX_UNIFORM_BUFFER_BINDINGS");
-
- if (mBoundUniformBuffers[index].get())
- retval.SetValue().SetAsWebGLBuffer() = mBoundUniformBuffers[index].get();
- return;
+ break;
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_START:
+ case LOCAL_GL_UNIFORM_BUFFER_START:
+ retval.SetValue().SetAsLongLong() = binding.mRangeStart;
+ break;
+
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;
+ retval.SetValue().SetAsLongLong() = binding.mRangeSize;
+ break;
}
-
- ErrorInvalidEnumInfo("getIndexedParameter: target", target);
}
void
WebGL2Context::GetUniformIndices(WebGLProgram* program,
const dom::Sequence<nsString>& uniformNames,
dom::Nullable< nsTArray<GLuint> >& retval)
{
retval.SetNull();
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -12,48 +12,49 @@
namespace mozilla {
WebGLBuffer::WebGLBuffer(WebGLContext* webgl, GLuint buf)
: WebGLContextBoundObject(webgl)
, mGLName(buf)
, mContent(Kind::Undefined)
, mByteLength(0)
+ , mNumActiveTFOs(0)
{
mContext->mBuffers.insertBack(this);
}
WebGLBuffer::~WebGLBuffer()
{
+ MOZ_ASSERT(!mNumActiveTFOs);
DeleteOnce();
}
void
-WebGLBuffer::BindTo(GLenum target)
+WebGLBuffer::SetContentAfterBind(GLenum target)
{
+ if (mContent != Kind::Undefined)
+ return;
+
switch (target) {
case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
mContent = Kind::ElementArray;
- if (!mCache)
- mCache = new WebGLElementArrayCache;
+ if (!mCache) {
+ mCache.reset(new WebGLElementArrayCache);
+ }
break;
case LOCAL_GL_ARRAY_BUFFER:
case LOCAL_GL_PIXEL_PACK_BUFFER:
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
case LOCAL_GL_UNIFORM_BUFFER:
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- mContent = Kind::OtherData;
- break;
-
case LOCAL_GL_COPY_READ_BUFFER:
case LOCAL_GL_COPY_WRITE_BUFFER:
- if (mContent == Kind::Undefined) {
- mContent = Kind::OtherData;
- }
+ mContent = Kind::OtherData;
break;
default:
MOZ_CRASH("GFX: invalid target");
}
}
void
@@ -61,16 +62,100 @@ WebGLBuffer::Delete()
{
mContext->MakeContextCurrent();
mContext->gl->fDeleteBuffers(1, &mGLName);
mByteLength = 0;
mCache = nullptr;
LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
}
+////////////////////////////////////////
+
+static bool
+ValidateBufferUsageEnum(WebGLContext* webgl, const char* funcName, GLenum usage)
+{
+ switch (usage) {
+ case LOCAL_GL_STREAM_DRAW:
+ case LOCAL_GL_STATIC_DRAW:
+ case LOCAL_GL_DYNAMIC_DRAW:
+ return true;
+
+ case LOCAL_GL_DYNAMIC_COPY:
+ case LOCAL_GL_DYNAMIC_READ:
+ case LOCAL_GL_STATIC_COPY:
+ case LOCAL_GL_STATIC_READ:
+ case LOCAL_GL_STREAM_COPY:
+ case LOCAL_GL_STREAM_READ:
+ if (MOZ_LIKELY(webgl->IsWebGL2()))
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ webgl->ErrorInvalidEnum("%s: Invalid `usage`: 0x%04x", funcName, usage);
+ return false;
+}
+
+void
+WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage)
+{
+ const char funcName[] = "bufferData";
+
+ if (!ValidateBufferUsageEnum(mContext, funcName, usage))
+ return;
+
+ if (mNumActiveTFOs) {
+ mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
+ " feedback object.",
+ funcName);
+ return;
+ }
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ mContext->InvalidateBufferFetching();
+
+#ifdef XP_MACOSX
+ // bug 790879
+ if (gl->WorkAroundDriverBugs() &&
+ size > INT32_MAX)
+ {
+ mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
+ return;
+ }
+#endif
+
+ const bool sizeChanges = (size != ByteLength());
+ if (sizeChanges) {
+ gl::GLContext::LocalErrorScope errorScope(*gl);
+ gl->fBufferData(target, size, data, usage);
+ const auto error = errorScope.GetError();
+
+ if (error) {
+ MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY);
+ mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error);
+ return;
+ }
+ } else {
+ gl->fBufferData(target, size, data, usage);
+ }
+
+ mByteLength = size;
+
+ // Warning: Possibly shared memory. See bug 1225033.
+ if (!ElementArrayCacheBufferData(data, size)) {
+ mByteLength = 0;
+ mContext->ErrorOutOfMemory("%s: Failed update index buffer cache.", funcName);
+ }
+}
+
+////////////////////////////////////////
+
bool
WebGLBuffer::ElementArrayCacheBufferData(const void* ptr,
size_t bufferSizeInBytes)
{
if (mContent == Kind::ElementArray)
return mCache->BufferData(ptr, bufferSizeInBytes);
return true;
@@ -88,20 +173,19 @@ size_t
WebGLBuffer::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
size_t sizeOfCache = mCache ? mCache->SizeOfIncludingThis(mallocSizeOf)
: 0;
return mallocSizeOf(this) + sizeOfCache;
}
bool
-WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first,
- size_t count, uint32_t* const out_upperBound)
+WebGLBuffer::Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count) const
{
- return mCache->Validate(type, maxAllowed, first, count, out_upperBound);
+ return mCache->Validate(type, maxAllowed, first, count);
}
bool
WebGLBuffer::IsElementArrayUsedWithMultipleTypes() const
{
return mCache->BeenUsedWithMultipleTypes();
}
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -3,76 +3,81 @@
* 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/. */
#ifndef WEBGL_BUFFER_H_
#define WEBGL_BUFFER_H_
#include "GLDefs.h"
#include "mozilla/LinkedList.h"
-#include "nsAutoPtr.h"
+#include "mozilla/UniquePtr.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
#include "WebGLTypes.h"
namespace mozilla {
class WebGLElementArrayCache;
class WebGLBuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLBuffer>
, public LinkedListElement<WebGLBuffer>
, public WebGLContextBoundObject
{
+ friend class WebGLContext;
+ friend class WebGL2Context;
+ friend class WebGLTexture;
+ friend class WebGLTransformFeedback;
+
public:
-
enum class Kind {
Undefined,
ElementArray,
OtherData
};
WebGLBuffer(WebGLContext* webgl, GLuint buf);
- void BindTo(GLenum target);
+ void SetContentAfterBind(GLenum target);
Kind Content() const { return mContent; }
void Delete();
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
- WebGLsizeiptr ByteLength() const { return mByteLength; }
- void SetByteLength(WebGLsizeiptr byteLength) { mByteLength = byteLength; }
+ size_t ByteLength() const { return mByteLength; }
bool ElementArrayCacheBufferData(const void* ptr, size_t bufferSizeInBytes);
void ElementArrayCacheBufferSubData(size_t pos, const void* ptr,
size_t updateSizeInBytes);
- bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
- uint32_t* const out_upperBound);
+ bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count) const;
bool IsElementArrayUsedWithMultipleTypes() const;
WebGLContext* GetParentObject() const {
return mContext;
}
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
+ void BufferData(GLenum target, size_t size, const void* data, GLenum usage);
+
const GLenum mGLName;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
protected:
~WebGLBuffer();
Kind mContent;
- WebGLsizeiptr mByteLength;
- nsAutoPtr<WebGLElementArrayCache> mCache;
+ size_t mByteLength;
+ UniquePtr<WebGLElementArrayCache> mCache;
+ size_t mNumActiveTFOs;
};
} // namespace mozilla
#endif // WEBGL_BUFFER_H_
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -241,31 +241,29 @@ WebGLContext::DestroyResourcesAndContext
mBound3DTextures.Clear();
mBound2DArrayTextures.Clear();
mBoundSamplers.Clear();
mBoundArrayBuffer = nullptr;
mBoundCopyReadBuffer = nullptr;
mBoundCopyWriteBuffer = nullptr;
mBoundPixelPackBuffer = nullptr;
mBoundPixelUnpackBuffer = nullptr;
- mBoundTransformFeedbackBuffer = nullptr;
mBoundUniformBuffer = nullptr;
mCurrentProgram = nullptr;
mActiveProgramLinkInfo = nullptr;
mBoundDrawFramebuffer = nullptr;
mBoundReadFramebuffer = nullptr;
mActiveOcclusionQuery = nullptr;
mBoundRenderbuffer = nullptr;
mBoundVertexArray = nullptr;
mDefaultVertexArray = nullptr;
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
- mBoundTransformFeedbackBuffers.Clear();
- mBoundUniformBuffers.Clear();
+ mIndexedUniformBufferBindings.clear();
//////
ClearLinkedList(mBuffers);
ClearLinkedList(mFramebuffers);
ClearLinkedList(mPrograms);
ClearLinkedList(mQueries);
ClearLinkedList(mRenderbuffers);
@@ -2068,16 +2066,40 @@ WebGLContext::ScopedMaskWorkaround::HasD
{
const auto& depth = fb->DepthAttachment();
const auto& stencil = fb->StencilAttachment();
return depth.IsDefined() && !stencil.IsDefined();
}
////////////////////////////////////////
+IndexedBufferBinding::IndexedBufferBinding()
+ : mRangeStart(0)
+ , mRangeSize(0)
+{ }
+
+uint64_t
+IndexedBufferBinding::ByteCount() const
+{
+ if (!mBufferBinding)
+ return 0;
+
+ uint64_t bufferSize = mBufferBinding->ByteLength();
+ if (!mRangeSize) // BindBufferBase
+ return bufferSize;
+
+ if (mRangeStart >= bufferSize)
+ return 0;
+ bufferSize -= mRangeStart;
+
+ return std::min(bufferSize, mRangeSize);
+}
+
+////////////////////////////////////////
+
ScopedUnpackReset::ScopedUnpackReset(WebGLContext* webgl)
: ScopedGLWrapper<ScopedUnpackReset>(webgl->gl)
, mWebGL(webgl)
{
if (mWebGL->mPixelStore_UnpackAlignment != 4) mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
if (mWebGL->IsWebGL2()) {
if (mWebGL->mPixelStore_UnpackRowLength != 0) mGL->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH , 0);
@@ -2417,16 +2439,34 @@ WebGLContext::StartVRPresentation()
screen->Morph(Move(factory));
return true;
}
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop
+void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
+ const std::vector<IndexedBufferBinding>& field,
+ const char* name, uint32_t flags)
+{
+ for (const auto& cur : field) {
+ ImplCycleCollectionTraverse(callback, cur.mBufferBinding, name, flags);
+ }
+}
+
+void
+ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field)
+{
+ field.clear();
+}
+
+////
+
NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mCanvasElement,
mOffscreenCanvas,
mExtensions,
mBound2DTextures,
@@ -2434,17 +2474,17 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(We
mBound3DTextures,
mBound2DArrayTextures,
mBoundSamplers,
mBoundArrayBuffer,
mBoundCopyReadBuffer,
mBoundCopyWriteBuffer,
mBoundPixelPackBuffer,
mBoundPixelUnpackBuffer,
- mBoundTransformFeedbackBuffer,
+ mBoundTransformFeedback,
mBoundUniformBuffer,
mCurrentProgram,
mBoundDrawFramebuffer,
mBoundReadFramebuffer,
mBoundRenderbuffer,
mBoundVertexArray,
mDefaultVertexArray,
mActiveOcclusionQuery,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -119,16 +119,17 @@ class SourceSurface;
class VRLayerChild;
} // namespace gfx
namespace webgl {
struct LinkedProgramInfo;
class ShaderValidator;
class TexUnpackBlob;
struct UniformInfo;
+struct UniformBlockInfo;
} // namespace webgl
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
struct WebGLContextOptions
{
@@ -176,37 +177,53 @@ class WebGLIntOrFloat {
public:
explicit WebGLIntOrFloat(GLint i) : mType(Int) { mValue.i = i; }
explicit WebGLIntOrFloat(GLfloat f) : mType(Float) { mValue.f = f; }
GLint AsInt() const { return (mType == Int) ? mValue.i : NS_lroundf(mValue.f); }
GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
};
+struct IndexedBufferBinding
+{
+ WebGLRefPtr<WebGLBuffer> mBufferBinding;
+ uint64_t mRangeStart;
+ uint64_t mRangeSize;
+
+ IndexedBufferBinding();
+
+ uint64_t ByteCount() const;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
class WebGLContext
: public nsIDOMWebGLRenderingContext
, public nsICanvasRenderingContextInternal
, public nsSupportsWeakReference
, public WebGLContextUnchecked
, public WebGLRectangleObject
, public nsWrapperCache
{
+ friend class ScopedDrawHelper;
+ friend class ScopedDrawWithTransformFeedback;
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureATC;
friend class WebGLExtensionCompressedTextureES3;
friend class WebGLExtensionCompressedTextureETC1;
friend class WebGLExtensionCompressedTexturePVRTC;
friend class WebGLExtensionCompressedTextureS3TC;
friend class WebGLExtensionDepthTexture;
friend class WebGLExtensionDisjointTimerQuery;
friend class WebGLExtensionDrawBuffers;
friend class WebGLExtensionLoseContext;
friend class WebGLExtensionVertexArray;
friend class WebGLMemoryTracker;
+ friend struct webgl::UniformBlockInfo;
enum {
UNPACK_FLIP_Y_WEBGL = 0x9240,
UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
CONTEXT_LOST_WEBGL = 0x9242,
UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
BROWSER_DEFAULT_WEBGL = 0x9244,
UNMASKED_VENDOR_WEBGL = 0x9245,
@@ -720,21 +737,16 @@ public:
// -----------------------------------------------------------------------------
// WEBGL_lose_context
public:
void LoseContext();
void RestoreContext();
// -----------------------------------------------------------------------------
// Buffer Objects (WebGLContextBuffers.cpp)
-private:
- void UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer);
- void UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer);
-
-public:
void BindBuffer(GLenum target, WebGLBuffer* buffer);
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buf);
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
WebGLintptr offset, WebGLsizeiptr size);
private:
template<typename BufferT>
void BufferDataT(GLenum target, const BufferT& data, GLenum usage);
@@ -766,21 +778,19 @@ public:
protected:
// bound buffer state
WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
WebGLRefPtr<WebGLBuffer> mBoundCopyReadBuffer;
WebGLRefPtr<WebGLBuffer> mBoundCopyWriteBuffer;
WebGLRefPtr<WebGLBuffer> mBoundPixelPackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundPixelUnpackBuffer;
- WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
WebGLRefPtr<WebGLBuffer> mBoundUniformBuffer;
- nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundUniformBuffers;
- nsTArray<WebGLRefPtr<WebGLBuffer>> mBoundTransformFeedbackBuffers;
+ std::vector<IndexedBufferBinding> mIndexedUniformBufferBindings;
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
GLuint index);
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
@@ -1038,21 +1048,21 @@ private:
// Cache the max number of vertices and instances that can be read from
// bound VBOs (result of ValidateBuffers).
bool mBufferFetchingIsVerified;
bool mBufferFetchingHasPerVertex;
uint32_t mMaxFetchedVertices;
uint32_t mMaxFetchedInstances;
bool mBufferFetch_IsAttrib0Active;
- bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
- const char* info);
- bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
- GLsizei primcount, const char* info,
- GLuint* out_upperBound);
+ bool DrawArrays_check(const char* funcName, GLenum mode, GLint first,
+ GLsizei vertCount, GLsizei instanceCount);
+ bool DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
+ GLenum type, WebGLintptr byteOffset,
+ GLsizei instanceCount);
bool DrawInstanced_check(const char* info);
void Draw_cleanup(const char* funcName);
void VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
void VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
const GLfloat* ptr);
void VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
@@ -1244,17 +1254,16 @@ protected:
// Validation functions (implemented in WebGLContextValidate.cpp)
bool InitAndValidateGL(FailureReason* const out_failReason);
bool ValidateBlendEquationEnum(GLenum cap, const char* info);
bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
const char* info);
- bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
bool ValidateTextureTargetEnum(GLenum target, const char* info);
bool ValidateComparisonEnum(GLenum target, const char* info);
bool ValidateStencilOpEnum(GLenum action, const char* info);
bool ValidateFaceEnum(GLenum face, const char* info);
bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
WebGLTexImageFunc func, WebGLTexDimensions dims);
bool ValidateDrawModeEnum(GLenum mode, const char* info);
@@ -1311,16 +1320,33 @@ protected:
bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
WebGLProgram* program,
const char* funcName);
bool ValidateCurFBForRead(const char* funcName,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
+ WebGLRefPtr<WebGLBuffer>* ValidateBufferSlot(const char* funcName, GLenum target);
+ WebGLBuffer* ValidateBufferSelection(const char* funcName, GLenum target);
+ IndexedBufferBinding* ValidateIndexedBufferSlot(const char* funcName, GLenum target,
+ GLuint index);
+
+ bool ValidateIndexedBufferBinding(const char* funcName, GLenum target, GLuint index,
+ WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
+ IndexedBufferBinding** const out_indexedBinding);
+
+ 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;
+ }
+
void Invalidate();
void DestroyResourcesAndContext();
void MakeContextCurrent() const;
// helpers
bool ConvertImage(size_t width, size_t height, size_t srcStride,
@@ -1356,30 +1382,19 @@ private:
bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
private:
// -------------------------------------------------------------------------
// Context customization points
virtual WebGLVertexArray* CreateVertexArrayImpl();
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, uint32_t* alignment, const char* info) = 0;
- virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
- virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
- virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info);
- virtual bool ValidateBufferUsageEnum(GLenum usage, const char* info) = 0;
virtual bool ValidateQueryTarget(GLenum usage, const char* info) = 0;
virtual bool ValidateUniformMatrixTranspose(bool transpose, const char* info) = 0;
-protected:
- /** Like glBufferData, but if the call may change the buffer size, checks
- * any GL error generated by this glBufferData call and returns it.
- */
- GLenum CheckedBufferData(GLenum target, GLsizeiptr size, const GLvoid* data,
- GLenum usage);
-
public:
void ForceLoseContext(bool simulateLoss = false);
protected:
void ForceRestoreContext();
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
@@ -1803,11 +1818,21 @@ Intersect(uint32_t srcSize, int32_t dstS
uint32_t* const out_intSize);
bool
ZeroTextureData(WebGLContext* webgl, const char* funcName, GLuint tex,
TexImageTarget target, uint32_t level,
const webgl::FormatUsageInfo* usage, uint32_t xOffset, uint32_t yOffset,
uint32_t zOffset, uint32_t width, uint32_t height, uint32_t depth);
+////
+
+void
+ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
+ const std::vector<IndexedBufferBinding>& field,
+ const char* name, uint32_t flags = 0);
+
+void
+ImplCycleCollectionUnlink(std::vector<IndexedBufferBinding>& field);
+
} // namespace mozilla
#endif
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -6,240 +6,407 @@
#include "WebGLContext.h"
#include "GLContext.h"
#include "WebGLBuffer.h"
#include "WebGLVertexArray.h"
namespace mozilla {
-void
-WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
+WebGLRefPtr<WebGLBuffer>*
+WebGLContext::ValidateBufferSlot(const char* funcName, GLenum target)
{
- WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
- bufferSlot = buffer;
+ WebGLRefPtr<WebGLBuffer>* slot = nullptr;
+
+ switch (target) {
+ case LOCAL_GL_ARRAY_BUFFER:
+ slot = &mBoundArrayBuffer;
+ break;
+
+ case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+ slot = &(mBoundVertexArray->mElementArrayBuffer);
+ break;
+ }
+
+ if (IsWebGL2()) {
+ switch (target) {
+ case LOCAL_GL_COPY_READ_BUFFER:
+ slot = &mBoundCopyReadBuffer;
+ break;
+
+ case LOCAL_GL_COPY_WRITE_BUFFER:
+ slot = &mBoundCopyWriteBuffer;
+ break;
+
+ case LOCAL_GL_PIXEL_PACK_BUFFER:
+ slot = &mBoundPixelPackBuffer;
+ break;
+
+ case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+ slot = &mBoundPixelUnpackBuffer;
+ break;
- if (!buffer)
- return;
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+ slot = &(mBoundTransformFeedback->mGenericBufferBinding);
+ break;
+
+ case LOCAL_GL_UNIFORM_BUFFER:
+ slot = &mBoundUniformBuffer;
+ break;
+ }
+ }
+
+ if (!slot) {
+ ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
+ return nullptr;
+ }
- buffer->BindTo(target);
+ return slot;
+}
+
+WebGLBuffer*
+WebGLContext::ValidateBufferSelection(const char* funcName, GLenum target)
+{
+ const auto& slot = ValidateBufferSlot(funcName, target);
+ if (!slot)
+ return nullptr;
+ const auto& buffer = *slot;
+
+ if (!buffer) {
+ ErrorInvalidOperation("%s: Buffer for `target` is null.", funcName);
+ return nullptr;
+ }
+
+ return buffer.get();
}
-void
-WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
+IndexedBufferBinding*
+WebGLContext::ValidateIndexedBufferSlot(const char* funcName, GLenum target, GLuint index)
+{
+ decltype(mIndexedUniformBufferBindings)* bindings;
+ const char* maxIndexEnum;
+ switch (target) {
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+ bindings = &(mBoundTransformFeedback->mIndexedBindings);
+ maxIndexEnum = "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS";
+ break;
+
+ case LOCAL_GL_UNIFORM_BUFFER:
+ bindings = &mIndexedUniformBufferBindings;
+ maxIndexEnum = "MAX_UNIFORM_BUFFER_BINDINGS";
+ break;
+
+ default:
+ ErrorInvalidEnum("%s: Bad `target`: 0x%04x", funcName, target);
+ return nullptr;
+ }
+
+ if (index >= bindings->size()) {
+ ErrorInvalidOperation("%s: `index` >= %s.", funcName, maxIndexEnum);
+ return nullptr;
+ }
+
+ return &(*bindings)[index];
+}
+
+////////////////////////////////////////
+
+static bool
+ValidateCanBindToTarget(WebGLContext* webgl, const char* funcName, GLenum target,
+ WebGLBuffer* buffer)
{
- UpdateBoundBuffer(target, buffer);
+ if (!buffer)
+ return true;
+
+ /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
+ *
+ * In the WebGL 2 API, buffers have their WebGL buffer type
+ * initially set to undefined. Calling bindBuffer, bindBufferRange
+ * or bindBufferBase with the target argument set to any buffer
+ * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
+ * then set the WebGL buffer type of the buffer being bound
+ * according to the table above.
+ *
+ * Any call to one of these functions which attempts to bind a
+ * WebGLBuffer that has the element array WebGL buffer type to a
+ * binding point that falls under other data, or bind a
+ * WebGLBuffer which has the other data WebGL buffer type to
+ * ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
+ * and the state of the binding point will remain untouched.
+ */
+
+ const auto& content = buffer->Content();
+ if (content == WebGLBuffer::Kind::Undefined)
+ return true;
- WebGLRefPtr<WebGLBuffer>& bufferIndexSlot =
- GetBufferSlotByTargetIndexed(target, index);
- bufferIndexSlot = buffer;
+ switch (target) {
+ case LOCAL_GL_COPY_READ_BUFFER:
+ case LOCAL_GL_COPY_WRITE_BUFFER:
+ return true;
+
+ case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+ if (content == WebGLBuffer::Kind::ElementArray)
+ return true;
+ break;
+
+ case LOCAL_GL_ARRAY_BUFFER:
+ case LOCAL_GL_PIXEL_PACK_BUFFER:
+ case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+ case LOCAL_GL_UNIFORM_BUFFER:
+ if (content == WebGLBuffer::Kind::OtherData)
+ return true;
+ break;
+
+ default:
+ MOZ_CRASH();
+ }
+
+ webgl->ErrorInvalidOperation("%s: buffer already contains %s data.", funcName,
+ content == WebGLBuffer::Kind::OtherData ? "other"
+ : "element");
+ return false;
}
void
WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
{
+ const char funcName[] = "bindBuffer";
if (IsContextLost())
return;
- if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
- return;
-
- // silently ignore a deleted buffer
- if (buffer && buffer->IsDeleted())
- return;
-
- if (!ValidateBufferTarget(target, "bindBuffer"))
- return;
-
- if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
- return;
-
- WebGLContextUnchecked::BindBuffer(target, buffer);
-
- UpdateBoundBuffer(target, buffer);
-}
-
-void
-WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
-{
- if (IsContextLost())
- return;
-
- if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
+ if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
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");
- break;
+ const auto& slot = ValidateBufferSlot(funcName, target);
+ if (!slot)
+ return;
+
+ if (!ValidateCanBindToTarget(this, funcName, target, buffer))
+ return;
+
+ gl->MakeCurrent();
+ gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
+
+ *slot = buffer;
+ if (buffer) {
+ buffer->SetContentAfterBind(target);
+ }
+}
+
+////////////////////////////////////////
- case LOCAL_GL_UNIFORM_BUFFER:
- if (index >= mGLMaxUniformBufferBindings)
- return ErrorInvalidValue("bindBufferBase: index should be less than "
- "MAX_UNIFORM_BUFFER_BINDINGS");
- break;
+bool
+WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target,
+ GLuint index,
+ WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
+ IndexedBufferBinding** const out_indexedBinding)
+{
+ *out_genericBinding = ValidateBufferSlot(funcName, target);
+ if (!*out_genericBinding)
+ return false;
- default:
- return ErrorInvalidEnumInfo("bindBufferBase: target", target);
+ *out_indexedBinding = ValidateIndexedBufferSlot(funcName, target, index);
+ if (!*out_indexedBinding)
+ return false;
+
+ if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
+ mBoundTransformFeedback->mIsActive)
+ {
+ ErrorInvalidOperation("%s: Cannot update indexed buffer bindings on active"
+ " transform feedback objects.",
+ funcName);
+ return false;
}
- if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
- return;
+ if (!ValidateCanBindToTarget(this, funcName, target, (*out_genericBinding)->get()))
+ return false;
- WebGLContextUnchecked::BindBufferBase(target, index, buffer);
-
- UpdateBoundBufferIndexed(target, index, buffer);
+ return true;
}
void
-WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
- WebGLintptr offset, WebGLsizeiptr size)
+WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
{
+ const char funcName[] = "bindBufferBase";
if (IsContextLost())
return;
- if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
+ if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
- // ValidateBufferTarget
+ WebGLRefPtr<WebGLBuffer>* genericBinding;
+ IndexedBufferBinding* indexedBinding;
+ if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
+ &indexedBinding))
+ {
+ return;
+ }
+
+ ////
+
+ gl->MakeCurrent();
+ gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
+
+ ////
+
+ *genericBinding = buffer;
+ indexedBinding->mBufferBinding = buffer;
+ indexedBinding->mRangeStart = 0;
+ indexedBinding->mRangeSize = 0;
+
+ if (buffer) {
+ buffer->SetContentAfterBind(target);
+ }
+}
+
+void
+WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
+ WebGLintptr offset, WebGLsizeiptr size)
+{
+ const char funcName[] = "bindBufferRange";
+ if (IsContextLost())
+ return;
+
+ if (!ValidateObjectAllowDeletedOrNull(funcName, buffer))
+ return;
+
+ // silently ignore a deleted buffer
+ if (buffer && buffer->IsDeleted())
+ return;
+
+ if (!ValidateNonNegative(funcName, "offset", offset) ||
+ !ValidateNonNegative(funcName, "size", size))
+ {
+ return;
+ }
+
+ WebGLRefPtr<WebGLBuffer>* genericBinding;
+ IndexedBufferBinding* indexedBinding;
+ if (!ValidateIndexedBufferBinding(funcName, target, index, &genericBinding,
+ &indexedBinding))
+ {
+ return;
+ }
+
+ gl->MakeCurrent();
+
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- if (index >= mGLMaxTransformFeedbackSeparateAttribs)
- return ErrorInvalidValue("bindBufferRange: index should be less than "
- "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
+ if (offset % 4 != 0 || size % 4 != 0) {
+ ErrorInvalidValue("%s: For %s, `offset` and `size` must be multiples of 4.",
+ funcName, "TRANSFORM_FEEDBACK_BUFFER");
+ return;
+ }
break;
case LOCAL_GL_UNIFORM_BUFFER:
- if (index >= mGLMaxUniformBufferBindings)
- return ErrorInvalidValue("bindBufferRange: index should be less than "
- "MAX_UNIFORM_BUFFER_BINDINGS");
+ {
+ GLuint offsetAlignment = 0;
+ gl->GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &offsetAlignment);
+ if (offset % offsetAlignment != 0) {
+ ErrorInvalidValue("%s: For %s, `offset` must be a multiple of %s.",
+ funcName, "UNIFORM_BUFFER",
+ "UNIFORM_BUFFER_OFFSET_ALIGNMENT");
+ return;
+ }
+ }
break;
-
- default:
- return ErrorInvalidEnumInfo("bindBufferRange: target", target);
}
- if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
- return;
+ ////
+
+#ifdef XP_MACOSX
+ if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined &&
+ gl->WorkAroundDriverBugs())
+ {
+ // BindBufferRange will fail if the buffer's contents is undefined.
+ // Bind so driver initializes the buffer.
+ gl->fBindBuffer(target, buffer->mGLName);
+ }
+#endif
+
+ gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
- WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size);
+ ////
+
+ *genericBinding = buffer;
+ indexedBinding->mBufferBinding = buffer;
+ indexedBinding->mRangeStart = offset;
+ indexedBinding->mRangeSize = size;
- UpdateBoundBufferIndexed(target, index, buffer);
+ if (buffer) {
+ buffer->SetContentAfterBind(target);
+ }
}
+////////////////////////////////////////
+
void
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
{
+ const char funcName[] = "bufferData";
if (IsContextLost())
return;
- if (!ValidateBufferTarget(target, "bufferData"))
- return;
-
- WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
-
- if (size < 0)
- return ErrorInvalidValue("bufferData: negative size");
-
- if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
+ if (!ValidateNonNegative(funcName, "size", size))
return;
// careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
if (!CheckedInt<GLsizeiptr>(size).isValid())
- return ErrorOutOfMemory("bufferData: bad size");
+ return ErrorOutOfMemory("%s: bad size", funcName);
- WebGLBuffer* boundBuffer = bufferSlot.get();
+ const auto& buffer = ValidateBufferSelection(funcName, target);
+ if (!buffer)
+ return;
- if (!boundBuffer)
- return ErrorInvalidOperation("bufferData: no buffer bound!");
+ ////
UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
if (!zeroBuffer)
- return ErrorOutOfMemory("bufferData: out of memory");
-
- MakeContextCurrent();
- InvalidateBufferFetching();
-
- GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);
+ return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
- if (error) {
- GenerateWarning("bufferData generated error %s", ErrorName(error));
- return;
- }
-
- boundBuffer->SetByteLength(size);
-
- if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
- boundBuffer->SetByteLength(0);
- return ErrorOutOfMemory("bufferData: out of memory");
- }
+ buffer->BufferData(target, size_t(size), zeroBuffer.get(), usage);
}
// BufferT may be one of
// const dom::ArrayBuffer&
// const dom::SharedArrayBuffer&
// const dom::ArrayBufferView&
template<typename BufferT>
void
WebGLContext::BufferDataT(GLenum target,
const BufferT& data,
GLenum usage)
{
+ const char funcName[] = "bufferData";
if (IsContextLost())
return;
- if (!ValidateBufferTarget(target, "bufferData"))
- return;
-
- const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
-
data.ComputeLengthAndData();
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
// is like intptr_t.
if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
return ErrorOutOfMemory("bufferData: bad size");
- if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
+ const auto& buffer = ValidateBufferSelection(funcName, target);
+ if (!buffer)
return;
- WebGLBuffer* boundBuffer = bufferSlot.get();
-
- if (!boundBuffer)
- return ErrorInvalidOperation("bufferData: no buffer bound!");
-
- MakeContextCurrent();
- InvalidateBufferFetching();
-
// Warning: Possibly shared memory. See bug 1225033.
- GLenum error = CheckedBufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
-
- if (error) {
- GenerateWarning("bufferData generated error %s", ErrorName(error));
- return;
- }
-
- boundBuffer->SetByteLength(data.LengthAllowShared());
-
- // Warning: Possibly shared memory. See bug 1225033.
- if (!boundBuffer->ElementArrayCacheBufferData(data.DataAllowShared(), data.LengthAllowShared())) {
- boundBuffer->SetByteLength(0);
- return ErrorOutOfMemory("bufferData: out of memory");
- }
+ buffer->BufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
}
void
WebGLContext::BufferData(GLenum target,
const dom::SharedArrayBuffer& data,
GLenum usage)
{
BufferDataT(target, data, usage);
@@ -259,67 +426,73 @@ WebGLContext::BufferData(GLenum target,
void
WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
GLenum usage)
{
BufferDataT(target, data, usage);
}
+////////////////////////////////////////
+
// BufferT may be one of
// const dom::ArrayBuffer&
// const dom::SharedArrayBuffer&
// const dom::ArrayBufferView&
template<typename BufferT>
void
WebGLContext::BufferSubDataT(GLenum target,
WebGLsizeiptr byteOffset,
const BufferT& data)
{
+ const char funcName[] = "bufferSubData";
if (IsContextLost())
return;
- if (!ValidateBufferTarget(target, "bufferSubData"))
+ if (!ValidateNonNegative(funcName, "byteOffset", byteOffset))
+ return;
+
+ const auto& buffer = ValidateBufferSelection(funcName, target);
+ if (!buffer)
return;
- WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
-
- if (byteOffset < 0)
- return ErrorInvalidValue("bufferSubData: negative offset");
-
- WebGLBuffer* boundBuffer = bufferSlot.get();
- if (!boundBuffer)
- return ErrorInvalidOperation("bufferData: no buffer bound!");
+ if (buffer->mNumActiveTFOs) {
+ ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+ " object.",
+ "bufferSubData");
+ return;
+ }
data.ComputeLengthAndData();
- CheckedInt<WebGLsizeiptr> checked_neededByteLength =
- CheckedInt<WebGLsizeiptr>(byteOffset) + data.LengthAllowShared();
+ const auto checked_neededByteLength =
+ CheckedInt<size_t>(byteOffset) + data.LengthAllowShared();
if (!checked_neededByteLength.isValid()) {
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
" byte length.");
return;
}
- if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
+ if (checked_neededByteLength.value() > buffer->ByteLength()) {
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
" %d bytes, but buffer only has %d bytes.",
checked_neededByteLength.value(),
- boundBuffer->ByteLength());
+ buffer->ByteLength());
return;
}
- // Warning: Possibly shared memory. See bug 1225033.
- boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
- data.LengthAllowShared());
-
MakeContextCurrent();
// Warning: Possibly shared memory. See bug 1225033.
- gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared());
+ gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(),
+ data.DataAllowShared());
+
+ // Warning: Possibly shared memory. See bug 1225033.
+ buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
+ data.LengthAllowShared());
}
void
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
const dom::Nullable<dom::ArrayBuffer>& maybeData)
{
if (maybeData.IsNull()) {
ErrorInvalidValue("BufferSubData: returnedData is null.");
@@ -337,16 +510,18 @@ WebGLContext::BufferSubData(GLenum targe
void
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
const dom::ArrayBufferView& data)
{
BufferSubDataT(target, byteOffset, data);
}
+////////////////////////////////////////
+
already_AddRefed<WebGLBuffer>
WebGLContext::CreateBuffer()
{
if (IsContextLost())
return nullptr;
GLuint buf = 0;
MakeContextCurrent();
@@ -363,70 +538,53 @@ WebGLContext::DeleteBuffer(WebGLBuffer*
return;
if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
return;
if (!buffer || buffer->IsDeleted())
return;
- // TODO: Extract this into a helper function?
- if (mBoundArrayBuffer == buffer) {
- WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
- mBoundArrayBuffer = nullptr;
- }
+ ////
- if (mBoundVertexArray->mElementArrayBuffer == buffer) {
- WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
- mBoundVertexArray->mElementArrayBuffer = nullptr;
- }
+ const auto fnClearIfBuffer = [&](WebGLRefPtr<WebGLBuffer>& bindPoint) {
+ if (bindPoint == buffer) {
+ bindPoint = nullptr;
+ }
+ };
+
+ fnClearIfBuffer(mBoundArrayBuffer);
+ fnClearIfBuffer(mBoundVertexArray->mElementArrayBuffer);
// WebGL binding points
if (IsWebGL2()) {
- if (mBoundCopyReadBuffer == buffer)
- mBoundCopyReadBuffer = nullptr;
-
- if (mBoundCopyWriteBuffer == buffer)
- mBoundCopyWriteBuffer = nullptr;
-
- if (mBoundPixelPackBuffer == buffer)
- mBoundPixelPackBuffer = nullptr;
-
- if (mBoundPixelUnpackBuffer == buffer)
- mBoundPixelUnpackBuffer = nullptr;
+ fnClearIfBuffer(mBoundCopyReadBuffer);
+ fnClearIfBuffer(mBoundCopyWriteBuffer);
+ fnClearIfBuffer(mBoundPixelPackBuffer);
+ fnClearIfBuffer(mBoundPixelUnpackBuffer);
+ fnClearIfBuffer(mBoundUniformBuffer);
+ fnClearIfBuffer(mBoundTransformFeedback->mGenericBufferBinding);
- if (mBoundTransformFeedbackBuffer == buffer)
- mBoundTransformFeedbackBuffer = nullptr;
-
- if (mBoundUniformBuffer == buffer)
- mBoundUniformBuffer = nullptr;
-
- const size_t xfBufferCount = mBoundTransformFeedbackBuffers.Length();
- for (size_t n = 0; n < xfBufferCount; n++) {
- if (mBoundTransformFeedbackBuffers[n] == buffer) {
- mBoundTransformFeedbackBuffers[n] = nullptr;
- }
+ for (auto& binding : mBoundTransformFeedback->mIndexedBindings) {
+ fnClearIfBuffer(binding.mBufferBinding);
}
- const size_t uniformBufferCount = mBoundUniformBuffers.Length();
- for (size_t n = 0; n < uniformBufferCount; n++) {
- if (mBoundUniformBuffers[n] == buffer) {
- mBoundUniformBuffers[n] = nullptr;
- }
+ for (auto& binding : mIndexedUniformBufferBindings) {
+ fnClearIfBuffer(binding.mBufferBinding);
}
}
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
- if (mBoundVertexArray->HasAttrib(i) &&
- mBoundVertexArray->mAttribs[i].buf == buffer)
- {
- mBoundVertexArray->mAttribs[i].buf = nullptr;
+ if (mBoundVertexArray->HasAttrib(i)) {
+ fnClearIfBuffer(mBoundVertexArray->mAttribs[i].buf);
}
}
+ ////
+
buffer->RequestDelete();
}
bool
WebGLContext::IsBuffer(WebGLBuffer* buffer)
{
if (IsContextLost())
return false;
@@ -436,167 +594,9 @@ WebGLContext::IsBuffer(WebGLBuffer* buff
if (buffer->IsDeleted())
return false;
MakeContextCurrent();
return gl->fIsBuffer(buffer->mGLName);
}
-bool
-WebGLContext::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
- const char* info)
-{
- if (!buffer)
- return true;
-
- /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
- *
- * In the WebGL 2 API, buffers have their WebGL buffer type
- * initially set to undefined. Calling bindBuffer, bindBufferRange
- * or bindBufferBase with the target argument set to any buffer
- * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
- * then set the WebGL buffer type of the buffer being bound
- * according to the table above.
- *
- * Any call to one of these functions which attempts to bind a
- * WebGLBuffer that has the element array WebGL buffer type to a
- * binding point that falls under other data, or bind a
- * WebGLBuffer which has the other data WebGL buffer type to
- * ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
- * and the state of the binding point will remain untouched.
- */
-
- WebGLBuffer::Kind content = buffer->Content();
- if (content == WebGLBuffer::Kind::Undefined)
- return true;
-
- switch (target) {
- case LOCAL_GL_COPY_READ_BUFFER:
- case LOCAL_GL_COPY_WRITE_BUFFER:
- return true;
-
- case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
- if (content == WebGLBuffer::Kind::ElementArray)
- return true;
- break;
-
- case LOCAL_GL_ARRAY_BUFFER:
- case LOCAL_GL_PIXEL_PACK_BUFFER:
- case LOCAL_GL_PIXEL_UNPACK_BUFFER:
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- case LOCAL_GL_UNIFORM_BUFFER:
- if (content == WebGLBuffer::Kind::OtherData)
- return true;
- break;
-
- default:
- MOZ_CRASH();
- }
-
- ErrorInvalidOperation("%s: buffer already contains %s data.", info,
- content == WebGLBuffer::Kind::OtherData ? "other" : "element");
-
- return false;
-}
-
-bool
-WebGLContext::ValidateBufferUsageEnum(GLenum target, const char* info)
-{
- switch (target) {
- case LOCAL_GL_STREAM_DRAW:
- case LOCAL_GL_STATIC_DRAW:
- case LOCAL_GL_DYNAMIC_DRAW:
- return true;
- default:
- break;
- }
-
- ErrorInvalidEnumInfo(info, target);
- return false;
-}
-
-WebGLRefPtr<WebGLBuffer>&
-WebGLContext::GetBufferSlotByTarget(GLenum target)
-{
- /* This function assumes that target has been validated for either
- * WebGL1 or WebGL2.
- */
- switch (target) {
- case LOCAL_GL_ARRAY_BUFFER:
- return mBoundArrayBuffer;
-
- case LOCAL_GL_COPY_READ_BUFFER:
- return mBoundCopyReadBuffer;
-
- case LOCAL_GL_COPY_WRITE_BUFFER:
- return mBoundCopyWriteBuffer;
-
- case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
- return mBoundVertexArray->mElementArrayBuffer;
-
- case LOCAL_GL_PIXEL_PACK_BUFFER:
- return mBoundPixelPackBuffer;
-
- case LOCAL_GL_PIXEL_UNPACK_BUFFER:
- return mBoundPixelUnpackBuffer;
-
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
- return mBoundTransformFeedbackBuffer;
-
- case LOCAL_GL_UNIFORM_BUFFER:
- return mBoundUniformBuffer;
-
- default:
- MOZ_CRASH("GFX: Should not get here.");
- }
-}
-
-WebGLRefPtr<WebGLBuffer>&
-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:
- MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs);
- return mBoundTransformFeedbackBuffers[index];
-
- case LOCAL_GL_UNIFORM_BUFFER:
- MOZ_ASSERT(index < mGLMaxUniformBufferBindings);
- return mBoundUniformBuffers[index];
-
- default:
- MOZ_CRASH("GFX: Should not get here.");
- }
-}
-
-GLenum
-WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
- const GLvoid* data, GLenum usage)
-{
-#ifdef XP_MACOSX
- // bug 790879
- if (gl->WorkAroundDriverBugs() &&
- int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit
- {
- GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
- " a Mac bug", size);
- return LOCAL_GL_INVALID_VALUE;
- }
-#endif
-
- WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
- WebGLBuffer* boundBuffer = bufferSlot.get();
- MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");
-
- bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
- if (sizeChanges) {
- GetAndFlushUnderlyingGLErrors();
- gl->fBufferData(target, size, data, usage);
- GLenum error = GetAndFlushUnderlyingGLErrors();
- return error;
- } else {
- gl->fBufferData(target, size, data, usage);
- return LOCAL_GL_NO_ERROR;
- }
-}
-
} // namespace mozilla
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -236,170 +236,331 @@ WebGLContext::DrawInstanced_check(const
ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info);
return false;
}
return true;
}
bool
-WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
- const char* info)
+WebGLContext::DrawArrays_check(const char* funcName, GLenum mode, GLint first,
+ GLsizei vertCount, GLsizei instanceCount)
{
- if (first < 0 || count < 0) {
- ErrorInvalidValue("%s: negative first or count", info);
+ if (!ValidateDrawModeEnum(mode, funcName))
+ return false;
+
+ if (!ValidateNonNegative(funcName, "first", first) ||
+ !ValidateNonNegative(funcName, "vertCount", vertCount) ||
+ !ValidateNonNegative(funcName, "instanceCount", instanceCount))
+ {
return false;
}
- if (primcount < 0) {
- ErrorInvalidValue("%s: negative primcount", info);
+ if (!ValidateStencilParamsForDrawCall())
return false;
- }
-
- if (!ValidateStencilParamsForDrawCall()) {
- return false;
- }
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != 4) {
mPrimRestartTypeBytes = 4;
// OSX has issues leaving this as 0.
gl->fPrimitiveRestartIndex(UINT32_MAX);
}
}
- // If count is 0, there's nothing to do.
- if (count == 0 || primcount == 0) {
- return false;
- }
+ if (!vertCount || !instanceCount)
+ return false; // No error, just early out.
- if (!ValidateBufferFetching(info)) {
+ if (!ValidateBufferFetching(funcName))
return false;
- }
- CheckedInt<GLsizei> checked_firstPlusCount = CheckedInt<GLsizei>(first) + count;
-
+ const auto checked_firstPlusCount = CheckedInt<GLsizei>(first) + vertCount;
if (!checked_firstPlusCount.isValid()) {
- ErrorInvalidOperation("%s: overflow in first+count", info);
+ ErrorInvalidOperation("%s: overflow in first+vertCount", funcName);
return false;
}
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;
- }
-
- MOZ_ASSERT(gl->IsCurrent());
-
- if (mBoundDrawFramebuffer) {
- if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
- return false;
- } else {
- ClearBackbufferIfNeeded();
- }
-
- if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
+ ErrorInvalidOperation("%s: Bound vertex attribute buffers do not have sufficient"
+ " size for given first and count.",
+ funcName);
return false;
}
return true;
}
+////////////////////////////////////////
+
+class ScopedDrawHelper final
+{
+ WebGLContext* const mWebGL;
+ bool mDidFake;
+
+public:
+ ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
+ uint32_t vertCount, uint32_t instanceCount, bool* const out_error)
+ : mWebGL(webgl)
+ , mDidFake(false)
+ {
+ if (instanceCount > mWebGL->mMaxFetchedInstances) {
+ mWebGL->ErrorInvalidOperation("%s: Bound instance attribute buffers do not"
+ " have sufficient size for given"
+ " `instanceCount`.",
+ funcName);
+ *out_error = true;
+ return;
+ }
+
+ MOZ_ASSERT(mWebGL->gl->IsCurrent());
+
+ if (mWebGL->mBoundDrawFramebuffer) {
+ if (!mWebGL->mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName)) {
+ *out_error = true;
+ return;
+ }
+ } else {
+ mWebGL->ClearBackbufferIfNeeded();
+ }
+
+ ////
+
+ const size_t requiredVerts = firstVertex + vertCount;
+ if (!mWebGL->DoFakeVertexAttrib0(requiredVerts)) {
+ *out_error = true;
+ return;
+ }
+ mDidFake = true;
+
+ ////
+ // Check UBO sizes.
+
+ const auto& linkInfo = webgl->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;
+ }
+
+ 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;
+ }
+ }
+
+ ////
+
+ mWebGL->RunContextLossTimer();
+ }
+
+ ~ScopedDrawHelper() {
+ if (mDidFake) {
+ mWebGL->UndoFakeVertexAttrib0();
+ }
+ }
+};
+
+////////////////////////////////////////
+
+static uint32_t
+UsedVertsForTFDraw(GLenum mode, uint32_t vertCount)
+{
+ uint8_t vertsPerPrim;
+
+ switch (mode) {
+ case LOCAL_GL_POINTS:
+ vertsPerPrim = 1;
+ break;
+ case LOCAL_GL_LINES:
+ vertsPerPrim = 2;
+ break;
+ case LOCAL_GL_TRIANGLES:
+ vertsPerPrim = 3;
+ break;
+ default:
+ MOZ_CRASH("`mode`");
+ }
+
+ return vertCount / vertsPerPrim * vertsPerPrim;
+}
+
+class ScopedDrawWithTransformFeedback final
+{
+ WebGLContext* const mWebGL;
+ WebGLTransformFeedback* const mTFO;
+ const bool mWithTF;
+ uint32_t mUsedVerts;
+
+public:
+ ScopedDrawWithTransformFeedback(WebGLContext* webgl, const char* funcName,
+ GLenum mode, uint32_t vertCount,
+ uint32_t instanceCount, bool* const out_error)
+ : mWebGL(webgl)
+ , mTFO(mWebGL->mBoundTransformFeedback)
+ , mWithTF(mTFO &&
+ mTFO->mIsActive &&
+ !mTFO->mIsPaused)
+ , mUsedVerts(0)
+ {
+ *out_error = false;
+ if (!mWithTF)
+ return;
+
+ if (mode != mTFO->mActive_PrimMode) {
+ mWebGL->ErrorInvalidOperation("%s: Drawing with transform feedback requires"
+ " `mode` to match BeginTransformFeedback's"
+ " `primitiveMode`.",
+ funcName);
+ *out_error = true;
+ return;
+ }
+
+ const auto usedVertsPerInstance = UsedVertsForTFDraw(mode, vertCount);
+ const auto usedVerts = CheckedInt<uint32_t>(usedVertsPerInstance) * instanceCount;
+
+ const auto remainingCapacity = mTFO->mActive_VertCapacity - mTFO->mActive_VertPosition;
+ if (!usedVerts.isValid() ||
+ usedVerts.value() > remainingCapacity)
+ {
+ mWebGL->ErrorInvalidOperation("%s: Insufficient buffer capacity remaining for"
+ " transform feedback.",
+ funcName);
+ *out_error = true;
+ return;
+ }
+
+ mUsedVerts = usedVerts.value();
+ }
+
+ void Advance() const {
+ if (!mWithTF)
+ return;
+
+ mTFO->mActive_VertPosition += mUsedVerts;
+ }
+};
+
+////////////////////////////////////////
+
void
-WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
+WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei vertCount)
{
const char funcName[] = "drawArrays";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, funcName))
- return;
-
MakeContextCurrent();
- bool error;
+ bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
- if (!DrawArrays_check(first, count, 1, funcName))
+ const GLsizei instanceCount = 1;
+ if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
return;
- RunContextLossTimer();
+ const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
+ if (error)
+ return;
+
+ const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
+ instanceCount, &error);
+ if (error)
+ return;
{
ScopedMaskWorkaround autoMask(*this);
- gl->fDrawArrays(mode, first, count);
+ gl->fDrawArrays(mode, first, vertCount);
}
Draw_cleanup(funcName);
+ scopedTF.Advance();
}
void
-WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
+ GLsizei instanceCount)
{
const char funcName[] = "drawArraysInstanced";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, funcName))
- return;
-
MakeContextCurrent();
- bool error;
+ bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
- if (!DrawArrays_check(first, count, primcount, funcName))
+ if (!DrawArrays_check(funcName, mode, first, vertCount, instanceCount))
return;
if (!DrawInstanced_check(funcName))
return;
- RunContextLossTimer();
+ const ScopedDrawHelper scopedHelper(this, funcName, first, vertCount, instanceCount, &error);
+ if (error)
+ return;
+
+ const ScopedDrawWithTransformFeedback scopedTF(this, funcName, mode, vertCount,
+ instanceCount, &error);
+ if (error)
+ return;
{
ScopedMaskWorkaround autoMask(*this);
- gl->fDrawArraysInstanced(mode, first, count, primcount);
+ gl->fDrawArraysInstanced(mode, first, vertCount, instanceCount);
}
Draw_cleanup(funcName);
+ scopedTF.Advance();
}
+////////////////////////////////////////
+
bool
-WebGLContext::DrawElements_check(GLsizei count, GLenum type,
- WebGLintptr byteOffset, GLsizei primcount,
- const char* info, GLuint* out_upperBound)
+WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount,
+ GLenum type, WebGLintptr byteOffset,
+ GLsizei instanceCount)
{
- if (count < 0 || byteOffset < 0) {
- ErrorInvalidValue("%s: negative count or offset", info);
+ if (!ValidateDrawModeEnum(mode, funcName))
+ return false;
+
+ if (mBoundTransformFeedback &&
+ mBoundTransformFeedback->mIsActive &&
+ !mBoundTransformFeedback->mIsPaused)
+ {
+ ErrorInvalidOperation("%s: DrawElements* functions are incompatible with"
+ " transform feedback.",
+ funcName);
return false;
}
- if (primcount < 0) {
- ErrorInvalidValue("%s: negative primcount", info);
+ if (!ValidateNonNegative(funcName, "vertCount", vertCount) ||
+ !ValidateNonNegative(funcName, "byteOffset", byteOffset) ||
+ !ValidateNonNegative(funcName, "instanceCount", instanceCount))
+ {
return false;
}
- if (!ValidateStencilParamsForDrawCall()) {
+ if (!ValidateStencilParamsForDrawCall())
return false;
- }
- // If count is 0, there's nothing to do.
- if (count == 0 || primcount == 0)
- return false;
+ if (!vertCount || !instanceCount)
+ return false; // No error, just early out.
uint8_t bytesPerElem = 0;
switch (type) {
case LOCAL_GL_UNSIGNED_BYTE:
bytesPerElem = 1;
break;
case LOCAL_GL_UNSIGNED_SHORT:
@@ -409,23 +570,23 @@ WebGLContext::DrawElements_check(GLsizei
case LOCAL_GL_UNSIGNED_INT:
if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
bytesPerElem = 4;
}
break;
}
if (!bytesPerElem) {
- ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
+ ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type);
return false;
}
if (byteOffset % bytesPerElem != 0) {
ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
- info);
+ funcName);
return false;
}
////
if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) {
MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart));
if (mPrimRestartTypeBytes != bytesPerElem) {
@@ -434,168 +595,146 @@ WebGLContext::DrawElements_check(GLsizei
const uint32_t ones = UINT32_MAX >> (4 - mPrimRestartTypeBytes);
gl->fPrimitiveRestartIndex(ones);
}
}
////
const GLsizei first = byteOffset / bytesPerElem;
- const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);
+ const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(vertCount);
if (!checked_byteCount.isValid()) {
- ErrorInvalidValue("%s: overflow in byteCount", info);
+ ErrorInvalidValue("%s: Overflow in byteCount.", funcName);
return false;
}
if (!mBoundVertexArray->mElementArrayBuffer) {
- ErrorInvalidOperation("%s: must have element array buffer binding", info);
+ ErrorInvalidOperation("%s: Must have element array buffer binding.", funcName);
return false;
}
WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer;
if (!elemArrayBuffer.ByteLength()) {
- ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info);
+ ErrorInvalidOperation("%s: Bound element array buffer doesn't have any data.",
+ funcName);
return false;
}
CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset;
if (!checked_neededByteCount.isValid()) {
- ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info);
+ ErrorInvalidOperation("%s: Overflow in byteOffset+byteCount.", funcName);
return false;
}
if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) {
- ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info);
+ ErrorInvalidOperation("%s: Bound element array buffer is too small for given"
+ " count and offset.",
+ funcName);
return false;
}
- if (!ValidateBufferFetching(info))
+ if (!ValidateBufferFetching(funcName))
return false;
if (!mMaxFetchedVertices ||
- !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound))
+ !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, vertCount))
{
- ErrorInvalidOperation(
- "%s: bound vertex attribute buffers do not have sufficient "
- "size for given indices from the bound element array", info);
- return false;
- }
-
- if (uint32_t(primcount) > mMaxFetchedInstances) {
- ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info);
+ ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient "
+ "size for given indices from the bound element array",
+ funcName);
return false;
}
// Bug 1008310 - Check if buffer has been used with a different previous type
if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) {
GenerateWarning("%s: bound element array buffer previously used with a type other than "
"%s, this will affect performance.",
- info,
- WebGLContext::EnumName(type));
- }
-
- MOZ_ASSERT(gl->IsCurrent());
-
- if (mBoundDrawFramebuffer) {
- if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info))
- return false;
- } else {
- ClearBackbufferIfNeeded();
- }
-
- if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) {
- return false;
+ funcName, WebGLContext::EnumName(type));
}
return true;
}
void
-WebGLContext::DrawElements(GLenum mode, GLsizei count, GLenum type,
+WebGLContext::DrawElements(GLenum mode, GLsizei vertCount, GLenum type,
WebGLintptr byteOffset)
{
const char funcName[] = "drawElements";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, funcName))
- return;
-
MakeContextCurrent();
- bool error;
+ bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
- GLuint upperBound = 0;
- if (!DrawElements_check(count, type, byteOffset, 1, funcName, &upperBound))
+ const GLsizei instanceCount = 1;
+ if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
return;
- RunContextLossTimer();
+ const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
+ &error);
+ if (error)
+ return;
{
ScopedMaskWorkaround autoMask(*this);
-
- if (gl->IsSupported(gl::GLFeature::draw_range_elements)) {
- gl->fDrawRangeElements(mode, 0, upperBound, count, type,
- reinterpret_cast<GLvoid*>(byteOffset));
- } else {
- gl->fDrawElements(mode, count, type,
- reinterpret_cast<GLvoid*>(byteOffset));
- }
+ gl->fDrawElements(mode, vertCount, type,
+ reinterpret_cast<GLvoid*>(byteOffset));
}
Draw_cleanup(funcName);
}
void
-WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
- WebGLintptr byteOffset, GLsizei primcount)
+WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
+ WebGLintptr byteOffset, GLsizei instanceCount)
{
const char funcName[] = "drawElementsInstanced";
if (IsContextLost())
return;
- if (!ValidateDrawModeEnum(mode, funcName))
- return;
-
MakeContextCurrent();
- bool error;
+ bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
if (error)
return;
- GLuint upperBound = 0;
- if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
+ if (!DrawElements_check(funcName, mode, vertCount, type, byteOffset, instanceCount))
return;
if (!DrawInstanced_check(funcName))
return;
- RunContextLossTimer();
+ const ScopedDrawHelper scopedHelper(this, funcName, 0, mMaxFetchedVertices, instanceCount,
+ &error);
+ if (error)
+ return;
{
ScopedMaskWorkaround autoMask(*this);
- gl->fDrawElementsInstanced(mode, count, type,
+ gl->fDrawElementsInstanced(mode, vertCount, type,
reinterpret_cast<GLvoid*>(byteOffset),
- primcount);
+ instanceCount);
}
Draw_cleanup(funcName);
}
-void WebGLContext::Draw_cleanup(const char* funcName)
+////////////////////////////////////////
+
+void
+WebGLContext::Draw_cleanup(const char* funcName)
{
- UndoFakeVertexAttrib0();
-
if (!mBoundDrawFramebuffer) {
Invalidate();
mShouldPresent = true;
MOZ_ASSERT(!mBackbufferNeedsClear);
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLRenderer::Tegra) {
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -679,25 +679,20 @@ WebGLContext::GetAttribLocation(WebGLPro
}
JS::Value
WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
{
if (IsContextLost())
return JS::NullValue();
- if (!ValidateBufferTarget(target, "getBufferParameter"))
+ const auto& buffer = ValidateBufferSelection("getBufferParameter", target);
+ if (!buffer)
return JS::NullValue();
- WebGLRefPtr<WebGLBuffer>& slot = GetBufferSlotByTarget(target);
- if (!slot) {
- ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
- return JS::NullValue();
- }
-
MakeContextCurrent();
switch (pname) {
case LOCAL_GL_BUFFER_SIZE:
case LOCAL_GL_BUFFER_USAGE:
{
GLint i = 0;
gl->fGetBufferParameteriv(target, pname, &i);
@@ -1552,16 +1547,23 @@ WebGL2Context::ReadPixels(GLint x, GLint
if (!ReadPixels_SharedPrecheck(&out_error))
return;
if (!mBoundPixelPackBuffer) {
ErrorInvalidOperation("readPixels: PIXEL_PACK_BUFFER must not be null.");
return;
}
+ if (mBoundPixelPackBuffer->mNumActiveTFOs) {
+ ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+ " object.",
+ "readPixels");
+ return;
+ }
+
//////
if (offset < 0) {
ErrorInvalidValue("readPixels: offset must not be negative.");
return;
}
{
--- a/dom/canvas/WebGLContextUnchecked.cpp
+++ b/dom/canvas/WebGLContextUnchecked.cpp
@@ -2,70 +2,25 @@
/* vim: set ts=8 sts=4 et sw=4 tw=80: */
/* 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 "WebGLContextUnchecked.h"
#include "GLContext.h"
-#include "WebGLBuffer.h"
#include "WebGLSampler.h"
namespace mozilla {
WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* _gl)
: mGL_OnlyClearInDestroyResourcesAndContext(_gl)
, gl(mGL_OnlyClearInDestroyResourcesAndContext) // const reference
{ }
-
-// -----------------------------------------------------------------------------
-// Buffer Objects
-
-void
-WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer)
-{
- gl->MakeCurrent();
- gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
-}
-
-void
-WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
-{
- gl->MakeCurrent();
- gl->fBindBufferBase(target, index, buffer ? buffer->mGLName : 0);
-}
-
-void
-WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
-{
- gl->MakeCurrent();
-
-#ifdef XP_MACOSX
- if (buffer && buffer->Content() == WebGLBuffer::Kind::Undefined &&
- gl->WorkAroundDriverBugs())
- {
- // BindBufferRange will fail if the buffer's contents is undefined.
- // Bind so driver initializes the buffer.
- gl->fBindBuffer(target, buffer->mGLName);
- }
-#endif
-
- gl->fBindBufferRange(target, index, buffer ? buffer->mGLName : 0, offset, size);
-}
-
-void
-WebGLContextUnchecked::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
-{
- gl->MakeCurrent();
- gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
-}
-
-
// -----------------------------------------------------------------------------
// Sampler Objects
void
WebGLContextUnchecked::BindSampler(GLuint unit, WebGLSampler* sampler)
{
gl->MakeCurrent();
gl->fBindSampler(unit, sampler ? sampler->mGLName : 0);
--- a/dom/canvas/WebGLContextUnchecked.h
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -16,23 +16,16 @@ class WebGLBuffer;
class WebGLSampler;
class WebGLContextUnchecked
{
public:
explicit WebGLContextUnchecked(gl::GLContext* gl);
// -------------------------------------------------------------------------
- // Buffer Objects
- void BindBuffer(GLenum target, WebGLBuffer* buffer);
- void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
- void BindBufferRange(GLenum taret, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size);
- void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
-
- // -------------------------------------------------------------------------
// Sampler Objects
void BindSampler(GLuint unit, WebGLSampler* sampler);
GLint GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname);
GLfloat GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname);
void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -117,46 +117,21 @@ WebGLContext::ValidateBlendFuncEnumsComp
ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in"
" the WebGL 1.0 spec", info);
return false;
}
return true;
}
-bool
-WebGLContext::ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info)
-{
- if (offset < 0) {
- ErrorInvalidValue("%s: offset must be positive", info);
- return false;
- }
-
- if (size < 0) {
- ErrorInvalidValue("%s: size must be positive", info);
- return false;
- }
-
- // *** Careful *** WebGLsizeiptr is always 64-bits but GLsizeiptr
- // is like intptr_t. On some platforms it is 32-bits.
- CheckedInt<GLsizeiptr> neededBytes = CheckedInt<GLsizeiptr>(offset) + size;
- if (!neededBytes.isValid() || neededBytes.value() > bufferSize) {
- ErrorInvalidValue("%s: invalid range", info);
- return false;
- }
-
- return true;
-}
-
/**
* Check data ranges [readOffset, readOffset + size] and [writeOffset,
* writeOffset + size] for overlap.
*
- * It is assumed that offset and size have already been validated with
- * ValidateDataOffsetSize().
+ * It is assumed that offset and size have already been validated.
*/
bool
WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info)
{
MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset);
@@ -733,17 +708,16 @@ WebGLContext::InitAndValidateGL(FailureR
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
mBound2DArrayTextures.Clear();
mBoundSamplers.Clear();
mBoundArrayBuffer = nullptr;
- mBoundTransformFeedbackBuffer = nullptr;
mCurrentProgram = nullptr;
mBoundDrawFramebuffer = nullptr;
mBoundReadFramebuffer = nullptr;
mBoundRenderbuffer = nullptr;
MakeContextCurrent();
@@ -975,17 +949,16 @@ WebGLContext::InitAndValidateGL(FailureR
// regardless of version.
//
// GL Spec 4.0.0:
// (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
// in Section E.2.2 "Removed Features", pg 397: "[...] The default
// vertex array object (the name zero) is also deprecated. [...]"
if (gl->IsCoreProfile()) {
- MakeContextCurrent();
mDefaultVertexArray->GenVertexArray();
mDefaultVertexArray->BindVertexArray();
}
mPixelStore_FlipY = false;
mPixelStore_PremultiplyAlpha = false;
mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL;
--- a/dom/canvas/WebGLElementArrayCache.cpp
+++ b/dom/canvas/WebGLElementArrayCache.cpp
@@ -10,26 +10,16 @@
#include <cstring>
#include <limits>
#include "mozilla/Assertions.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
namespace mozilla {
-static void
-UpdateUpperBound(uint32_t* const out_upperBound, uint32_t newBound)
-{
- MOZ_ASSERT(out_upperBound);
- // Move *out_upperBound to a local variable to work around a false positive
- // -Wuninitialized gcc warning about std::max() in PGO builds.
- uint32_t upperBound = *out_upperBound;
- *out_upperBound = std::max(upperBound, newBound);
-}
-
/* WebGLElementArrayCacheTree contains most of the implementation of
* WebGLElementArrayCache, which performs WebGL element array buffer validation
* for drawElements.
*
* Attention: Here lie nontrivial data structures, bug-prone algorithms, and
* non-canonical tweaks! Whence the explanatory comments, and compiled unit
* test.
*
@@ -240,53 +230,49 @@ public:
return element & ~kElementsPerLeafMask;
}
static size_t NextMultipleOfElementsPerLeaf(size_t numElements) {
MOZ_ASSERT(numElements >= 1);
return ((numElements - 1) | kElementsPerLeafMask) + 1;
}
- bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf,
- uint32_t* const out_upperBound)
+ bool Validate(T maxAllowed, size_t firstLeaf, size_t lastLeaf)
{
size_t firstTreeIndex = TreeIndexForLeaf(firstLeaf);
size_t lastTreeIndex = TreeIndexForLeaf(lastLeaf);
while (true) {
// Given that we tweak these values in nontrivial ways, it doesn't
// hurt to do this sanity check.
MOZ_ASSERT(firstTreeIndex <= lastTreeIndex);
// Final case where there is only one node to validate at the
// current tree level:
if (lastTreeIndex == firstTreeIndex) {
const T& curData = mTreeData[firstTreeIndex];
- UpdateUpperBound(out_upperBound, curData);
return curData <= maxAllowed;
}
// If the first node at current tree level is a right node, handle
// it individually and replace it with its right neighbor, which is
// a left node.
if (IsRightNode(firstTreeIndex)) {
const T& curData = mTreeData[firstTreeIndex];
- UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowed)
return false;
firstTreeIndex = RightNeighborNode(firstTreeIndex);
}
// If the last node at current tree level is a left node, handle it
// individually and replace it with its left neighbor, which is a
// right node.
if (IsLeftNode(lastTreeIndex)) {
const T& curData = mTreeData[lastTreeIndex];
- UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowed)
return false;
lastTreeIndex = LeftNeighborNode(lastTreeIndex);
}
/* At this point it can happen that firstTreeIndex and lastTreeIndex
* "crossed" eachother. That happens if firstTreeIndex was a right
@@ -509,28 +495,23 @@ WebGLElementArrayCache::UpdateTrees(size
if (mUint32Tree)
result &= mUint32Tree->Update(firstByte, lastByte);
return result;
}
template<typename T>
bool
WebGLElementArrayCache::Validate(uint32_t maxAllowed, size_t firstElement,
- size_t countElements,
- uint32_t* const out_upperBound)
+ size_t countElements)
{
- *out_upperBound = 0;
-
// If maxAllowed is >= the max T value, then there is no way that a T index
// could be invalid.
uint32_t maxTSize = std::numeric_limits<T>::max();
- if (maxAllowed >= maxTSize) {
- UpdateUpperBound(out_upperBound, maxTSize);
+ if (maxAllowed >= maxTSize)
return true;
- }
T maxAllowedT(maxAllowed);
// Integer overflow must have been handled earlier, so we assert that
// maxAllowedT is exactly the max allowed value.
MOZ_ASSERT(uint32_t(maxAllowedT) == maxAllowed);
if (!mBytes.Length() || !countElements)
@@ -551,70 +532,62 @@ WebGLElementArrayCache::Validate(uint32_
}
}
size_t lastElement = firstElement + countElements - 1;
// Fast-exit path when the global maximum for the whole element array buffer
// falls in the allowed range:
T globalMax = tree->GlobalMaximum();
- if (globalMax <= maxAllowedT) {
- UpdateUpperBound(out_upperBound, globalMax);
+ if (globalMax <= maxAllowedT)
return true;
- }
const T* elements = Elements<T>();
// Before calling tree->Validate, we have to validate ourselves the
// boundaries of the elements span, to round them to the nearest multiple of
// kElementsPerLeaf.
size_t firstElementAdjustmentEnd = std::min(lastElement,
tree->LastElementUnderSameLeaf(firstElement));
while (firstElement <= firstElementAdjustmentEnd) {
const T& curData = elements[firstElement];
- UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowedT)
return false;
firstElement++;
}
size_t lastElementAdjustmentEnd = std::max(firstElement,
tree->FirstElementUnderSameLeaf(lastElement));
while (lastElement >= lastElementAdjustmentEnd) {
const T& curData = elements[lastElement];
- UpdateUpperBound(out_upperBound, curData);
if (curData > maxAllowedT)
return false;
lastElement--;
}
// at this point, for many tiny validations, we're already done.
if (firstElement > lastElement)
return true;
// general case
return tree->Validate(maxAllowedT, tree->LeafForElement(firstElement),
- tree->LeafForElement(lastElement), out_upperBound);
+ tree->LeafForElement(lastElement));
}
bool
WebGLElementArrayCache::Validate(GLenum type, uint32_t maxAllowed,
- size_t firstElement, size_t countElements,
- uint32_t* const out_upperBound)
+ size_t firstElement, size_t countElements)
{
if (type == LOCAL_GL_UNSIGNED_BYTE)
- return Validate<uint8_t>(maxAllowed, firstElement, countElements,
- out_upperBound);
+ return Validate<uint8_t>(maxAllowed, firstElement, countElements);
if (type == LOCAL_GL_UNSIGNED_SHORT)
- return Validate<uint16_t>(maxAllowed, firstElement, countElements,
- out_upperBound);
+ return Validate<uint16_t>(maxAllowed, firstElement, countElements);
if (type == LOCAL_GL_UNSIGNED_INT)
- return Validate<uint32_t>(maxAllowed, firstElement, countElements,
- out_upperBound);
+ return Validate<uint32_t>(maxAllowed, firstElement, countElements);
MOZ_ASSERT(false, "Invalid type.");
return false;
}
template<typename T>
static size_t
SizeOfNullable(mozilla::MallocSizeOf mallocSizeOf, const T& obj)
--- a/dom/canvas/WebGLElementArrayCache.h
+++ b/dom/canvas/WebGLElementArrayCache.h
@@ -32,18 +32,17 @@ struct WebGLElementArrayCacheTree;
* Most of the implementation is hidden in the auxilary class template,
* WebGLElementArrayCacheTree. Refer to its code for design comments.
*/
class WebGLElementArrayCache {
public:
bool BufferData(const void* ptr, size_t byteLength);
bool BufferSubData(size_t pos, const void* ptr, size_t updateByteSize);
- bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count,
- uint32_t* const out_upperBound);
+ bool Validate(GLenum type, uint32_t maxAllowed, size_t first, size_t count);
template<typename T>
T Element(size_t i) const { return Elements<T>()[i]; }
WebGLElementArrayCache();
~WebGLElementArrayCache();
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
@@ -69,18 +68,17 @@ private:
* Output parameter:
* out_upperBound: Upon success, is set to the actual maximum value in the
* specified range, which is then guaranteed to be less
* than or equal to maxAllowed. upon failure, is set to
* the first value in the specified range, that is greater
* than maxAllowed.
*/
template<typename T>
- bool Validate(uint32_t maxAllowed, size_t first, size_t count,
- uint32_t* const out_upperBound);
+ bool Validate(uint32_t maxAllowed, size_t first, size_t count);
template<typename T>
const T* Elements() const {
return reinterpret_cast<const T*>(mBytes.Elements());
}
template<typename T>
T* Elements() { return reinterpret_cast<T*>(mBytes.Elements()); }
--- a/dom/canvas/WebGLObjectModel.h
+++ b/dom/canvas/WebGLObjectModel.h
@@ -326,16 +326,16 @@ inline void
ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field)
{
field = nullptr;
}
template <typename T>
inline void
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
- mozilla::WebGLRefPtr<T>& field,
+ const mozilla::WebGLRefPtr<T>& field,
const char* name,
uint32_t flags = 0)
{
CycleCollectionNoteChild(callback, field.get(), name, flags);
}
#endif
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -9,16 +9,17 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/RefPtr.h"
#include "nsPrintfCString.h"
#include "WebGLActiveInfo.h"
#include "WebGLContext.h"
#include "WebGLShader.h"
+#include "WebGLTransformFeedback.h"
#include "WebGLUniformLocation.h"
#include "WebGLValidateStrings.h"
namespace mozilla {
/* If `name`: "foo[3]"
* Then returns true, with
* `out_baseName`: "foo"
@@ -322,25 +323,33 @@ QueryProgramInfo(WebGLProgram* prog, gl:
GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
mappedNameStr.c_str());
if (loc != LOCAL_GL_INVALID_INDEX)
isArray = true;
}
}
+ ////
+
+ GLuint dataSize = 0;
+ gl->fGetActiveUniformBlockiv(prog->mGLName, i,
+ LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
+ (GLint*)&dataSize);
+
#ifdef DUMP_SHADERVAR_MAPPINGS
printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
mappedName.BeginReading(), (int)isArray,
baseMappedName.BeginReading(), baseUserName.BeginReading());
printf_stderr(" lengthWithoutNull: %d\n", lengthWithoutNull);
printf_stderr(" isArray: %d\n", (int)isArray);
#endif
- const auto* block = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
+ auto* block = new webgl::UniformBlockInfo(webgl, baseUserName, baseMappedName,
+ dataSize);
info->uniformBlocks.push_back(block);
}
}
// Transform feedback varyings
if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
GLuint numTransformFeedbackVaryings = 0;
@@ -427,17 +436,18 @@ CreateProgram(gl::GLContext* gl)
{
gl->MakeCurrent();
return gl->fCreateProgram();
}
WebGLProgram::WebGLProgram(WebGLContext* webgl)
: WebGLContextBoundObject(webgl)
, mGLName(CreateProgram(webgl->GL()))
- , mTransformFeedbackBufferMode(LOCAL_GL_NONE)
+ , mNumActiveTFOs(0)
+ , mNextLink_TransformFeedbackBufferMode(LOCAL_GL_SEPARATE_ATTRIBS)
{
mContext->mPrograms.insertBack(this);
}
WebGLProgram::~WebGLProgram()
{
DeleteOnce();
}
@@ -508,17 +518,17 @@ WebGLProgram::BindAttribLocation(GLuint
if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the location of a"
" name that starts with 'gl_'.");
return;
}
NS_LossyConvertUTF16toASCII asciiName(name);
- auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
+ auto res = mNextLink_BoundAttribLocs.insert({asciiName, loc});
const bool wasInserted = res.second;
if (!wasInserted) {
auto itr = res.first;
itr->second = loc;
}
}
@@ -666,21 +676,23 @@ 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:
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
case LOCAL_GL_TRANSFORM_FEEDBACK_VARYINGS:
- return JS::Int32Value(mTransformFeedbackVaryings.size());
+ return JS::Int32Value(mNextLink_TransformFeedbackVaryings.size());
+
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
+ return JS::Int32Value(mNextLink_TransformFeedbackBufferMode);
}
}
switch (pname) {
case LOCAL_GL_ATTACHED_SHADERS:
case LOCAL_GL_ACTIVE_UNIFORMS:
case LOCAL_GL_ACTIVE_ATTRIBUTES:
return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
@@ -927,106 +939,143 @@ WebGLProgram::GetUniformIndices(const do
GLuint index = 0;
gl->fGetUniformIndices(mGLName, 1, &mappedNameBytes, &index);
arr.AppendElement(index);
}
}
void
-WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
+WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
+ GLuint uniformBlockBinding) const
{
+ const char funcName[] = "getActiveUniformBlockName";
if (!IsLinked()) {
- mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
+ mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
return;
}
- const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
- if (uniformBlockIndex >= linkInfo->uniformBlocks.size()) {
- mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
+ const auto& uniformBlocks = LinkInfo()->uniformBlocks;
+ if (uniformBlockIndex >= uniformBlocks.size()) {
+ mContext->ErrorInvalidValue("%s: Index %u invalid.", funcName, uniformBlockIndex);
return;
}
+ const auto& uniformBlock = uniformBlocks[uniformBlockIndex];
- if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
- mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
+ const auto& indexedBindings = mContext->mIndexedUniformBufferBindings;
+ if (uniformBlockBinding >= indexedBindings.size()) {
+ mContext->ErrorInvalidValue("%s: Binding %u invalid.", funcName,
+ uniformBlockBinding);
return;
}
+ const auto& indexedBinding = indexedBindings[uniformBlockBinding];
+
+ ////
gl::GLContext* gl = mContext->GL();
gl->MakeCurrent();
gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
+
+ ////
+
+ uniformBlock->mBinding = &indexedBinding;
}
-void
-WebGLProgram::LinkProgram()
+bool
+WebGLProgram::ValidateForLink()
{
- mContext->InvalidateBufferFetching(); // we do it early in this function
- // as some of the validation below changes program state
-
- mLinkLog.Truncate();
- mMostRecentLinkInfo = nullptr;
-
if (!mVertShader || !mVertShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
- mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
- return;
+ return false;
}
if (!mFragShader || !mFragShader->IsCompiled()) {
mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
- mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
- return;
+ return false;
}
- if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
- mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
- return;
- }
+ if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog))
+ return false;
- gl::GLContext* gl = mContext->gl;
- gl->MakeCurrent();
+ const auto& gl = mContext->gl;
if (gl->WorkAroundDriverBugs() &&
mContext->mIsMesa)
{
// Bug 777028: Mesa can't handle more than 16 samplers per program,
// counting each array entry.
size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
mFragShader->CalcNumSamplerUniforms();
if (numSamplerUniforms_upperBound > 16) {
mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
" Mesa drivers to avoid crashing.");
- mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
- return;
+ return false;
}
// Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
- mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count.");
- mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
- return;
+ mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max"
+ " attribute count.");
+ return false;
}
}
+ return true;
+}
+
+void
+WebGLProgram::LinkProgram()
+{
+ const char funcName[] = "linkProgram";
+
+ if (mNumActiveTFOs) {
+ mContext->ErrorInvalidOperation("%s: Program is in-use by one or more active"
+ " transform feedback objects.",
+ funcName);
+ return;
+ }
+
+ mContext->MakeContextCurrent();
+ mContext->InvalidateBufferFetching(); // we do it early in this function
+ // as some of the validation changes program state
+
+ mLinkLog.Truncate();
+ mMostRecentLinkInfo = nullptr;
+
+ if (!ValidateForLink()) {
+ mContext->GenerateWarning("%s: %s", funcName, mLinkLog.BeginReading());
+ return;
+ }
+
// Bind the attrib locations.
// This can't be done trivially, because we have to deal with mapped attrib names.
- for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
- const nsCString& name = itr->first;
- GLuint index = itr->second;
+ for (const auto& pair : mNextLink_BoundAttribLocs) {
+ const auto& name = pair.first;
+ const auto& index = pair.second;
mVertShader->BindAttribLocation(mGLName, name, index);
}
- if (!mTransformFeedbackVaryings.empty()) {
- // Bind the transform feedback varyings.
- // This can't be done trivially, because we have to deal with mapped names too.
- mVertShader->ApplyTransformFeedbackVaryings(mGLName,
- mTransformFeedbackVaryings,
- mTransformFeedbackBufferMode,
- &mTempMappedVaryings);
+ // Storage for transform feedback varyings before link.
+ // (Work around for bug seen on nVidia drivers.)
+ std::vector<std::string> scopedMappedTFVaryings;
+
+ if (mContext->IsWebGL2()) {
+ mVertShader->MapTransformFeedbackVaryings(mNextLink_TransformFeedbackVaryings,
+ &scopedMappedTFVaryings);
+
+ std::vector<const char*> driverVaryings;
+ driverVaryings.reserve(scopedMappedTFVaryings.size());
+ for (const auto& cur : scopedMappedTFVaryings) {
+ driverVaryings.push_back(cur.c_str());
+ }
+
+ mContext->gl->fTransformFeedbackVaryings(mGLName, driverVaryings.size(),
+ driverVaryings.data(),
+ mNextLink_TransformFeedbackBufferMode);
}
LinkAndUpdate();
if (mMostRecentLinkInfo) {
nsCString postLinkLog;
if (ValidateAfterTentativeLink(&postLinkLog))
return;
@@ -1071,20 +1120,73 @@ NumUsedLocationsByElemType(GLenum elemTy
case LOCAL_GL_FLOAT_MAT4:
return 4;
default:
return 1;
}
}
+static uint8_t
+NumComponents(GLenum elemType)
+{
+ switch (elemType) {
+ case LOCAL_GL_FLOAT:
+ case LOCAL_GL_INT:
+ case LOCAL_GL_UNSIGNED_INT:
+ case LOCAL_GL_BOOL:
+ return 1;
+
+ case LOCAL_GL_FLOAT_VEC2:
+ case LOCAL_GL_INT_VEC2:
+ case LOCAL_GL_UNSIGNED_INT_VEC2:
+ case LOCAL_GL_BOOL_VEC2:
+ return 2;
+
+ case LOCAL_GL_FLOAT_VEC3:
+ case LOCAL_GL_INT_VEC3:
+ case LOCAL_GL_UNSIGNED_INT_VEC3:
+ case LOCAL_GL_BOOL_VEC3:
+ return 3;
+
+ case LOCAL_GL_FLOAT_VEC4:
+ case LOCAL_GL_INT_VEC4:
+ case LOCAL_GL_UNSIGNED_INT_VEC4:
+ case LOCAL_GL_BOOL_VEC4:
+ case LOCAL_GL_FLOAT_MAT2:
+ return 4;
+
+ case LOCAL_GL_FLOAT_MAT2x3:
+ case LOCAL_GL_FLOAT_MAT3x2:
+ return 6;
+
+ case LOCAL_GL_FLOAT_MAT2x4:
+ case LOCAL_GL_FLOAT_MAT4x2:
+ return 8;
+
+ case LOCAL_GL_FLOAT_MAT3:
+ return 9;
+
+ case LOCAL_GL_FLOAT_MAT3x4:
+ case LOCAL_GL_FLOAT_MAT4x3:
+ return 12;
+
+ case LOCAL_GL_FLOAT_MAT4:
+ return 16;
+
+ default:
+ MOZ_CRASH("`elemType`");
+ }
+}
+
bool
WebGLProgram::ValidateAfterTentativeLink(nsCString* const out_linkLog) const
{
const auto& linkInfo = mMostRecentLinkInfo;
+ const auto& gl = mContext->gl;
// Check if the attrib name conflicting to uniform name
for (const auto& attrib : linkInfo->attribs) {
const auto& attribName = attrib.mActiveInfo->mBaseUserName;
for (const auto& uniform : linkInfo->uniforms) {
const auto& uniformName = uniform->mActiveInfo->mBaseUserName;
if (attribName == uniformName) {
@@ -1114,25 +1216,117 @@ WebGLProgram::ValidateAfterTentativeLink
" attrib \"%s\".",
aliasingName.BeginReading(),
existingName.BeginReading());
return false;
}
}
}
+ // Forbid:
+ // * Unrecognized varying name
+ // * Duplicate varying name
+ // * Too many components for specified buffer mode
+ if (mNextLink_TransformFeedbackVaryings.size()) {
+ GLuint maxComponentsPerIndex = 0;
+ switch (mNextLink_TransformFeedbackBufferMode) {
+ case LOCAL_GL_INTERLEAVED_ATTRIBS:
+ gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS,
+ &maxComponentsPerIndex);
+ break;
+
+ case LOCAL_GL_SEPARATE_ATTRIBS:
+ gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS,
+ &maxComponentsPerIndex);
+ break;
+
+ default:
+ MOZ_CRASH("`bufferMode`");
+ }
+
+ std::vector<size_t> componentsPerVert;
+ std::set<const WebGLActiveInfo*> alreadyUsed;
+ for (const auto& wideUserName : mNextLink_TransformFeedbackVaryings) {
+ if (!componentsPerVert.size() ||
+ mNextLink_TransformFeedbackBufferMode == LOCAL_GL_SEPARATE_ATTRIBS)
+ {
+ componentsPerVert.push_back(0);
+ }
+
+ ////
+
+ const WebGLActiveInfo* curInfo = nullptr;
+ for (const auto& info : linkInfo->transformFeedbackVaryings) {
+ const NS_ConvertASCIItoUTF16 info_wideUserName(info->mBaseUserName);
+ if (info_wideUserName == wideUserName) {
+ curInfo = info.get();
+ break;
+ }
+ }
+
+ if (!curInfo) {
+ const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
+ *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\" not"
+ " found.",
+ asciiUserName.BeginReading());
+ return false;
+ }
+
+ const auto insertResPair = alreadyUsed.insert(curInfo);
+ const auto& didInsert = insertResPair.second;
+ if (!didInsert) {
+ const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
+ *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
+ " specified twice.",
+ asciiUserName.BeginReading());
+ return false;
+ }
+
+ ////
+
+ size_t varyingComponents = NumComponents(curInfo->mElemType);
+ varyingComponents *= curInfo->mElemCount;
+
+ auto& totalComponentsForIndex = *(componentsPerVert.rbegin());
+ totalComponentsForIndex += varyingComponents;
+
+ if (totalComponentsForIndex > maxComponentsPerIndex) {
+ const NS_LossyConvertUTF16toASCII asciiUserName(wideUserName);
+ *out_linkLog = nsPrintfCString("Transform feedback varying \"%s\""
+ " pushed `componentsForIndex` over the"
+ " limit of %u.",
+ asciiUserName.BeginReading(),
+ maxComponentsPerIndex);
+ return false;
+ }
+ }
+
+ linkInfo->componentsPerTFVert.swap(componentsPerVert);
+ }
+
return true;
}
bool
WebGLProgram::UseProgram() const
{
+ const char funcName[] = "useProgram";
+
if (!mMostRecentLinkInfo) {
- mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
- " linked.");
+ mContext->ErrorInvalidOperation("%s: Program has not been successfully linked.",
+ funcName);
+ return false;
+ }
+
+ if (mContext->mBoundTransformFeedback &&
+ mContext->mBoundTransformFeedback->mIsActive &&
+ !mContext->mBoundTransformFeedback->mIsPaused)
+ {
+ mContext->ErrorInvalidOperation("%s: Transform feedback active and not paused.",
+ funcName);
return false;
}
mContext->MakeContextCurrent();
mContext->InvalidateBufferFetching();
mContext->gl->fUseProgram(mGLName);
@@ -1174,21 +1368,16 @@ WebGLProgram::LinkAndUpdate()
gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
if (logLenWithNull > 1) {
mLinkLog.SetLength(logLenWithNull - 1);
gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
} else {
mLinkLog.SetLength(0);
}
- // Post link, temporary mapped varying names for transform feedback can be discarded.
- // The memory can only be deleted after log is queried or the link status will fail.
- std::vector<std::string> empty;
- empty.swap(mTempMappedVaryings);
-
GLint ok = 0;
gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
if (!ok)
return;
mMostRecentLinkInfo = QueryProgramInfo(this, gl);
MOZ_RELEASE_ASSERT(mMostRecentLinkInfo, "GFX: most recent link info not set.");
}
@@ -1228,52 +1417,53 @@ WebGLProgram::FindUniformByMappedName(co
return false;
}
void
WebGLProgram::TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
GLenum bufferMode)
{
- if (bufferMode != LOCAL_GL_INTERLEAVED_ATTRIBS &&
- bufferMode != LOCAL_GL_SEPARATE_ATTRIBS)
- {
- mContext->ErrorInvalidEnum("transformFeedbackVaryings: `bufferMode` %s is "
- "invalid. Must be one of gl.INTERLEAVED_ATTRIBS or "
- "gl.SEPARATE_ATTRIBS.",
- mContext->EnumName(bufferMode));
+ const char funcName[] = "transformFeedbackVaryings";
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+
+ switch (bufferMode) {
+ case LOCAL_GL_INTERLEAVED_ATTRIBS:
+ break;
+
+ case LOCAL_GL_SEPARATE_ATTRIBS:
+ {
+ GLuint maxAttribs = 0;
+ gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
+ &maxAttribs);
+ if (varyings.Length() >= maxAttribs) {
+ mContext->ErrorInvalidValue("%s: Length of `varyings` exceeds %s.",
+ funcName,
+ "TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
+ return;
+ }
+ }
+ break;
+
+ default:
+ mContext->ErrorInvalidEnum("%s: Bad `bufferMode`: 0x%04x.", funcName, bufferMode);
return;
}
- size_t varyingsCount = varyings.Length();
- if (bufferMode == LOCAL_GL_SEPARATE_ATTRIBS &&
- varyingsCount >= mContext->mGLMaxTransformFeedbackSeparateAttribs)
- {
- mContext->ErrorInvalidValue("transformFeedbackVaryings: Number of `varyings` exc"
- "eeds gl.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS.");
- return;
- }
+ ////
- std::vector<nsCString> asciiVaryings;
- for (size_t i = 0; i < varyingsCount; i++) {
- if (!ValidateGLSLVariableName(varyings[i], mContext, "transformFeedbackVaryings"))
- return;
-
- NS_LossyConvertUTF16toASCII asciiName(varyings[i]);
- asciiVaryings.push_back(asciiName);
- }
-
- // All validated. Translate the strings and store them until
- // program linking.
- mTransformFeedbackBufferMode = bufferMode;
- mTransformFeedbackVaryings.swap(asciiVaryings);
+ mNextLink_TransformFeedbackVaryings.assign(varyings.Elements(),
+ varyings.Elements() + varyings.Length());
+ mNextLink_TransformFeedbackBufferMode = bufferMode;
}
already_AddRefed<WebGLActiveInfo>
-WebGLProgram::GetTransformFeedbackVarying(GLuint index)
+WebGLProgram::GetTransformFeedbackVarying(GLuint index) const
{
// No docs in the WebGL 2 spec for this function. Taking the language for
// getActiveAttrib, which states that the function returns null on any error.
if (!IsLinked()) {
mContext->ErrorInvalidOperation("getTransformFeedbackVarying: `program` must be "
"linked.");
return nullptr;
}
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -56,43 +56,52 @@ protected:
public:
explicit UniformInfo(WebGLActiveInfo* activeInfo);
};
struct UniformBlockInfo final
{
const nsCString mBaseUserName;
const nsCString mBaseMappedName;
+ const uint32_t mDataSize;
- UniformBlockInfo(const nsACString& baseUserName,
- const nsACString& baseMappedName)
+ const IndexedBufferBinding* mBinding;
+
+ UniformBlockInfo(WebGLContext* webgl, const nsACString& baseUserName,
+ const nsACString& baseMappedName, uint32_t dataSize)
: mBaseUserName(baseUserName)
, mBaseMappedName(baseMappedName)
- {}
+ , mDataSize(dataSize)
+ , mBinding(&webgl->mIndexedUniformBufferBindings[0])
+ { }
};
struct LinkedProgramInfo final
: public RefCounted<LinkedProgramInfo>
, public SupportsWeakPtr<LinkedProgramInfo>
{
+ friend class WebGLProgram;
+
MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(LinkedProgramInfo)
//////
WebGLProgram* const prog;
std::vector<AttribInfo> attribs;
std::vector<UniformInfo*> uniforms; // Owns its contents.
- std::vector<const UniformBlockInfo*> uniformBlocks; // Owns its contents.
+ std::vector<UniformBlockInfo*> uniformBlocks; // Owns its contents.
std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
// Needed for draw call validation.
std::vector<UniformInfo*> uniformSamplers;
+ mutable std::vector<size_t> componentsPerTFVert;
+
//////
// The maps for the frag data names to the translated names.
std::map<nsCString, const nsCString> fragDataMap;
explicit LinkedProgramInfo(WebGLProgram* prog);
~LinkedProgramInfo();
@@ -118,16 +127,18 @@ struct LinkedProgramInfo final
} // namespace webgl
class WebGLProgram final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLProgram>
, public LinkedListElement<WebGLProgram>
, public WebGLContextBoundObject
{
+ friend class WebGLTransformFeedback;
+
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
explicit WebGLProgram(WebGLContext* webgl);
void Delete();
@@ -169,17 +180,17 @@ public:
nsCString* const out_userName,
bool* const out_isArray) const;
bool FindUniformBlockByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
GLenum bufferMode);
- already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index);
+ already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index) const;
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
bool IsLinked() const { return mMostRecentLinkInfo; }
const webgl::LinkedProgramInfo* LinkInfo() const {
return mMostRecentLinkInfo.get();
}
@@ -189,29 +200,31 @@ public:
}
virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;
private:
~WebGLProgram();
void LinkAndUpdate();
+ bool ValidateForLink();
bool ValidateAfterTentativeLink(nsCString* const out_linkLog) const;
public:
const GLuint mGLName;
private:
WebGLRefPtr<WebGLShader> mVertShader;
WebGLRefPtr<WebGLShader> mFragShader;
- std::map<nsCString, GLuint> mBoundAttribLocs;
- std::vector<nsCString> mTransformFeedbackVaryings;
- GLenum mTransformFeedbackBufferMode;
+ size_t mNumActiveTFOs;
+
+ std::map<nsCString, GLuint> mNextLink_BoundAttribLocs;
+
+ std::vector<nsString> mNextLink_TransformFeedbackVaryings;
+ GLenum mNextLink_TransformFeedbackBufferMode;
+
nsCString mLinkLog;
RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
- // Storage for transform feedback varyings before link.
- // (Work around for bug seen on nVidia drivers.)
- std::vector<std::string> mTempMappedVaryings;
};
} // namespace mozilla
#endif // WEBGL_PROGRAM_H_
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -403,50 +403,34 @@ WebGLShader::EnumerateFragOutputs(std::m
if (!mValidator) {
return;
}
mValidator->EnumerateFragOutputs(out_FragOutputs);
}
void
-WebGLShader::ApplyTransformFeedbackVaryings(GLuint prog,
- const std::vector<nsCString>& varyings,
- GLenum bufferMode,
- std::vector<std::string>* out_mappedVaryings) const
+WebGLShader::MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
+ std::vector<std::string>* out_mappedVaryings) const
{
MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
- MOZ_ASSERT(!varyings.empty());
MOZ_ASSERT(out_mappedVaryings);
- const size_t varyingsCount = varyings.size();
- std::vector<std::string> mappedVaryings;
+ out_mappedVaryings->clear();
+ out_mappedVaryings->reserve(varyings.size());
- for (size_t i = 0; i < varyingsCount; i++) {
- const nsCString& userName = varyings[i];
- std::string userNameStr(userName.BeginReading());
-
- const std::string* mappedNameStr = &userNameStr;
- if (mValidator)
- mValidator->FindVaryingMappedNameByUserName(userNameStr, &mappedNameStr);
-
- mappedVaryings.push_back(*mappedNameStr);
+ for (const auto& wideUserName : varyings) {
+ const NS_LossyConvertUTF16toASCII mozUserName(wideUserName); // Don't validate here.
+ const std::string userName(mozUserName.BeginReading(), mozUserName.Length());
+ const std::string* pMappedName = &userName;
+ if (mValidator) {
+ mValidator->FindVaryingMappedNameByUserName(userName, &pMappedName);
+ }
+ out_mappedVaryings->push_back(*pMappedName);
}
-
- // Temporary, tight packed array of string pointers into mappedVaryings.
- std::vector<const GLchar*> strings;
- strings.resize(varyingsCount);
- for (size_t i = 0; i < varyingsCount; i++) {
- strings[i] = mappedVaryings[i].c_str();
- }
-
- mContext->MakeContextCurrent();
- mContext->gl->fTransformFeedbackVaryings(prog, varyingsCount, &strings[0], bufferMode);
-
- out_mappedVaryings->swap(mappedVaryings);
}
////////////////////////////////////////////////////////////////////////////////
// Boilerplate
JSObject*
WebGLShader::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
{
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -47,17 +47,16 @@ public:
void GetShaderSource(nsAString* out) const;
void GetShaderTranslatedSource(nsAString* out) const;
void ShaderSource(const nsAString& source);
// Util funcs
bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
size_t CalcNumSamplerUniforms() const;
size_t NumAttributes() const;
- void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
bool FindAttribUserNameByMappedName(const nsACString& mappedName,
nsDependentCString* const out_userName) const;
bool FindVaryingByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
bool FindUniformByMappedName(const nsACString& mappedName,
nsCString* const out_userName,
bool* const out_isArray) const;
@@ -66,21 +65,22 @@ public:
bool* const out_isArray) const;
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
bool IsCompiled() const {
return mTranslationSuccessful && mCompilationSuccessful;
}
- void ApplyTransformFeedbackVaryings(GLuint prog,
- const std::vector<nsCString>& varyings,
- GLenum bufferMode,
- std::vector<std::string>* out_mappedVaryings) const;
+private:
+ void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
+ void MapTransformFeedbackVaryings(const std::vector<nsString>& varyings,
+ std::vector<std::string>* out_mappedVaryings) const;
+public:
// Other funcs
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
void Delete();
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto) override;
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -59,14 +59,18 @@ public:
bool* const out_isArray) const;
bool FindUniformByMappedName(const std::string& mappedName,
std::string* const out_userName,
bool* const out_isArray) const;
bool FindUniformBlockByMappedName(const std::string& mappedName,
std::string* const out_userName) const;
void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
+
+ bool ValidateTransformFeedback(const std::vector<nsString>& userNames,
+ uint32_t maxComponents, nsCString* const out_errorText,
+ std::vector<std::string>* const out_mappedNames);
};
} // namespace webgl
} // namespace mozilla
#endif // WEBGL_SHADER_VALIDATOR_H_
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -14,16 +14,17 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Scoped.h"
#include "mozilla/Unused.h"
#include "ScopedGLHelpers.h"
#include "TexUnpackBlob.h"
+#include "WebGLBuffer.h"
#include "WebGLContext.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
#include "WebGLTexelConversions.h"
namespace mozilla {
/* This file handles:
@@ -208,16 +209,25 @@ WebGLContext::ValidateUnpackInfo(const c
GLenum type, webgl::PackingInfo* const out)
{
if (usePBOs != bool(mBoundPixelUnpackBuffer)) {
ErrorInvalidOperation("%s: PACK_BUFFER must be %s.", funcName,
(usePBOs ? "non-null" : "null"));
return false;
}
+ if (mBoundPixelUnpackBuffer &&
+ mBoundPixelUnpackBuffer->mNumActiveTFOs)
+ {
+ ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
+ " object.",
+ funcName);
+ return false;
+ }
+
if (!mFormatUsage->AreUnpackEnumsValid(format, type)) {
ErrorInvalidEnum("%s: Invalid unpack format/type: 0x%04x/0x%04x", funcName,
format, type);
return false;
}
out->format = format;
out->type = type;
@@ -310,17 +320,17 @@ WebGLTexture::TexOrSubImage(bool isSubIm
const bool isClientData = false;
const auto ptr = (const uint8_t*)offset;
webgl::TexUnpackBytes blob(mContext, target, width, height, depth, isClientData, ptr);
const auto& packBuffer = mContext->mBoundPixelUnpackBuffer;
const auto bufferByteCount = packBuffer->ByteLength();
uint32_t byteCount = 0;
- if (bufferByteCount >= offset) {
+ if (bufferByteCount >= uint64_t(offset)) {
byteCount = bufferByteCount - offset;
}
if (!ValidateUnpackBytes(mContext, funcName, width, height, depth, pi, byteCount,
&blob))
{
return;
}
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -6,53 +6,211 @@
#include "WebGLTransformFeedback.h"
#include "GLContext.h"
#include "mozilla/dom/WebGL2RenderingContextBinding.h"
#include "WebGL2Context.h"
namespace mozilla {
-WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl,
- GLuint tf)
+WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl, GLuint tf)
: WebGLContextBoundObject(webgl)
, mGLName(tf)
- , mMode(LOCAL_GL_NONE)
+ , mIndexedBindings(webgl->mGLMaxTransformFeedbackSeparateAttribs)
+ , mIsPaused(false)
, mIsActive(false)
- , mIsPaused(false)
{
mContext->mTransformFeedbacks.insertBack(this);
}
WebGLTransformFeedback::~WebGLTransformFeedback()
{
- mMode = LOCAL_GL_NONE;
- mIsActive = false;
- mIsPaused = false;
DeleteOnce();
}
void
WebGLTransformFeedback::Delete()
{
- mContext->MakeContextCurrent();
- mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
+ if (mGLName) {
+ mContext->MakeContextCurrent();
+ mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
+ }
removeFrom(mContext->mTransformFeedbacks);
}
-WebGLContext*
-WebGLTransformFeedback::GetParentObject() const
+////////////////////////////////////////
+
+void
+WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
{
- return mContext;
+ const char funcName[] = "beginTransformFeedback";
+
+ if (mIsActive)
+ return mContext->ErrorInvalidOperation("%s: Already active.", funcName);
+
+ switch (primMode) {
+ case LOCAL_GL_POINTS:
+ case LOCAL_GL_LINES:
+ case LOCAL_GL_TRIANGLES:
+ break;
+ default:
+ mContext->ErrorInvalidEnum("%s: `primitiveMode` must be one of POINTS, LINES, or"
+ " TRIANGLES.",
+ funcName);
+ return;
+ }
+
+ const auto& prog = mContext->mCurrentProgram;
+ if (!prog ||
+ !prog->IsLinked() ||
+ !prog->LinkInfo()->componentsPerTFVert.size())
+ {
+ mContext->ErrorInvalidOperation("%s: Current program not valid for transform"
+ " feedback.",
+ funcName);
+ return;
+ }
+
+ const auto& linkInfo = prog->LinkInfo();
+ const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
+
+ size_t minVertCapacity = SIZE_MAX;
+ for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
+ const auto& indexedBinding = mIndexedBindings[i];
+ const auto& componentsPerVert = componentsPerTFVert[i];
+
+ const auto& buffer = indexedBinding.mBufferBinding;
+ if (!buffer) {
+ mContext->ErrorInvalidOperation("%s: No buffer attached to required transform"
+ " feedback index %u.",
+ funcName, (uint32_t)i);
+ return;
+ }
+
+ const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
+ minVertCapacity = std::min(minVertCapacity, vertCapacity);
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ gl->fBeginTransformFeedback(primMode);
+
+ ////
+
+ mIsActive = true;
+ MOZ_ASSERT(!mIsPaused);
+
+ mActive_Program = prog;
+ mActive_PrimMode = primMode;
+ mActive_VertPosition = 0;
+ mActive_VertCapacity = minVertCapacity;
+
+ ////
+
+ for (const auto& cur : mIndexedBindings) {
+ const auto& buffer = cur.mBufferBinding;
+ if (buffer) {
+ buffer->mNumActiveTFOs++;
+ }
+ }
+
+ mActive_Program->mNumActiveTFOs++;
}
+
+void
+WebGLTransformFeedback::EndTransformFeedback()
+{
+ const char funcName[] = "endTransformFeedback";
+
+ if (!mIsActive)
+ return mContext->ErrorInvalidOperation("%s: Not active.", funcName);
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ gl->fEndTransformFeedback();
+
+ ////
+
+ mIsActive = false;
+ mIsPaused = false;
+
+ ////
+
+ for (const auto& cur : mIndexedBindings) {
+ const auto& buffer = cur.mBufferBinding;
+ if (buffer) {
+ buffer->mNumActiveTFOs--;
+ }
+ }
+
+ mActive_Program->mNumActiveTFOs--;
+}
+
+void
+WebGLTransformFeedback::PauseTransformFeedback()
+{
+ const char funcName[] = "pauseTransformFeedback";
+
+ if (!mIsActive ||
+ mIsPaused)
+ {
+ mContext->ErrorInvalidOperation("%s: Not active or is paused.", funcName);
+ return;
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ gl->fPauseTransformFeedback();
+
+ ////
+
+ mIsPaused = true;
+}
+
+void
+WebGLTransformFeedback::ResumeTransformFeedback()
+{
+ const char funcName[] = "resumeTransformFeedback";
+
+ if (!mIsPaused)
+ return mContext->ErrorInvalidOperation("%s: Not paused.", funcName);
+
+ if (mContext->mCurrentProgram != mActive_Program) {
+ mContext->ErrorInvalidOperation("%s: Active program differs from original.",
+ funcName);
+ return;
+ }
+
+ ////
+
+ const auto& gl = mContext->gl;
+ gl->MakeCurrent();
+ gl->fResumeTransformFeedback();
+
+ ////
+
+ MOZ_ASSERT(mIsActive);
+ mIsPaused = false;
+}
+
+////////////////////////////////////////
+
JSObject*
WebGLTransformFeedback::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
{
return dom::WebGLTransformFeedbackBinding::Wrap(cx, this, givenProto);
}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTransformFeedback)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTransformFeedback, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTransformFeedback, Release)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLTransformFeedback,
+ mGenericBufferBinding,
+ mIndexedBindings,
+ mActive_Program)
} // namespace mozilla
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -13,34 +13,50 @@
namespace mozilla {
class WebGLTransformFeedback final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLTransformFeedback>
, public LinkedListElement<WebGLTransformFeedback>
, public WebGLContextBoundObject
{
+ friend class ScopedDrawWithTransformFeedback;
friend class WebGLContext;
friend class WebGL2Context;
+ friend class WebGLProgram;
+
+public:
+ const GLuint mGLName;
+private:
+ // GLES 3.0.4 p267, Table 6.24 "Transform Feedback State"
+ WebGLRefPtr<WebGLBuffer> mGenericBufferBinding;
+ std::vector<IndexedBufferBinding> mIndexedBindings;
+ bool mIsPaused;
+ bool mIsActive;
+ // Not in state tables:
+ WebGLRefPtr<WebGLProgram> mActive_Program;
+ GLenum mActive_PrimMode;
+ size_t mActive_VertPosition;
+ size_t mActive_VertCapacity;
public:
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
+private:
+ ~WebGLTransformFeedback();
- void Delete();
- WebGLContext* GetParentObject() const;
- virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
-
- const GLuint mGLName;
-
+public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
-private:
- ~WebGLTransformFeedback();
+ void Delete();
+ WebGLContext* GetParentObject() const { return mContext; }
+ virtual JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
- GLenum mMode;
- bool mIsActive;
- bool mIsPaused;
+ // GL Funcs
+ void BeginTransformFeedback(GLenum primMode);
+ void EndTransformFeedback();
+ void PauseTransformFeedback();
+ void ResumeTransformFeedback();
};
} // namespace mozilla
#endif // WEBGL_TRANSFORM_FEEDBACK_H_
--- a/dom/canvas/WebGLVertexAttribData.h
+++ b/dom/canvas/WebGLVertexAttribData.h
@@ -36,36 +36,29 @@ struct WebGLVertexAttribData
GLenum type;
bool enabled;
bool normalized;
bool integer;
GLuint componentSize() const {
switch(type) {
case LOCAL_GL_BYTE:
- return sizeof(GLbyte);
-
case LOCAL_GL_UNSIGNED_BYTE:
- return sizeof(GLubyte);
+ return 1;
case LOCAL_GL_SHORT:
- return sizeof(GLshort);
-
case LOCAL_GL_UNSIGNED_SHORT:
- return sizeof(GLushort);
+ case LOCAL_GL_HALF_FLOAT:
+ case LOCAL_GL_HALF_FLOAT_OES:
+ return 2;
case LOCAL_GL_INT:
- return sizeof(GLint);
-
case LOCAL_GL_UNSIGNED_INT:
- return sizeof(GLuint);
-
- // case LOCAL_GL_FIXED:
case LOCAL_GL_FLOAT:
- return sizeof(GLfloat);
+ return 4;
default:
MOZ_ASSERT(false, "Should never get here!");
return 0;
}
}
GLuint actualStride() const {
--- a/dom/canvas/compiledtest/TestWebGLElementArrayCache.cpp
+++ b/dom/canvas/compiledtest/TestWebGLElementArrayCache.cpp
@@ -61,24 +61,18 @@ GLType()
return 0;
}
}
void
CheckValidate(bool expectSuccess, mozilla::WebGLElementArrayCache& c, GLenum type,
uint32_t maxAllowed, size_t first, size_t count)
{
- uint32_t out_upperBound = 0;
- const bool success = c.Validate(type, maxAllowed, first, count, &out_upperBound);
+ const bool success = c.Validate(type, maxAllowed, first, count);
VERIFY(success == expectSuccess);
- if (success) {
- VERIFY(out_upperBound <= maxAllowed);
- } else {
- VERIFY(out_upperBound > maxAllowed);
- }
}
template<typename T>
void
CheckValidateOneTypeVariousBounds(mozilla::WebGLElementArrayCache& c, size_t firstByte,
size_t countBytes)
{
size_t first = firstByte / sizeof(T);
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -66,17 +66,16 @@ UNIFIED_SOURCES += [
SOURCES += [
'ImageUtils.cpp',
]
# WebGL Sources
UNIFIED_SOURCES += [
'TexUnpackBlob.cpp',
'WebGL1Context.cpp',
- 'WebGL1ContextBuffers.cpp',
'WebGL1ContextUniforms.cpp',
'WebGL2Context.cpp',
'WebGL2ContextBuffers.cpp',
'WebGL2ContextDraw.cpp',
'WebGL2ContextFramebuffers.cpp',
'WebGL2ContextMRTs.cpp',
'WebGL2ContextPrograms.cpp',
'WebGL2ContextQueries.cpp',