2013-08-20 19:36:19 +04:00
|
|
|
/* -*- 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 "WebGLContext.h"
|
2014-11-14 07:03:50 +03:00
|
|
|
|
2013-09-04 16:14:52 +04:00
|
|
|
#include "GLContext.h"
|
2013-08-20 19:36:19 +04:00
|
|
|
#include "WebGLBuffer.h"
|
|
|
|
#include "WebGLVertexArray.h"
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
namespace mozilla {
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
void
|
|
|
|
WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
|
|
|
|
{
|
|
|
|
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
|
|
|
bufferSlot = buffer;
|
|
|
|
|
|
|
|
if (!buffer)
|
|
|
|
return;
|
|
|
|
|
2015-05-21 02:59:14 +03:00
|
|
|
buffer->BindTo(target);
|
2014-12-05 10:04:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
|
|
|
|
{
|
|
|
|
UpdateBoundBuffer(target, buffer);
|
|
|
|
|
|
|
|
WebGLRefPtr<WebGLBuffer>& bufferIndexSlot =
|
|
|
|
GetBufferSlotByTargetIndexed(target, index);
|
|
|
|
bufferIndexSlot = buffer;
|
|
|
|
}
|
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
void
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// silently ignore a deleted buffer
|
|
|
|
if (buffer && buffer->IsDeleted())
|
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
if (!ValidateBufferTarget(target, "bindBuffer"))
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
|
|
|
|
return;
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLContextUnchecked::BindBuffer(target, buffer);
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
UpdateBoundBuffer(target, buffer);
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
2013-08-20 19:36:20 +04:00
|
|
|
void
|
2013-09-04 16:14:43 +04:00
|
|
|
WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
|
2013-08-20 19:36:20 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// silently ignore a deleted buffer
|
2014-12-05 10:04:55 +03:00
|
|
|
if (buffer && buffer->IsDeleted())
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
// 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");
|
2015-04-21 04:02:34 +03:00
|
|
|
break;
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
case LOCAL_GL_UNIFORM_BUFFER:
|
|
|
|
if (index >= mGLMaxUniformBufferBindings)
|
|
|
|
return ErrorInvalidValue("bindBufferBase: index should be less than "
|
|
|
|
"MAX_UNIFORM_BUFFER_BINDINGS");
|
2015-04-21 04:02:34 +03:00
|
|
|
break;
|
2014-05-07 07:11:18 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
default:
|
|
|
|
return ErrorInvalidEnumInfo("bindBufferBase: target", target);
|
2013-08-20 19:36:20 +04:00
|
|
|
}
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
|
|
|
|
return;
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLContextUnchecked::BindBufferBase(target, index, buffer);
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
UpdateBoundBufferIndexed(target, index, buffer);
|
2013-08-20 19:36:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-09-04 16:14:43 +04:00
|
|
|
WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
|
2013-08-20 19:36:20 +04:00
|
|
|
WebGLintptr offset, WebGLsizeiptr size)
|
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// silently ignore a deleted buffer
|
|
|
|
if (buffer && buffer->IsDeleted())
|
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
// 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");
|
2015-04-21 04:02:34 +03:00
|
|
|
break;
|
2014-11-26 05:00:06 +03:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
case LOCAL_GL_UNIFORM_BUFFER:
|
|
|
|
if (index >= mGLMaxUniformBufferBindings)
|
|
|
|
return ErrorInvalidValue("bindBufferRange: index should be less than "
|
|
|
|
"MAX_UNIFORM_BUFFER_BINDINGS");
|
2015-04-21 04:02:34 +03:00
|
|
|
break;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
default:
|
|
|
|
return ErrorInvalidEnumInfo("bindBufferRange: target", target);
|
|
|
|
}
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
|
|
|
|
return;
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size);
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
UpdateBoundBufferIndexed(target, index, buffer);
|
2013-08-20 19:36:20 +04:00
|
|
|
}
|
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
void
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
if (!ValidateBufferTarget(target, "bufferData"))
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
2014-11-26 05:00:06 +03:00
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (size < 0)
|
|
|
|
return ErrorInvalidValue("bufferData: negative size");
|
|
|
|
|
|
|
|
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
|
|
|
return;
|
|
|
|
|
2013-09-04 16:14:39 +04:00
|
|
|
// careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
|
|
|
|
if (!CheckedInt<GLsizeiptr>(size).isValid())
|
|
|
|
return ErrorOutOfMemory("bufferData: bad size");
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLBuffer* boundBuffer = bufferSlot.get();
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!boundBuffer)
|
|
|
|
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
|
|
|
|
2015-02-19 07:51:06 +03:00
|
|
|
UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!zeroBuffer)
|
|
|
|
return ErrorOutOfMemory("bufferData: out of memory");
|
|
|
|
|
|
|
|
MakeContextCurrent();
|
|
|
|
InvalidateBufferFetching();
|
|
|
|
|
2014-10-16 07:11:30 +04:00
|
|
|
GLenum error = CheckedBufferData(target, size, zeroBuffer.get(), usage);
|
2013-08-20 19:36:19 +04:00
|
|
|
|
|
|
|
if (error) {
|
|
|
|
GenerateWarning("bufferData generated error %s", ErrorName(error));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
boundBuffer->SetByteLength(size);
|
2016-01-01 22:00:48 +03:00
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
|
2016-01-01 22:00:48 +03:00
|
|
|
boundBuffer->SetByteLength(0);
|
2013-08-20 19:36:19 +04:00
|
|
|
return ErrorOutOfMemory("bufferData: out of memory");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
// BufferT may be one of
|
|
|
|
// const dom::ArrayBuffer&
|
|
|
|
// const dom::SharedArrayBuffer&
|
|
|
|
// const dom::ArrayBufferView&
|
|
|
|
template<typename BufferT>
|
2013-08-20 19:36:19 +04:00
|
|
|
void
|
2015-10-14 08:48:19 +03:00
|
|
|
WebGLContext::BufferDataT(GLenum target,
|
|
|
|
const BufferT& data,
|
|
|
|
GLenum usage)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
if (!ValidateBufferTarget(target, "bufferData"))
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
2014-11-26 05:00:06 +03:00
|
|
|
|
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff
2014-05-28 01:32:41 +04:00
|
|
|
data.ComputeLengthAndData();
|
2013-08-20 19:36:20 +04:00
|
|
|
|
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff
2014-05-28 01:32:41 +04:00
|
|
|
// Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
|
|
|
|
// is like intptr_t.
|
2015-11-26 14:47:53 +03:00
|
|
|
if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
|
2013-09-04 16:14:39 +04:00
|
|
|
return ErrorOutOfMemory("bufferData: bad size");
|
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
|
|
|
|
return;
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLBuffer* boundBuffer = bufferSlot.get();
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!boundBuffer)
|
|
|
|
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
|
|
|
|
|
|
|
MakeContextCurrent();
|
|
|
|
InvalidateBufferFetching();
|
|
|
|
|
2015-11-26 14:47:53 +03:00
|
|
|
// Warning: Possibly shared memory. See bug 1225033.
|
|
|
|
GLenum error = CheckedBufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
|
2013-08-20 19:36:19 +04:00
|
|
|
|
|
|
|
if (error) {
|
|
|
|
GenerateWarning("bufferData generated error %s", ErrorName(error));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-26 14:47:53 +03:00
|
|
|
boundBuffer->SetByteLength(data.LengthAllowShared());
|
2016-01-01 22:00:48 +03:00
|
|
|
|
2015-11-26 14:47:53 +03:00
|
|
|
// Warning: Possibly shared memory. See bug 1225033.
|
2016-01-01 22:00:48 +03:00
|
|
|
if (!boundBuffer->ElementArrayCacheBufferData(data.DataAllowShared(), data.LengthAllowShared())) {
|
|
|
|
boundBuffer->SetByteLength(0);
|
2013-08-20 19:36:19 +04:00
|
|
|
return ErrorOutOfMemory("bufferData: out of memory");
|
2016-01-01 22:00:48 +03:00
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-10-14 08:48:19 +03:00
|
|
|
WebGLContext::BufferData(GLenum target,
|
|
|
|
const dom::SharedArrayBuffer& data,
|
2013-09-04 16:14:43 +04:00
|
|
|
GLenum usage)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2015-10-14 08:48:19 +03:00
|
|
|
BufferDataT(target, data, usage);
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
void
|
|
|
|
WebGLContext::BufferData(GLenum target,
|
|
|
|
const dom::Nullable<dom::ArrayBuffer>& maybeData,
|
|
|
|
GLenum usage)
|
|
|
|
{
|
|
|
|
if (maybeData.IsNull()) {
|
|
|
|
// see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
|
|
|
|
return ErrorInvalidValue("bufferData: null object passed");
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
2015-10-14 08:48:19 +03:00
|
|
|
BufferDataT(target, maybeData.Value(), usage);
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
void
|
|
|
|
WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
|
|
|
|
GLenum usage)
|
|
|
|
{
|
|
|
|
BufferDataT(target, data, usage);
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
2014-11-26 05:00:06 +03:00
|
|
|
if (!ValidateBufferTarget(target, "bufferSubData"))
|
2013-08-20 19:36:20 +04:00
|
|
|
return;
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
2014-11-26 05:00:06 +03:00
|
|
|
|
2013-08-20 19:36:19 +04:00
|
|
|
if (byteOffset < 0)
|
|
|
|
return ErrorInvalidValue("bufferSubData: negative offset");
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLBuffer* boundBuffer = bufferSlot.get();
|
2013-08-20 19:36:19 +04:00
|
|
|
if (!boundBuffer)
|
|
|
|
return ErrorInvalidOperation("bufferData: no buffer bound!");
|
|
|
|
|
Bug 999651, bug 995679, bug 1009952, bug 1011007, bug 991981. r=sfink, r=shu, r=jandem, r=jdm, r=luke, r=bbouvier, r=nmatsakis, r=bz, r=ehsan, r=jgilbert, r=smaug, r=sicking, r=terrence, r=bholley, r=bent, r=efaust, r=jorendorff
2014-05-28 01:32:41 +04:00
|
|
|
data.ComputeLengthAndData();
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
CheckedInt<WebGLsizeiptr> checked_neededByteLength =
|
2015-11-26 14:47:53 +03:00
|
|
|
CheckedInt<WebGLsizeiptr>(byteOffset) + data.LengthAllowShared();
|
2014-12-05 10:04:55 +03:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
if (!checked_neededByteLength.isValid()) {
|
|
|
|
ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
|
|
|
|
" byte length.");
|
|
|
|
return;
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
|
|
|
|
ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
|
|
|
|
" %d bytes, but buffer only has %d bytes.",
|
|
|
|
checked_neededByteLength.value(),
|
|
|
|
boundBuffer->ByteLength());
|
|
|
|
return;
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2015-11-26 14:47:53 +03:00
|
|
|
// Warning: Possibly shared memory. See bug 1225033.
|
|
|
|
boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
|
|
|
|
data.LengthAllowShared());
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
MakeContextCurrent();
|
2015-11-26 14:47:53 +03:00
|
|
|
// Warning: Possibly shared memory. See bug 1225033.
|
|
|
|
gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(), data.DataAllowShared());
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2013-09-04 16:14:43 +04:00
|
|
|
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
2015-10-14 08:48:19 +03:00
|
|
|
const dom::Nullable<dom::ArrayBuffer>& maybeData)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2015-10-14 08:48:19 +03:00
|
|
|
if (maybeData.IsNull()) {
|
|
|
|
// see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
|
2014-11-14 07:03:50 +03:00
|
|
|
return;
|
|
|
|
}
|
2015-10-14 08:48:19 +03:00
|
|
|
BufferSubDataT(target, byteOffset, maybeData.Value());
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
void
|
|
|
|
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
|
|
|
const dom::SharedArrayBuffer& data)
|
|
|
|
{
|
|
|
|
BufferSubDataT(target, byteOffset, data);
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2015-10-14 08:48:19 +03:00
|
|
|
void
|
|
|
|
WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
|
|
|
|
const dom::ArrayBufferView& data)
|
|
|
|
{
|
|
|
|
BufferSubDataT(target, byteOffset, data);
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
|
|
|
already_AddRefed<WebGLBuffer>
|
|
|
|
WebGLContext::CreateBuffer()
|
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return nullptr;
|
|
|
|
|
2014-11-17 05:21:04 +03:00
|
|
|
GLuint buf = 0;
|
|
|
|
MakeContextCurrent();
|
|
|
|
gl->fGenBuffers(1, &buf);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<WebGLBuffer> globj = new WebGLBuffer(this, buf);
|
2013-08-20 19:36:19 +04:00
|
|
|
return globj.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::DeleteBuffer(WebGLBuffer* buffer)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!buffer || buffer->IsDeleted())
|
|
|
|
return;
|
|
|
|
|
2015-06-02 04:08:55 +03:00
|
|
|
// TODO: Extract this into a helper function?
|
|
|
|
if (mBoundArrayBuffer == buffer) {
|
|
|
|
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ARRAY_BUFFER, nullptr);
|
|
|
|
mBoundArrayBuffer = nullptr;
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-06-06 03:38:27 +04:00
|
|
|
if (mBoundVertexArray->mElementArrayBuffer == buffer) {
|
2015-06-02 04:08:55 +03:00
|
|
|
WebGLContextUnchecked::BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nullptr);
|
|
|
|
mBoundVertexArray->mElementArrayBuffer = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const size_t uniformBufferCount = mBoundUniformBuffers.Length();
|
|
|
|
for (size_t n = 0; n < uniformBufferCount; n++) {
|
|
|
|
if (mBoundUniformBuffers[n] == buffer) {
|
|
|
|
mBoundUniformBuffers[n] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
|
2014-11-14 07:03:50 +03:00
|
|
|
if (mBoundVertexArray->HasAttrib(i) &&
|
|
|
|
mBoundVertexArray->mAttribs[i].buf == buffer)
|
|
|
|
{
|
2013-10-11 17:16:44 +04:00
|
|
|
mBoundVertexArray->mAttribs[i].buf = nullptr;
|
2014-11-14 07:03:50 +03:00
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer->RequestDelete();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::IsBuffer(WebGLBuffer* buffer)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-09-04 16:14:44 +04:00
|
|
|
if (IsContextLost())
|
2013-08-20 19:36:19 +04:00
|
|
|
return false;
|
|
|
|
|
2015-05-21 02:59:14 +03:00
|
|
|
if (!ValidateObjectAllowDeleted("isBuffer", buffer))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
GLenum boundTo = GetCurrentBinding(buffer);
|
|
|
|
if (boundTo != LOCAL_GL_NONE) {
|
|
|
|
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
|
|
|
boundTo != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
|
|
|
|
{
|
|
|
|
ErrorInvalidOperation("Can't bind buffer to TRANSFORM_FEEDBACK_BUFFER as the "
|
|
|
|
"buffer is already bound to another bind point.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (target != LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
|
|
|
boundTo == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER)
|
|
|
|
{
|
|
|
|
ErrorInvalidOperation("Can't bind buffer to bind point as it is currently "
|
|
|
|
"bound to TRANSFORM_FEEDBACK_BUFFER.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::ValidateBufferUsageEnum(GLenum target, const char* info)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2013-08-20 19:36:20 +04:00
|
|
|
switch (target) {
|
2014-11-14 07:03:50 +03:00
|
|
|
case LOCAL_GL_STREAM_DRAW:
|
|
|
|
case LOCAL_GL_STATIC_DRAW:
|
|
|
|
case LOCAL_GL_DYNAMIC_DRAW:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
break;
|
2013-08-20 19:36:20 +04:00
|
|
|
}
|
|
|
|
|
2014-11-14 07:03:50 +03:00
|
|
|
ErrorInvalidEnumInfo(info, target);
|
2013-08-20 19:36:20 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLRefPtr<WebGLBuffer>&
|
2014-11-26 05:00:06 +03:00
|
|
|
WebGLContext::GetBufferSlotByTarget(GLenum target)
|
2013-08-20 19:36:20 +04:00
|
|
|
{
|
2014-12-05 10:04:55 +03:00
|
|
|
/* This function assumes that target has been validated for either
|
|
|
|
* WebGL1 or WebGL2.
|
|
|
|
*/
|
2013-08-20 19:36:20 +04:00
|
|
|
switch (target) {
|
2014-12-05 10:04:55 +03:00
|
|
|
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;
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
case LOCAL_GL_PIXEL_UNPACK_BUFFER:
|
|
|
|
return mBoundPixelUnpackBuffer;
|
2013-08-20 19:36:20 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
|
|
|
return mBoundTransformFeedbackBuffer;
|
|
|
|
|
|
|
|
case LOCAL_GL_UNIFORM_BUFFER:
|
|
|
|
return mBoundUniformBuffer;
|
2014-11-14 07:03:50 +03:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
default:
|
|
|
|
MOZ_CRASH("Should not get here.");
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLRefPtr<WebGLBuffer>&
|
2014-11-26 05:00:06 +03:00
|
|
|
WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
|
2013-08-20 19:36:19 +04:00
|
|
|
{
|
2014-11-26 05:00:06 +03:00
|
|
|
/* This function assumes that target has been validated for either WebGL1 or WebGL. */
|
2013-08-20 19:36:19 +04:00
|
|
|
switch (target) {
|
2014-11-14 07:03:50 +03:00
|
|
|
case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
|
2014-11-26 05:00:06 +03:00
|
|
|
MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs);
|
2014-12-05 10:04:55 +03:00
|
|
|
return mBoundTransformFeedbackBuffers[index];
|
2015-04-21 04:02:34 +03:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
case LOCAL_GL_UNIFORM_BUFFER:
|
|
|
|
MOZ_ASSERT(index < mGLMaxUniformBufferBindings);
|
|
|
|
return mBoundUniformBuffers[index];
|
2013-08-20 19:36:19 +04:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
default:
|
|
|
|
MOZ_CRASH("Should not get here.");
|
|
|
|
}
|
2013-08-20 19:36:19 +04:00
|
|
|
}
|
2013-09-04 16:14:46 +04:00
|
|
|
|
2015-05-21 02:59:14 +03:00
|
|
|
GLenum
|
|
|
|
WebGLContext::GetCurrentBinding(WebGLBuffer* buffer) const
|
|
|
|
{
|
|
|
|
if (mBoundArrayBuffer == buffer)
|
|
|
|
return LOCAL_GL_ARRAY_BUFFER;
|
|
|
|
|
|
|
|
if (mBoundCopyReadBuffer == buffer)
|
|
|
|
return LOCAL_GL_COPY_READ_BUFFER;
|
|
|
|
|
|
|
|
if (mBoundCopyWriteBuffer == buffer)
|
|
|
|
return LOCAL_GL_COPY_WRITE_BUFFER;
|
|
|
|
|
|
|
|
if (mBoundPixelPackBuffer == buffer)
|
|
|
|
return LOCAL_GL_PIXEL_PACK_BUFFER;
|
|
|
|
|
|
|
|
if (mBoundPixelUnpackBuffer == buffer)
|
|
|
|
return LOCAL_GL_PIXEL_UNPACK_BUFFER;
|
|
|
|
|
|
|
|
if (mBoundTransformFeedbackBuffer == buffer ||
|
|
|
|
mBoundTransformFeedbackBuffers.Contains(buffer)) {
|
|
|
|
return LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mBoundUniformBuffer == buffer ||
|
|
|
|
mBoundUniformBuffers.Contains(buffer)) {
|
|
|
|
return LOCAL_GL_UNIFORM_BUFFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LOCAL_GL_NONE;
|
|
|
|
}
|
|
|
|
|
2013-09-04 16:14:46 +04:00
|
|
|
GLenum
|
2014-11-14 07:03:50 +03:00
|
|
|
WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
|
|
|
|
const GLvoid* data, GLenum usage)
|
2013-09-04 16:14:46 +04:00
|
|
|
{
|
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// bug 790879
|
|
|
|
if (gl->WorkAroundDriverBugs() &&
|
2014-12-05 10:04:55 +03:00
|
|
|
int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit
|
2013-09-04 16:14:46 +04:00
|
|
|
{
|
2014-11-14 07:03:50 +03:00
|
|
|
GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
|
|
|
|
" a Mac bug", size);
|
2013-09-04 16:14:46 +04:00
|
|
|
return LOCAL_GL_INVALID_VALUE;
|
|
|
|
}
|
|
|
|
#endif
|
2014-11-14 07:03:50 +03:00
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
|
|
|
|
WebGLBuffer* boundBuffer = bufferSlot.get();
|
2014-11-14 07:03:50 +03:00
|
|
|
MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");
|
2013-09-04 16:14:46 +04:00
|
|
|
|
|
|
|
bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
|
|
|
|
if (sizeChanges) {
|
2014-03-08 01:16:34 +04:00
|
|
|
GetAndFlushUnderlyingGLErrors();
|
2013-09-04 16:14:46 +04:00
|
|
|
gl->fBufferData(target, size, data, usage);
|
2014-03-08 01:16:34 +04:00
|
|
|
GLenum error = GetAndFlushUnderlyingGLErrors();
|
2013-09-04 16:14:46 +04:00
|
|
|
return error;
|
|
|
|
} else {
|
|
|
|
gl->fBufferData(target, size, data, usage);
|
|
|
|
return LOCAL_GL_NO_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2014-11-14 07:03:50 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|