Skip to content

Commit

Permalink
Change: Always load GLB buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
spnda committed Apr 25, 2024
1 parent c0d51fc commit 8f4d753
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 36 deletions.
16 changes: 14 additions & 2 deletions include/fastgltf/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ namespace fastgltf {
* a byte offset and length into the GLB file, which can be useful when using APIs like
* DirectStorage or Metal IO.
*/
LoadGLBBuffers = 1 << 3,
LoadGLBBuffers [[deprecated]] = 1 << 3,

/**
* Loads all external buffers into CPU memory. If disabled, fastgltf will only provide
Expand Down Expand Up @@ -607,12 +607,23 @@ namespace fastgltf {
*/
class GltfDataGetter {
public:
/**
* The read functions expect the implementation to store an offset from the start
* of the buffer/file to the current position. The parse process will always linearly
* access the memory, meaning it will go through the memory once from start to finish.
*/
virtual void read(void* ptr, std::size_t count) = 0;
/**
* Reads a chunk of memory from the current offset, with some amount of padding.
* This padding is necessary for the simdjson parser, but can be initialized to anything.
* The memory pointed to by the span only needs to live until the next call to read().
*/
[[nodiscard]] virtual span<std::byte> read(std::size_t count, std::size_t padding) = 0;

/**
* Reset is used to put the offset index back to the start of the buffer/file.
* This is only used with determineGltfFileType, as it needs to peek into the beginning of the file.
* This is only necessary for functionality like determineGltfFileType. However, reset()
* will be called at the beginning of every parse process.
*/
virtual void reset() = 0;

Expand Down Expand Up @@ -707,6 +718,7 @@ namespace fastgltf {
MappedGltfFile(MappedGltfFile&& other) noexcept;
MappedGltfFile& operator=(MappedGltfFile&& other) noexcept;

/** Memory maps a file. If this fails, you can check std::strerror for a more exact error. */
static Expected<MappedGltfFile> FromPath(const std::filesystem::path& path) noexcept {
MappedGltfFile buffer(path);
if (buffer.error != fastgltf::Error::None) {
Expand Down
52 changes: 23 additions & 29 deletions src/fastgltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3824,7 +3824,7 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept {
}

// Get the file size
struct stat statInfo;
struct stat statInfo {};
if (fstat(fd, &statInfo) != 0) {
error = Error::InvalidPath;
return;
Expand All @@ -3840,7 +3840,6 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept {
if (mappedFile != MAP_FAILED) {
fileSize = static_cast<std::uint64_t>(statInfo.st_size);
} else {
std::perror("Mapping file");
error = Error::FileBufferAllocationFailed;
}

Expand All @@ -3849,7 +3848,7 @@ fg::MappedGltfFile::MappedGltfFile(const fs::path& path) noexcept {
}

fg::MappedGltfFile::MappedGltfFile(fastgltf::MappedGltfFile &&other) noexcept {
// Make sure that munmap is never called when other gets destructud.
// Make sure that munmap is never called when other gets destructed.
mappedFile = std::exchange(other.mappedFile, MAP_FAILED);
fileSize = other.fileSize;
idx = other.idx;
Expand Down Expand Up @@ -4043,11 +4042,12 @@ fg::Expected<fg::Asset> fg::Parser::loadGltfJson(GltfDataGetter& data, fs::path
this->options = options;
this->directory = std::move(directory);

data.reset();
auto jsonSpan = data.read(data.totalSize(), SIMDJSON_PADDING);
simdjson::padded_string_view view(reinterpret_cast<const std::uint8_t*>(jsonSpan.data()),
padded_string_view view(reinterpret_cast<const std::uint8_t*>(jsonSpan.data()),
data.totalSize(),
data.totalSize() + SIMDJSON_PADDING);
simdjson::dom::object root;
dom::object root;
if (auto error = jsonParser->parse(view).get(root); error != SUCCESS) FASTGLTF_UNLIKELY {
return Error::InvalidJson;
}
Expand All @@ -4066,6 +4066,8 @@ fg::Expected<fg::Asset> fg::Parser::loadGltfBinary(GltfDataGetter& data, fs::pat
this->options = options;
this->directory = std::move(directory);

data.reset();

BinaryGltfHeader header = {};
data.read(&header, sizeof header);
if (header.magic != binaryGltfHeaderMagic) {
Expand Down Expand Up @@ -4108,34 +4110,26 @@ fg::Expected<fg::Asset> fg::Parser::loadGltfBinary(GltfDataGetter& data, fs::pat
return Error::InvalidGLB;
}

// TODO: Somehow allow skipping the binary part in the future?
if (binaryChunk.chunkLength != 0) {
if (hasBit(options, Options::LoadGLBBuffers)) {
if (config.mapCallback != nullptr) {
auto info = config.mapCallback(binaryChunk.chunkLength, config.userPointer);
if (info.mappedMemory != nullptr) {
data.read(info.mappedMemory, binaryChunk.chunkLength);
if (config.unmapCallback != nullptr) {
config.unmapCallback(&info, config.userPointer);
}
glbBuffer = sources::CustomBuffer{info.customId, MimeType::None};
if (config.mapCallback != nullptr) {
auto info = config.mapCallback(binaryChunk.chunkLength, config.userPointer);
if (info.mappedMemory != nullptr) {
data.read(info.mappedMemory, binaryChunk.chunkLength);
if (config.unmapCallback != nullptr) {
config.unmapCallback(&info, config.userPointer);
}
} else {
StaticVector<std::uint8_t> binaryData(binaryChunk.chunkLength);
data.read(binaryData.data(), binaryChunk.chunkLength);

sources::Array vectorData = {
std::move(binaryData),
MimeType::GltfBuffer,
};
glbBuffer = std::move(vectorData);
glbBuffer = sources::CustomBuffer{info.customId, MimeType::None};
}
} else {
// TODO: What to do with this?
//const span<const std::byte> glbBytes(reinterpret_cast<std::byte*>(buffer->bufferPointer + offset), binaryChunk.chunkLength);
sources::ByteView glbByteView = {};
//glbByteView.bytes = glbBytes;
glbByteView.mimeType = MimeType::GltfBuffer;
glbBuffer = glbByteView;
StaticVector<std::uint8_t> binaryData(binaryChunk.chunkLength);
data.read(binaryData.data(), binaryChunk.chunkLength);

sources::Array vectorData = {
std::move(binaryData),
MimeType::GltfBuffer,
};
glbBuffer = std::move(vectorData);
}
}
}
Expand Down
8 changes: 3 additions & 5 deletions tests/glb_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@ TEST_CASE("Load basic GLB file", "[gltf-loader]") {
REQUIRE(asset->buffers.size() == 1);

auto& buffer = asset->buffers.front();
auto* bufferView = std::get_if<fastgltf::sources::ByteView>(&buffer.data);
REQUIRE(bufferView != nullptr);
auto jsonSpan = fastgltf::span<std::byte>(jsonData.get());
REQUIRE(bufferView->bytes.data() - jsonSpan.data() == 1016);
REQUIRE(jsonSpan.size() == 1664);
auto* array = std::get_if<fastgltf::sources::Array>(&buffer.data);
REQUIRE(array != nullptr);
REQUIRE(array->bytes.size() == 1664 - 1016);
}

SECTION("Load basic Box.glb and load buffers") {
Expand Down

0 comments on commit 8f4d753

Please sign in to comment.