2014-09-18 02:08:41 +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 "WebGL2Context.h"
|
2014-12-05 10:04:55 +03:00
|
|
|
|
2014-09-18 02:08:41 +04:00
|
|
|
#include "GLContext.h"
|
2014-12-05 10:04:55 +03:00
|
|
|
#include "WebGLBuffer.h"
|
2015-07-15 03:37:28 +03:00
|
|
|
#include "WebGLTransformFeedback.h"
|
2014-09-18 02:08:41 +04:00
|
|
|
|
2015-07-15 03:37:28 +03:00
|
|
|
namespace mozilla {
|
2014-09-18 02:08:41 +04:00
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Buffer objects
|
|
|
|
|
|
|
|
void
|
2014-12-05 10:04:55 +03:00
|
|
|
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
|
|
|
GLintptr readOffset, GLintptr writeOffset,
|
|
|
|
GLsizeiptr size)
|
2014-09-18 02:08:41 +04:00
|
|
|
{
|
2016-06-14 19:02:01 +03:00
|
|
|
const char funcName[] = "copyBufferSubData";
|
2014-12-05 10:04:55 +03:00
|
|
|
if (IsContextLost())
|
|
|
|
return;
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
|
|
|
|
if (!readBuffer)
|
2014-12-05 10:04:55 +03:00
|
|
|
return;
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
|
|
|
|
if (!writeBuffer)
|
2014-12-05 10:04:55 +03:00
|
|
|
return;
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (readBuffer->mNumActiveTFOs ||
|
|
|
|
writeBuffer->mNumActiveTFOs)
|
|
|
|
{
|
|
|
|
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
|
|
|
" object.",
|
|
|
|
funcName);
|
2016-06-14 19:02:01 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-12-05 10:04:55 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
|
|
|
|
!ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
|
|
|
|
!ValidateNonNegative(funcName, "size", size))
|
|
|
|
{
|
2014-12-05 10:04:55 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
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;
|
|
|
|
};
|
2016-06-14 19:02:01 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
|
|
|
|
!fnValidateOffsetSize("write", writeOffset, writeBuffer))
|
|
|
|
{
|
2014-12-05 10:04:55 +03:00
|
|
|
return;
|
2016-09-10 07:02:54 +03:00
|
|
|
}
|
2014-12-05 10:04:55 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (readBuffer == writeBuffer &&
|
2016-06-14 19:02:01 +03:00
|
|
|
!ValidateDataRanges(readOffset, writeOffset, size, funcName))
|
2014-12-05 10:04:55 +03:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
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) {
|
2016-06-14 19:02:01 +03:00
|
|
|
ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
|
|
|
|
funcName,
|
|
|
|
(readType == WebGLBuffer::Kind::OtherData) ? "other"
|
|
|
|
: "element",
|
|
|
|
(writeType == WebGLBuffer::Kind::OtherData) ? "other"
|
|
|
|
: "element");
|
2015-05-21 02:59:14 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
gl->MakeCurrent();
|
2016-09-26 23:38:56 +03:00
|
|
|
const ScopedLazyBind readBind(gl, readTarget, readBuffer);
|
|
|
|
const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
|
2016-09-10 07:02:54 +03:00
|
|
|
gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
|
2014-09-18 02:08:41 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-08-10 03:16:09 +03:00
|
|
|
WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
|
|
|
|
const dom::ArrayBufferView& data)
|
2014-09-18 02:08:41 +04:00
|
|
|
{
|
2016-06-14 19:02:01 +03:00
|
|
|
const char funcName[] = "getBufferSubData";
|
2015-04-17 04:20:22 +03:00
|
|
|
if (IsContextLost())
|
|
|
|
return;
|
2015-05-22 08:49:30 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!ValidateNonNegative(funcName, "offset", offset))
|
2015-04-17 04:20:22 +03:00
|
|
|
return;
|
2014-09-18 02:08:41 +04:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto& buffer = ValidateBufferSelection(funcName, target);
|
|
|
|
if (!buffer)
|
2016-06-14 19:02:01 +03:00
|
|
|
return;
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
2015-05-22 08:49:30 +03:00
|
|
|
|
2015-04-17 04:20:22 +03:00
|
|
|
// If offset + returnedData.byteLength would extend beyond the end
|
|
|
|
// of the buffer an INVALID_VALUE error is generated.
|
|
|
|
data.ComputeLengthAndData();
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto neededByteLength = CheckedInt<size_t>(offset) + data.LengthAllowShared();
|
2015-04-17 04:20:22 +03:00
|
|
|
if (!neededByteLength.isValid()) {
|
2016-06-14 19:02:01 +03:00
|
|
|
ErrorInvalidValue("%s: Integer overflow computing the needed byte length.",
|
|
|
|
funcName);
|
2015-04-17 04:20:22 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (neededByteLength.value() > buffer->ByteLength()) {
|
2016-06-14 19:02:01 +03:00
|
|
|
ErrorInvalidValue("%s: Not enough data. Operation requires %d bytes, but buffer"
|
|
|
|
" only has %d bytes.",
|
2016-09-10 07:02:54 +03:00
|
|
|
funcName, neededByteLength.value(), buffer->ByteLength());
|
2015-04-17 04:20:22 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (buffer->mNumActiveTFOs) {
|
|
|
|
ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
|
|
|
|
" object.",
|
|
|
|
funcName);
|
|
|
|
return;
|
|
|
|
}
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
if (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER &&
|
|
|
|
mBoundTransformFeedback->mIsActive)
|
|
|
|
{
|
|
|
|
ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
|
|
|
|
funcName);
|
|
|
|
return;
|
2015-04-17 04:20:22 +03:00
|
|
|
}
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
|
|
|
|
|
|
|
gl->MakeCurrent();
|
2016-09-26 23:38:56 +03:00
|
|
|
const ScopedLazyBind readBind(gl, target, buffer);
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
const auto ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
|
|
|
|
LOCAL_GL_MAP_READ_BIT);
|
2015-11-26 14:47:53 +03:00
|
|
|
// Warning: Possibly shared memory. See bug 1225033.
|
|
|
|
memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
|
2015-04-17 04:20:22 +03:00
|
|
|
gl->fUnmapBuffer(target);
|
2014-09-18 02:08:41 +04:00
|
|
|
}
|
2015-07-15 03:37:28 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|