--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -37,13 +37,14 @@ public:
// IMPLEMENT nsWrapperCache
virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
private:
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+ virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL1ContextBuffers.cpp
+++ b/dom/canvas/WebGL1ContextBuffers.cpp
@@ -27,8 +27,22 @@ WebGL1Context::ValidateBufferTarget(GLen
}
bool
WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
{
ErrorInvalidEnumInfo(info, target);
return false;
}
+
+/** Buffer and Target validation for BindBuffer */
+bool
+WebGL1Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info)
+{
+ if (!buffer)
+ return true;
+
+ bool matchingBinding = !buffer->HasEverBeenBound() || buffer->Target() == target;
+ if (!matchingBinding)
+ ErrorInvalidOperation("%s: buffer already bound to a different target", info);
+
+ return matchingBinding;
+}
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -73,14 +73,18 @@ WebGLContext::InitWebGL2()
{
GenerateWarning("WebGL 2 requires GLFeature::%s!", GLContext::GetFeatureName(feature));
return false;
}
}
// 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 = MakeUnique<WebGLBufferRefPtr[]>(mGLMaxTransformFeedbackSeparateAttribs);
+ mBoundUniformBuffers = MakeUnique<WebGLBufferRefPtr[]>(mGLMaxUniformBufferBindings);
mDefaultTransformFeedback = new WebGLTransformFeedback(this);
mBoundTransformFeedback = mDefaultTransformFeedback;
return true;
}
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -261,13 +261,14 @@ private:
bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
GLsizei width, GLsizei height, GLsizei depth,
const char* info);
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+ virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) MOZ_OVERRIDE;
};
} // namespace mozilla
#endif
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -8,18 +8,23 @@
using namespace mozilla;
using namespace mozilla::dom;
bool
WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
{
bool valid = (target == LOCAL_GL_ARRAY_BUFFER ||
+ target == LOCAL_GL_COPY_READ_BUFFER ||
+ target == LOCAL_GL_COPY_WRITE_BUFFER ||
target == LOCAL_GL_ELEMENT_ARRAY_BUFFER ||
- target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
+ target == LOCAL_GL_PIXEL_PACK_BUFFER ||
+ target == LOCAL_GL_PIXEL_UNPACK_BUFFER ||
+ target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER ||
+ target == LOCAL_GL_UNIFORM_BUFFER);
if (!valid)
ErrorInvalidEnumInfo(info, target);
return valid;
}
bool
@@ -28,25 +33,87 @@ WebGL2Context::ValidateBufferIndexedTarg
bool valid = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER ||
target == LOCAL_GL_UNIFORM_BUFFER);
if (!valid)
ErrorInvalidEnumInfo(info, target);
return valid;
}
+bool
+WebGL2Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info)
+{
+ if (!buffer)
+ return true;
+
+ switch (target) {
+ case LOCAL_GL_COPY_READ_BUFFER:
+ case LOCAL_GL_COPY_WRITE_BUFFER:
+ return true;
+
+ case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+ return !buffer->HasEverBeenBound() ||
+ buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER;
+
+ 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:
+ return !buffer->HasEverBeenBound() ||
+ buffer->Target() != LOCAL_GL_ELEMENT_ARRAY_BUFFER;
+ }
+
+ ErrorInvalidOperation("%s: buffer already bound to a incompatible target %s",
+ info, EnumName(buffer->Target().get()));
+ return false;
+}
+
// -------------------------------------------------------------------------
// Buffer objects
void
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
GLintptr writeOffset, GLsizeiptr size)
{
- MakeContextCurrent();
- gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+ if (IsContextLost())
+ return;
+
+ if (!ValidateBufferTarget(readTarget, "copyBufferSubData") ||
+ !ValidateBufferTarget(writeTarget, "copyBufferSubData"))
+ {
+ return;
+ }
+
+ WebGLBufferRefPtr* readBufferSlot = GetBufferSlotByTarget(readTarget);
+ WebGLBufferRefPtr* writeBufferSlot = GetBufferSlotByTarget(writeTarget);
+ if (!readBufferSlot || !writeBufferSlot)
+ return;
+
+ WebGLBuffer* readBuffer = readBufferSlot->get();
+ if (!readBuffer)
+ return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");
+
+ WebGLBuffer* writeBuffer = writeBufferSlot->get();
+ if (!writeBuffer)
+ return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");
+
+ if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(), "copyBufferSubData"))
+ return;
+
+ if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(), "copyBufferSubData"))
+ return;
+
+ if (readTarget == writeTarget &&
+ !ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData"))
+ {
+ return;
+ }
+
+ WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
}
void
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBuffer& returnedData)
{
MOZ_CRASH("Not Implemented.");
}
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -279,16 +279,17 @@ WebGLContext::WebGLContext()
mGLMaxTextureImageUnits = 0;
mGLMaxVertexTextureImageUnits = 0;
mGLMaxVaryingVectors = 0;
mGLMaxFragmentUniformVectors = 0;
mGLMaxVertexUniformVectors = 0;
mGLMaxColorAttachments = 1;
mGLMaxDrawBuffers = 1;
mGLMaxTransformFeedbackSeparateAttribs = 0;
+ mGLMaxUniformBufferBindings = 0;
// See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
mPixelStorePackAlignment = 4;
mPixelStoreUnpackAlignment = 4;
WebGLMemoryTracker::AddWebGLContext(this);
mAllowContextRestore = true;
@@ -344,29 +345,37 @@ WebGLContext::DestroyResourcesAndContext
return;
gl->MakeCurrent();
mBound2DTextures.Clear();
mBoundCubeMapTextures.Clear();
mBound3DTextures.Clear();
mBoundArrayBuffer = nullptr;
+ mBoundCopyReadBuffer = nullptr;
+ mBoundCopyWriteBuffer = nullptr;
+ mBoundPixelPackBuffer = nullptr;
+ mBoundPixelUnpackBuffer = nullptr;
mBoundTransformFeedbackBuffer = nullptr;
+ mBoundUniformBuffer = nullptr;
mCurrentProgram = nullptr;
mBoundFramebuffer = nullptr;
mActiveOcclusionQuery = nullptr;
mBoundRenderbuffer = nullptr;
mBoundVertexArray = nullptr;
mDefaultVertexArray = nullptr;
mBoundTransformFeedback = nullptr;
mDefaultTransformFeedback = nullptr;
for (GLuint i = 0; i < mGLMaxTransformFeedbackSeparateAttribs; i++)
mBoundTransformFeedbackBuffers[i] = nullptr;
+ for (GLuint i = 0; i < mGLMaxUniformBufferBindings; i++)
+ mBoundUniformBuffers[i] = nullptr;
+
while (!mTextures.isEmpty())
mTextures.getLast()->DeleteOnce();
while (!mVertexArrays.isEmpty())
mVertexArrays.getLast()->DeleteOnce();
while (!mBuffers.isEmpty())
mBuffers.getLast()->DeleteOnce();
while (!mRenderbuffers.isEmpty())
mRenderbuffers.getLast()->DeleteOnce();
@@ -1891,17 +1900,22 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLCo
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
mCanvasElement,
mExtensions,
mBound2DTextures,
mBoundCubeMapTextures,
mBound3DTextures,
mBoundArrayBuffer,
+ mBoundCopyReadBuffer,
+ mBoundCopyWriteBuffer,
+ mBoundPixelPackBuffer,
+ mBoundPixelUnpackBuffer,
mBoundTransformFeedbackBuffer,
+ mBoundUniformBuffer,
mCurrentProgram,
mBoundFramebuffer,
mBoundRenderbuffer,
mBoundVertexArray,
mDefaultVertexArray,
mActiveOcclusionQuery,
mActiveTransformFeedbackQuery)
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -94,16 +94,17 @@ template<typename> struct Nullable;
}
namespace gfx {
class SourceSurface;
}
typedef WebGLRefPtr<WebGLBuffer> WebGLBufferRefPtr;
typedef WebGLRefPtr<WebGLFramebuffer> WebGLFramebufferRefPtr;
+typedef WebGLRefPtr<WebGLProgram> WebGLProgramRefPtr;
typedef WebGLRefPtr<WebGLQuery> WebGLQueryRefPtr;
typedef WebGLRefPtr<WebGLRenderbuffer> WebGLRenderbufferRefPtr;
typedef WebGLRefPtr<WebGLTexture> WebGLTextureRefPtr;
typedef WebGLRefPtr<WebGLTransformFeedback> WebGLTransformFeedbackRefPtr;
typedef WebGLRefPtr<WebGLVertexArray> WebGLVertexArrayRefPtr;
WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
@@ -247,17 +248,17 @@ public:
const char *ErrorName(GLenum error);
/**
* Return displayable name for GLenum.
* This version is like gl::GLenumToStr but with out the GL_ prefix to
* keep consistency with how errors are reported from WebGL.
*/
- static const char *EnumName(GLenum glenum);
+ static const char* EnumName(GLenum glenum);
bool IsCompressedTextureFormat(GLenum format);
bool IsTextureFormatCompressed(TexInternalFormat format);
void DummyFramebufferOperation(const char *info);
WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const {
switch (texTarget.get()) {
@@ -827,41 +828,63 @@ 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* buf);
+ void BindBuffer(GLenum target, WebGLBuffer* buffer);
void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size);
+
+private:
+ void BufferDataUnchecked(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+ void BufferData(GLenum target, WebGLsizeiptr size, void* data, GLenum usage);
+
+public:
void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
void BufferData(GLenum target, const dom::ArrayBufferView &data,
GLenum usage);
void BufferData(GLenum target,
const Nullable<dom::ArrayBuffer> &maybeData,
GLenum usage);
+
+private:
+ void BufferSubDataUnchecked(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+ void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+
+public:
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
const dom::ArrayBufferView &data);
void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
const Nullable<dom::ArrayBuffer> &maybeData);
already_AddRefed<WebGLBuffer> CreateBuffer();
void DeleteBuffer(WebGLBuffer *buf);
bool IsBuffer(WebGLBuffer *buffer);
protected:
// bound buffer state
WebGLBufferRefPtr mBoundArrayBuffer;
+ WebGLBufferRefPtr mBoundCopyReadBuffer;
+ WebGLBufferRefPtr mBoundCopyWriteBuffer;
+ WebGLBufferRefPtr mBoundPixelPackBuffer;
+ WebGLBufferRefPtr mBoundPixelUnpackBuffer;
WebGLBufferRefPtr mBoundTransformFeedbackBuffer;
+ WebGLBufferRefPtr mBoundUniformBuffer;
UniquePtr<WebGLBufferRefPtr[]> mBoundTransformFeedbackBuffers;
+ UniquePtr<WebGLBufferRefPtr[]> mBoundUniformBuffers;
WebGLBufferRefPtr* GetBufferSlotByTarget(GLenum target);
WebGLBufferRefPtr* GetBufferSlotByTargetIndexed(GLenum target, GLuint index);
bool ValidateBufferUsageEnum(GLenum target, const char* infos);
// -----------------------------------------------------------------------------
// Queries (WebGL2ContextQueries.cpp)
protected:
@@ -962,25 +985,16 @@ public:
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;
-protected:
- inline void InvalidateBufferFetching()
- {
- mBufferFetchingIsVerified = false;
- mBufferFetchingHasPerVertex = false;
- mMaxFetchedVertices = 0;
- mMaxFetchedInstances = 0;
- }
-
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 DrawInstanced_check(const char* info);
void Draw_cleanup();
void VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength, const GLfloat* ptr);
@@ -1018,16 +1032,24 @@ protected:
virtual JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname);
// Returns x rounded to the next highest multiple of y.
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
return ((x + y - 1) / y) * y;
}
+ inline void InvalidateBufferFetching()
+ {
+ mBufferFetchingIsVerified = false;
+ mBufferFetchingHasPerVertex = false;
+ mMaxFetchedVertices = 0;
+ mMaxFetchedInstances = 0;
+ }
+
CheckedUint32 mGeneration;
WebGLContextOptions mOptions;
bool mInvalidated;
bool mResetLayer;
bool mOptionsFrozen;
bool mMinCapability;
@@ -1065,16 +1087,17 @@ protected:
int32_t mGLMaxTextureImageUnits;
int32_t mGLMaxVertexTextureImageUnits;
int32_t mGLMaxVaryingVectors;
int32_t mGLMaxFragmentUniformVectors;
int32_t mGLMaxVertexUniformVectors;
int32_t mGLMaxColorAttachments;
int32_t mGLMaxDrawBuffers;
GLuint mGLMaxTransformFeedbackSeparateAttribs;
+ GLuint mGLMaxUniformBufferBindings;
public:
GLuint MaxVertexAttribs() const {
return mGLMaxVertexAttribs;
}
protected:
// Represents current status of the context with respect to context loss.
@@ -1131,16 +1154,18 @@ protected:
// Validation functions (implemented in WebGLContextValidate.cpp)
bool CreateOffscreenGL(bool forceEnabled);
bool InitAndValidateGL();
bool ResizeBackbuffer(uint32_t width, uint32_t height);
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);
@@ -1298,16 +1323,17 @@ private:
bool ValidateObjectAssumeNonNull(const char* info, ObjectType *aObject);
private:
// -------------------------------------------------------------------------
// Context customization points
virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
+ virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) = 0;
protected:
int32_t MaxTextureSizeForTarget(TexTarget target) const {
return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
}
int32_t MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const {
const TexTarget target = TexImageTargetToTexTarget(texImageTarget);
@@ -1334,17 +1360,17 @@ protected:
void ForceLoseContext(bool simulateLosing = false);
void ForceRestoreContext();
nsTArray<WebGLTextureRefPtr> mBound2DTextures;
nsTArray<WebGLTextureRefPtr> mBoundCubeMapTextures;
nsTArray<WebGLTextureRefPtr> mBound3DTextures;
- WebGLRefPtr<WebGLProgram> mCurrentProgram;
+ WebGLProgramRefPtr mCurrentProgram;
uint32_t mMaxFramebufferColorAttachments;
WebGLFramebufferRefPtr mBoundFramebuffer;
WebGLRenderbufferRefPtr mBoundRenderbuffer;
WebGLTransformFeedbackRefPtr mBoundTransformFeedback;
WebGLVertexArrayRefPtr mBoundVertexArray;
@@ -1356,18 +1382,18 @@ protected:
LinkedList<WebGLRenderbuffer> mRenderbuffers;
LinkedList<WebGLFramebuffer> mFramebuffers;
LinkedList<WebGLVertexArray> mVertexArrays;
// TODO(djg): Does this need a rethink? Should it be WebGL2Context?
LinkedList<WebGLSampler> mSamplers;
LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
- WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
WebGLTransformFeedbackRefPtr mDefaultTransformFeedback;
+ WebGLVertexArrayRefPtr mDefaultVertexArray;
// PixelStore parameters
uint32_t mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
WebGLContextFakeBlackStatus mFakeBlackStatus;
class FakeBlackTexture
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -7,93 +7,103 @@
#include "GLContext.h"
#include "WebGLBuffer.h"
#include "WebGLVertexArray.h"
using namespace mozilla;
using namespace mozilla::dom;
void
-WebGLContext::BindBuffer(GLenum target, WebGLBuffer *buffer)
+WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
+{
+ WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+ if (!bufferSlot)
+ return;
+
+ *bufferSlot = buffer;
+
+ if (!buffer)
+ return;
+
+ /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1 */
+ if (target != LOCAL_GL_COPY_READ_BUFFER && target != LOCAL_GL_COPY_WRITE_BUFFER)
+ buffer->BindTo(target);
+}
+
+void
+WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
+{
+ UpdateBoundBuffer(target, buffer);
+
+ WebGLBufferRefPtr* bufferIndexSlot = GetBufferSlotByTargetIndexed(target, index);
+ *bufferIndexSlot = buffer;
+}
+
+void
+WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
{
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
return;
// silently ignore a deleted buffer
if (buffer && buffer->IsDeleted())
return;
if (!ValidateBufferTarget(target, "bindBuffer"))
return;
- WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
- MOZ_ASSERT(bufferSlot);
+ if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
+ return;
- if (buffer) {
- if (!buffer->HasEverBeenBound()) {
- buffer->BindTo(target);
- } else if (target != buffer->Target()) {
- return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
- }
- }
+ WebGLContextUnchecked::BindBuffer(target, buffer);
- *bufferSlot = buffer;
-
- MakeContextCurrent();
-
- gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+ UpdateBoundBuffer(target, buffer);
}
void
WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
{
if (IsContextLost())
return;
if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
return;
// silently ignore a deleted buffer
- if (buffer && buffer->IsDeleted()) {
+ 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");
+
+ case LOCAL_GL_UNIFORM_BUFFER:
+ if (index >= mGLMaxUniformBufferBindings)
+ return ErrorInvalidValue("bindBufferBase: index should be less than "
+ "MAX_UNIFORM_BUFFER_BINDINGS");
+
default:
return ErrorInvalidEnumInfo("bindBufferBase: target", target);
}
WebGLBufferRefPtr* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
MOZ_ASSERT(indexedBufferSlot);
- if (buffer) {
- if (!buffer->HasEverBeenBound())
- buffer->BindTo(target);
-
- if (target != buffer->Target())
- return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
- }
+ if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
+ return;
- WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
- MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
+ WebGLContextUnchecked::BindBufferBase(target, index, buffer);
- *indexedBufferSlot = buffer;
- *bufferSlot = buffer;
-
- MakeContextCurrent();
-
- gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
+ UpdateBoundBufferIndexed(target, index, buffer);
}
void
WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
WebGLintptr offset, WebGLsizeiptr size)
{
if (IsContextLost())
return;
@@ -107,47 +117,33 @@ WebGLContext::BindBufferRange(GLenum tar
// ValidateBufferTarget
switch (target) {
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
if (index >= mGLMaxTransformFeedbackSeparateAttribs)
return ErrorInvalidValue("bindBufferRange: index should be less than "
"MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
+ case LOCAL_GL_UNIFORM_BUFFER:
+ if (index >= mGLMaxUniformBufferBindings)
+ return ErrorInvalidValue("bindBufferRange: index should be less than "
+ "MAX_UNIFORM_BUFFER_BINDINGS");
default:
return ErrorInvalidEnumInfo("bindBufferRange: target", target);
}
WebGLBufferRefPtr* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
MOZ_ASSERT(indexedBufferSlot);
- if (buffer) {
- if (!buffer->HasEverBeenBound())
- buffer->BindTo(target);
-
- if (target != buffer->Target())
- return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
+ if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
+ return;
- CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + size;
- if (!checked_neededByteLength.isValid() ||
- checked_neededByteLength.value() > buffer->ByteLength())
- {
- return ErrorInvalidValue("bindBufferRange: invalid range");
- }
- }
+ WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size);
- WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
- MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
-
- *indexedBufferSlot = buffer;
- *bufferSlot = buffer;
-
- MakeContextCurrent();
-
- gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
+ UpdateBoundBufferIndexed(target, index, buffer);
}
void
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size,
GLenum usage)
{
if (IsContextLost())
return;
@@ -256,17 +252,16 @@ WebGLContext::BufferData(GLenum target,
WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
MOZ_ASSERT(bufferSlot);
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
return;
WebGLBuffer* boundBuffer = bufferSlot->get();
-
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
data.ComputeLengthAndData();
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
// is like intptr_t.
if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
@@ -304,17 +299,16 @@ WebGLContext::BufferSubData(GLenum targe
WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
MOZ_ASSERT(bufferSlot);
if (byteOffset < 0)
return ErrorInvalidValue("bufferSubData: negative offset");
WebGLBuffer* boundBuffer = bufferSlot->get();
-
if (!boundBuffer)
return ErrorInvalidOperation("bufferData: no buffer bound!");
const ArrayBuffer& data = maybeData.Value();
data.ComputeLengthAndData();
CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
if (!checked_neededByteLength.isValid())
@@ -343,17 +337,16 @@ WebGLContext::BufferSubData(GLenum targe
WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
MOZ_ASSERT(bufferSlot);
if (byteOffset < 0)
return ErrorInvalidValue("bufferSubData: negative offset");
WebGLBuffer* boundBuffer = bufferSlot->get();
-
if (!boundBuffer)
return ErrorInvalidOperation("bufferSubData: no buffer bound!");
data.ComputeLengthAndData();
CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
if (!checked_neededByteLength.isValid())
return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
@@ -435,32 +428,36 @@ WebGLContext::ValidateBufferUsageEnum(GL
return false;
}
WebGLBufferRefPtr*
WebGLContext::GetBufferSlotByTarget(GLenum target)
{
/* This function assumes that target has been validated for either WebGL1 or WebGL. */
switch (target) {
- case LOCAL_GL_ARRAY_BUFFER: return &mBoundArrayBuffer;
- case LOCAL_GL_ELEMENT_ARRAY_BUFFER: return &mBoundVertexArray->mElementArrayBuffer;
- case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: return &mBoundTransformFeedbackBuffer;
- default:
- return nullptr;
+ 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:
+ return nullptr;
}
}
WebGLBufferRefPtr*
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:
- return &mBoundTransformFeedbackBuffers[index];
-
+ case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: return &mBoundTransformFeedbackBuffers[index];
+ case LOCAL_GL_UNIFORM_BUFFER: return &mBoundUniformBuffers[index];
default:
return nullptr;
}
}
GLenum
WebGLContext::CheckedBufferData(GLenum target,
GLsizeiptr size,
@@ -471,22 +468,21 @@ WebGLContext::CheckedBufferData(GLenum t
// bug 790879
if (gl->WorkAroundDriverBugs() &&
int64_t(size) > INT32_MAX) // the 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
- WebGLBuffer *boundBuffer = nullptr;
- if (target == LOCAL_GL_ARRAY_BUFFER) {
- boundBuffer = mBoundArrayBuffer;
- } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
- boundBuffer = mBoundVertexArray->mElementArrayBuffer;
- }
+
+ WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+ MOZ_ASSERT(bufferSlot);
+
+ WebGLBuffer* boundBuffer = bufferSlot->get();
MOZ_ASSERT(boundBuffer != nullptr, "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;
--- a/dom/canvas/WebGLContextUnchecked.cpp
+++ b/dom/canvas/WebGLContextUnchecked.cpp
@@ -13,16 +13,48 @@
namespace mozilla {
WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* gl)
: gl(gl)
{ }
// -----------------------------------------------------------------------------
+// Buffer Objects
+
+void
+WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer)
+{
+ gl->MakeCurrent();
+ gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
+{
+ gl->MakeCurrent();
+ gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
+{
+ gl->MakeCurrent();
+ gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 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(WebGLSampler* sampler, GLuint unit)
{
gl->MakeCurrent();
gl->fBindSampler(unit, sampler ? sampler->GLName() : 0);
if (sampler)
--- a/dom/canvas/WebGLContextUnchecked.h
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -4,31 +4,37 @@
* 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 WEBGLCONTEXTUNCHECKED_H
#define WEBGLCONTEXTUNCHECKED_H
#include "GLDefs.h"
#include "WebGLTypes.h"
-#include "nsAutoPtr.h"
-#include "nsTArray.h"
namespace mozilla {
+class WebGLBuffer;
class WebGLSampler;
namespace gl { class GLContext; }
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(WebGLSampler* sampler, GLuint unit);
void GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname, GLint* param);
void GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname, GLfloat* param);
void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param);
void SamplerParameterf(WebGLSampler* sampler, GLenum pname, GLfloat param);
void SamplerParameterfv(WebGLSampler* sampler, GLenum pname, const GLfloat* param);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -207,16 +207,60 @@ bool WebGLContext::ValidateBlendFuncEnum
(dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
return false;
} else {
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().
+ */
+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);
+ if (!separate)
+ ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, writeOffset + size) overlap");
+
+ return separate;
+}
+
bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
{
switch (target) {
case LOCAL_GL_TEXTURE_2D:
case LOCAL_GL_TEXTURE_CUBE_MAP:
return true;
case LOCAL_GL_TEXTURE_3D: {
const bool isValid = IsWebGL2();
--- a/dom/canvas/WebGLVertexArrayFake.cpp
+++ b/dom/canvas/WebGLVertexArrayFake.cpp
@@ -16,17 +16,17 @@ WebGLVertexArrayFake::BindVertexArrayImp
// Go through and re-bind all buffers and setup all
// vertex attribute pointers
gl::GLContext* gl = mContext->gl;
WebGLRefPtr<WebGLVertexArray> prevVertexArray = mContext->mBoundVertexArray;
mContext->mBoundVertexArray = this;
- WebGLRefPtr<WebGLBuffer> prevBuffer = mContext->mBoundArrayBuffer;
+ WebGLBufferRefPtr prevBuffer = mContext->mBoundArrayBuffer;
mContext->BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, mElementArrayBuffer);
for (size_t i = 0; i < mAttribs.Length(); ++i) {
const WebGLVertexAttribData& vd = mAttribs[i];
mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, vd.buf);
if (vd.integer) {