2018-11-30 22:52:05 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2014-09-18 02:08:41 +04:00
|
|
|
/* 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
|
|
|
|
2020-01-09 01:19:14 +03:00
|
|
|
#include "ClientWebGLContext.h"
|
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
|
|
|
|
|
2014-12-05 10:04:55 +03:00
|
|
|
void WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
|
2020-01-09 01:19:16 +03:00
|
|
|
uint64_t readOffset, uint64_t writeOffset,
|
|
|
|
uint64_t size) const {
|
2018-07-27 07:46:33 +03:00
|
|
|
const FuncScope funcScope(*this, "copyBufferSubData");
|
2014-12-05 10:04:55 +03:00
|
|
|
if (IsContextLost()) return;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
const auto& readBuffer = ValidateBufferSelection(readTarget);
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!readBuffer) return;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
const auto& writeBuffer = ValidateBufferSelection(writeTarget);
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!writeBuffer) return;
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2019-03-07 02:52:05 +03:00
|
|
|
if (!CheckedInt<GLintptr>(readOffset).isValid() ||
|
|
|
|
!CheckedInt<GLintptr>(writeOffset).isValid() ||
|
|
|
|
!CheckedInt<GLsizeiptr>(size).isValid())
|
|
|
|
return ErrorOutOfMemory("offset or size too large for platform.");
|
|
|
|
|
|
|
|
const auto fnValidateOffsetSize = [&](const char* info, WebGLintptr offset,
|
2016-09-10 07:02:54 +03:00
|
|
|
const WebGLBuffer* buffer) {
|
2019-03-07 02:52:05 +03:00
|
|
|
const auto neededBytes = CheckedInt<uint64_t>(offset) + size;
|
2016-09-10 07:02:54 +03:00
|
|
|
if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
|
2018-07-27 07:46:33 +03:00
|
|
|
ErrorInvalidValue("Invalid %s range.", info);
|
2016-09-10 07:02:54 +03:00
|
|
|
return false;
|
2014-12-05 10:04:55 +03:00
|
|
|
}
|
2016-09-10 07:02:54 +03:00
|
|
|
return true;
|
|
|
|
};
|
2018-11-30 13:46:48 +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
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-09-29 00:18:23 +03:00
|
|
|
if (readBuffer == writeBuffer) {
|
2016-09-29 00:21:43 +03:00
|
|
|
const bool separate =
|
|
|
|
(readOffset + size <= writeOffset || writeOffset + size <= readOffset);
|
2016-09-29 00:18:23 +03:00
|
|
|
if (!separate) {
|
2018-07-27 07:46:33 +03:00
|
|
|
ErrorInvalidValue(
|
|
|
|
"Ranges [readOffset, readOffset + size) and"
|
2016-09-10 07:02:54 +03:00
|
|
|
" [writeOffset, writeOffset + size) overlap.");
|
2015-05-21 02:59:14 +03:00
|
|
|
return;
|
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
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) {
|
2018-07-27 07:46:33 +03:00
|
|
|
ErrorInvalidOperation(
|
|
|
|
"Can't copy %s data to %s data.",
|
2016-06-14 19:02:01 +03:00
|
|
|
(readType == WebGLBuffer::Kind::OtherData) ? "other" : "element",
|
|
|
|
(writeType == WebGLBuffer::Kind::OtherData) ? "other" : "element");
|
2018-11-30 13:46:48 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
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,
|
2018-11-30 13:46:48 +03:00
|
|
|
size);
|
|
|
|
|
2017-12-21 03:31:58 +03:00
|
|
|
writeBuffer->ResetLastUpdateFenceId();
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2015-05-21 02:59:14 +03:00
|
|
|
|
2020-07-22 01:56:52 +03:00
|
|
|
bool WebGL2Context::GetBufferSubData(GLenum target, uint64_t srcByteOffset,
|
2020-01-09 01:19:16 +03:00
|
|
|
const Range<uint8_t>& dest) const {
|
2016-09-10 07:02:54 +03:00
|
|
|
const FuncScope funcScope(*this, "getBufferSubData");
|
2020-07-22 01:56:52 +03:00
|
|
|
if (IsContextLost()) return false;
|
2015-05-22 08:49:30 +03:00
|
|
|
|
2018-07-27 07:46:33 +03:00
|
|
|
const auto& buffer = ValidateBufferSelection(target);
|
2020-07-22 01:56:52 +03:00
|
|
|
if (!buffer) return false;
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2020-01-09 01:19:16 +03:00
|
|
|
const auto byteLen = dest.length();
|
2020-07-22 01:56:52 +03:00
|
|
|
if (!buffer->ValidateRange(srcByteOffset, byteLen)) return false;
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
2015-04-17 04:20:22 +03:00
|
|
|
|
2019-03-07 02:52:05 +03:00
|
|
|
if (!CheckedInt<GLintptr>(srcByteOffset).isValid() ||
|
|
|
|
!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
|
|
|
|
ErrorOutOfMemory("offset or size too large for platform.");
|
2020-07-22 01:56:52 +03:00
|
|
|
return false;
|
2016-10-12 03:38:45 +03:00
|
|
|
}
|
|
|
|
const GLsizeiptr glByteLen(byteLen);
|
|
|
|
|
2016-09-10 07:02:54 +03:00
|
|
|
////
|
|
|
|
|
2017-12-15 20:47:29 +03:00
|
|
|
switch (buffer->mUsage) {
|
|
|
|
case LOCAL_GL_STATIC_READ:
|
|
|
|
case LOCAL_GL_STREAM_READ:
|
|
|
|
case LOCAL_GL_DYNAMIC_READ:
|
|
|
|
if (mCompletedFenceId < buffer->mLastUpdateFenceId) {
|
2018-07-27 07:46:33 +03:00
|
|
|
GenerateWarning(
|
|
|
|
"Reading from a buffer without checking for previous"
|
2017-12-21 03:31:58 +03:00
|
|
|
" command completion likely causes pipeline stalls."
|
2018-07-27 07:46:33 +03:00
|
|
|
" Please use FenceSync.");
|
2017-12-15 20:47:29 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2018-07-27 07:46:33 +03:00
|
|
|
GenerateWarning(
|
|
|
|
"Reading from a buffer with usage other than *_READ"
|
|
|
|
" causes pipeline stalls. Copy through a STREAM_READ buffer.");
|
2017-12-15 20:47:29 +03:00
|
|
|
break;
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
////
|
|
|
|
|
2016-09-26 23:38:56 +03:00
|
|
|
const ScopedLazyBind readBind(gl, target, buffer);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-10-12 03:38:45 +03:00
|
|
|
if (byteLen) {
|
2016-12-29 11:08:39 +03:00
|
|
|
const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
|
|
|
|
GLenum mapTarget = target;
|
|
|
|
if (isTF) {
|
|
|
|
gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
|
|
|
|
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
|
|
|
|
mapTarget = LOCAL_GL_ARRAY_BUFFER;
|
2017-12-15 20:47:29 +03:00
|
|
|
}
|
|
|
|
|
2016-12-29 11:08:39 +03:00
|
|
|
const auto mappedBytes = gl->fMapBufferRange(
|
|
|
|
mapTarget, srcByteOffset, glByteLen, LOCAL_GL_MAP_READ_BIT);
|
2020-01-09 01:19:16 +03:00
|
|
|
memcpy(dest.begin().get(), mappedBytes, dest.length());
|
2016-12-29 11:08:39 +03:00
|
|
|
gl->fUnmapBuffer(mapTarget);
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2016-12-29 11:08:39 +03:00
|
|
|
if (isTF) {
|
|
|
|
const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
|
|
|
|
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
|
|
|
|
const GLuint tfo =
|
|
|
|
(mBoundTransformFeedback ? mBoundTransformFeedback->mGLName : 0);
|
|
|
|
gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
|
2016-10-12 03:38:45 +03:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
}
|
2020-07-22 01:56:52 +03:00
|
|
|
return true;
|
2014-09-18 02:08:41 +04:00
|
|
|
}
|
2015-07-15 03:37:28 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|