// Copyright 2021 Benjamin Barenblat // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "src/gl/buffer.h" #include #include #include "src/gl/error.h" #include "src/util.h" #include "third_party/abseil/absl/strings/substitute.h" #include "third_party/glew/include/GL/glew.h" namespace gl { namespace { constexpr uint16_t Pack(Buffer::AccessFrequency frequency, Buffer::AccessNature nature) noexcept { static_assert(sizeof(Buffer::AccessFrequency) == 1); static_assert(sizeof(Buffer::AccessNature) == 1); return FromEnum(frequency) << 8 | FromEnum(nature); } GLenum CombineFrequencyAndNature(Buffer::AccessFrequency frequency, Buffer::AccessNature nature) { using F = ::gl::Buffer::AccessFrequency; using N = ::gl::Buffer::AccessNature; switch (Pack(frequency, nature)) { case Pack(F::kStream, N::kDraw): return GL_STREAM_DRAW; case Pack(F::kStream, N::kRead): return GL_STREAM_READ; case Pack(F::kStream, N::kCopy): return GL_STREAM_COPY; case Pack(F::kStatic, N::kDraw): return GL_STATIC_DRAW; case Pack(F::kStatic, N::kRead): return GL_STATIC_READ; case Pack(F::kStatic, N::kCopy): return GL_STATIC_COPY; case Pack(F::kDynamic, N::kDraw): return GL_DYNAMIC_DRAW; case Pack(F::kDynamic, N::kRead): return GL_DYNAMIC_READ; case Pack(F::kDynamic, N::kCopy): return GL_DYNAMIC_COPY; default: throw std::invalid_argument(absl::Substitute( "GL: invalid access frequency and/or nature ($0, $1)", FromEnum(frequency), FromEnum(nature))); } } } // namespace Buffer::Buffer(const Buffer& other) : size_bytes_(other.size_bytes_), frequency_(other.frequency_), nature_(other.nature_) { gl_internal::CheckThreadSafety(); glCreateBuffers(1, &buffer_); gl_internal::UnnecessaryErrorCheck(); glNamedBufferData(buffer_, size_bytes_, /*data=*/nullptr, CombineFrequencyAndNature(frequency_, nature_)); // An error check is necessary here to detect allocation failure, but it can // be folded into a future error check. gl_internal::UnnecessaryErrorCheck(); glCopyNamedBufferSubData(other.buffer_, buffer_, /*readOffset=*/0, /*writeOffset=*/0, other.size_bytes_); // This error check is necessary because other might be mapped. gl_internal::ErrorCheck(); fprintf(stderr, "BUFFER COPY\n"); } void Buffer::SetData(const void* data, int size_bytes, AccessFrequency frequency, AccessNature nature) { gl_internal::CheckThreadSafety(); glNamedBufferData(buffer_, size_bytes, data, CombineFrequencyAndNature(frequency, nature)); // This error check is necessary to detect allocation failure. gl_internal::ErrorCheck(); size_bytes_ = size_bytes; } } // namespace gl