WebGL2ContextBuffers.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "WebGL2Context.h"
  6. #include "GLContext.h"
  7. #include "WebGLBuffer.h"
  8. #include "WebGLTransformFeedback.h"
  9. namespace mozilla {
  10. // -------------------------------------------------------------------------
  11. // Buffer objects
  12. void
  13. WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
  14. GLintptr readOffset, GLintptr writeOffset,
  15. GLsizeiptr size)
  16. {
  17. const char funcName[] = "copyBufferSubData";
  18. if (IsContextLost())
  19. return;
  20. const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
  21. if (!readBuffer)
  22. return;
  23. const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
  24. if (!writeBuffer)
  25. return;
  26. if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
  27. !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
  28. !ValidateNonNegative(funcName, "size", size))
  29. {
  30. return;
  31. }
  32. const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
  33. const WebGLBuffer* buffer)
  34. {
  35. const auto neededBytes = CheckedInt<size_t>(offset) + size;
  36. if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
  37. ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
  38. return false;
  39. }
  40. return true;
  41. };
  42. if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
  43. !fnValidateOffsetSize("write", writeOffset, writeBuffer))
  44. {
  45. return;
  46. }
  47. if (readBuffer == writeBuffer) {
  48. MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
  49. MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
  50. const bool separate = (readOffset + size <= writeOffset ||
  51. writeOffset + size <= readOffset);
  52. if (!separate) {
  53. ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and"
  54. " [writeOffset, writeOffset + size) overlap",
  55. funcName);
  56. return;
  57. }
  58. }
  59. const auto& readType = readBuffer->Content();
  60. const auto& writeType = writeBuffer->Content();
  61. MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
  62. MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
  63. if (writeType != readType) {
  64. ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
  65. funcName,
  66. (readType == WebGLBuffer::Kind::OtherData) ? "other"
  67. : "element",
  68. (writeType == WebGLBuffer::Kind::OtherData) ? "other"
  69. : "element");
  70. return;
  71. }
  72. gl->MakeCurrent();
  73. const ScopedLazyBind readBind(gl, readTarget, readBuffer);
  74. const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
  75. gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
  76. }
  77. void
  78. WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
  79. const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
  80. GLuint dstElemCountOverride)
  81. {
  82. const char funcName[] = "getBufferSubData";
  83. if (IsContextLost())
  84. return;
  85. if (!ValidateNonNegative(funcName, "srcByteOffset", srcByteOffset))
  86. return;
  87. uint8_t* bytes;
  88. size_t byteLen;
  89. if (!ValidateArrayBufferView(funcName, dstData, dstElemOffset, dstElemCountOverride,
  90. &bytes, &byteLen))
  91. {
  92. return;
  93. }
  94. ////
  95. const auto& buffer = ValidateBufferSelection(funcName, target);
  96. if (!buffer)
  97. return;
  98. if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
  99. return;
  100. ////
  101. if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
  102. ErrorOutOfMemory("%s: Size too large.", funcName);
  103. return;
  104. }
  105. const GLsizeiptr glByteLen(byteLen);
  106. ////
  107. gl->MakeCurrent();
  108. const ScopedLazyBind readBind(gl, target, buffer);
  109. if (byteLen) {
  110. const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
  111. GLenum mapTarget = target;
  112. if (isTF) {
  113. gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
  114. gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
  115. mapTarget = LOCAL_GL_ARRAY_BUFFER;
  116. }
  117. const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
  118. LOCAL_GL_MAP_READ_BIT);
  119. memcpy(bytes, mappedBytes, byteLen);
  120. gl->fUnmapBuffer(mapTarget);
  121. if (isTF) {
  122. const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
  123. gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
  124. const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
  125. : 0);
  126. gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
  127. }
  128. }
  129. }
  130. } // namespace mozilla