blob: 74fa731ae521842f890324315a9187da8408e482 [file] [log] [blame] [edit]
/*
* Copyright 2025 Rive
*/
#include <fstream>
#include <filesystem>
#include <vector>
#include "shader_hotload.hpp"
#include "rive/math/math_types.hpp"
// We also keep a uint32 header for the size of the bytecode span
static constexpr size_t NUM_EXTRA_BYTECODE_SPAN_BYTES = sizeof(uint32_t);
static size_t write_span_header_into_buffer(char* bytecodeAllocation,
uint32_t fileSize)
{
const size_t numSpanHeaderBytes = sizeof(fileSize);
memcpy(bytecodeAllocation, &fileSize, numSpanHeaderBytes);
return numSpanHeaderBytes;
}
static size_t load_bytecode_file_into_buffer(std::ifstream& shaderBytecodeFile,
size_t fileSize,
char* bytecodeAllocation)
{
// Read entire file into buffer
shaderBytecodeFile.read(
bytecodeAllocation,
rive::math::lossless_numeric_cast<std::streamsize>(fileSize));
const size_t numActualBytesRead = shaderBytecodeFile.gcount();
if (shaderBytecodeFile.good() && numActualBytesRead == fileSize)
{
return fileSize;
}
return numActualBytesRead;
}
static bool is_little_endian()
{
uint32_t num = 1;
uint8_t c[4];
memcpy(&c[0], &num, 4);
return (c[0] == 1);
}
static std::vector<uint32_t> spirvAllocation;
#define RIVE_SUBDIR "rive"
rive::Span<const uint32_t> loadNewShaderFileData()
{
if (!is_little_endian())
{
fprintf(stderr,
"Big endian machine detected! Spir-V data must be little "
"endian.\n");
abort();
}
printf("Loading updated shader bytecode files...\n");
std::filesystem::path riveSpirvPath =
std::filesystem::temp_directory_path() / RIVE_SUBDIR / "spirv";
// List of all shader bytecode files
std::filesystem::path spirvFileNames[] = {
riveSpirvPath / "color_ramp.vert.spirv",
riveSpirvPath / "color_ramp.frag.spirv",
riveSpirvPath / "tessellate.vert.spirv",
riveSpirvPath / "tessellate.frag.spirv",
riveSpirvPath / "render_atlas.vert.spirv",
riveSpirvPath / "render_atlas_fill.frag.spirv",
riveSpirvPath / "render_atlas_stroke.frag.spirv",
riveSpirvPath / "draw_path.vert.spirv",
riveSpirvPath / "draw_path.frag.spirv",
riveSpirvPath / "draw_interior_triangles.vert.spirv",
riveSpirvPath / "draw_interior_triangles.frag.spirv",
riveSpirvPath / "draw_atlas_blit.vert.spirv",
riveSpirvPath / "draw_atlas_blit.frag.spirv",
riveSpirvPath / "draw_image_mesh.vert.spirv",
riveSpirvPath / "draw_image_mesh.frag.spirv",
riveSpirvPath / "atomic_draw_path.vert.spirv",
riveSpirvPath / "atomic_draw_path.frag.spirv",
riveSpirvPath / "atomic_draw_path.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_interior_triangles.vert.spirv",
riveSpirvPath / "atomic_draw_interior_triangles.frag.spirv",
riveSpirvPath / "atomic_draw_interior_triangles.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.vert.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.frag.spirv",
riveSpirvPath / "atomic_draw_atlas_blit.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_image_rect.vert.spirv",
riveSpirvPath / "atomic_draw_image_rect.frag.spirv",
riveSpirvPath / "atomic_draw_image_rect.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_draw_image_mesh.vert.spirv",
riveSpirvPath / "atomic_draw_image_mesh.frag.spirv",
riveSpirvPath / "atomic_draw_image_mesh.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_resolve.vert.spirv",
riveSpirvPath / "atomic_resolve.frag.spirv",
riveSpirvPath / "atomic_resolve.fixedcolor_frag.spirv",
riveSpirvPath / "atomic_resolve_coalesced.vert.spirv",
riveSpirvPath / "atomic_resolve_coalesced.frag.spirv",
riveSpirvPath / "draw_clockwise_atomic_path.vert.spirv",
riveSpirvPath / "draw_clockwise_atomic_path.frag.spirv",
riveSpirvPath / "draw_clockwise_atomic_interior_triangles.vert.spirv",
riveSpirvPath / "draw_clockwise_atomic_interior_triangles.frag.spirv",
riveSpirvPath / "draw_clockwise_atomic_atlas_blit.vert.spirv",
riveSpirvPath / "draw_clockwise_atomic_atlas_blit.frag.spirv",
riveSpirvPath / "draw_clockwise_atomic_image_mesh.vert.spirv",
riveSpirvPath / "draw_clockwise_atomic_image_mesh.frag.spirv",
riveSpirvPath / "draw_msaa_path.vert.spirv",
riveSpirvPath / "draw_msaa_path.noclipdistance_vert.spirv",
riveSpirvPath / "draw_msaa_path.frag.spirv",
riveSpirvPath / "draw_msaa_path.fixedcolor_frag.spirv",
riveSpirvPath / "draw_msaa_stencil.vert.spirv",
riveSpirvPath / "draw_msaa_stencil.frag.spirv",
riveSpirvPath / "draw_msaa_stencil.fixedcolor_frag.spirv",
riveSpirvPath / "draw_msaa_atlas_blit.vert.spirv",
riveSpirvPath / "draw_msaa_atlas_blit.noclipdistance_vert.spirv",
riveSpirvPath / "draw_msaa_atlas_blit.frag.spirv",
riveSpirvPath / "draw_msaa_atlas_blit.fixedcolor_frag.spirv",
riveSpirvPath / "draw_msaa_image_mesh.vert.spirv",
riveSpirvPath / "draw_msaa_image_mesh.noclipdistance_vert.spirv",
riveSpirvPath / "draw_msaa_image_mesh.frag.spirv",
riveSpirvPath / "draw_msaa_image_mesh.fixedcolor_frag.spirv",
riveSpirvPath / "copy_attachment_to_attachment.vert",
riveSpirvPath / "copy_attachment_to_attachment.frag",
};
constexpr size_t numFiles = std::size(spirvFileNames);
size_t spirvSpanSizes[numFiles] = {};
size_t totalSpirvCodeSize = 0;
for (size_t i = 0; i < numFiles; ++i)
{
std::string currFileName = spirvFileNames[i].string();
if (!std::filesystem::exists(currFileName))
{
fprintf(stderr,
"File %s does not exist! Quitting.\n",
currFileName.c_str());
return rive::make_span<const uint32_t>(0, 0);
}
const size_t fileSize = rive::math::lossless_numeric_cast<size_t>(
std::filesystem::file_size(currFileName));
if (fileSize > std::numeric_limits<uint32_t>::max())
{
fprintf(stderr,
"File %s is over 4gb (> 32 bits), aborting!\n",
currFileName.c_str());
abort();
}
spirvSpanSizes[i] = fileSize;
totalSpirvCodeSize += fileSize + NUM_EXTRA_BYTECODE_SPAN_BYTES;
}
// Allocate memory for loading files into
spirvAllocation.resize(totalSpirvCodeSize / sizeof(uint32_t));
char* currSpirvAllocPtr = reinterpret_cast<char*>(spirvAllocation.data());
for (size_t i = 0; i < numFiles; ++i)
{
const size_t currFileSize = spirvSpanSizes[i];
if (currFileSize == 0)
{
continue;
}
const size_t numExpectedBytesToProcess =
NUM_EXTRA_BYTECODE_SPAN_BYTES + currFileSize;
char* prevSpirvAllocPtr = currSpirvAllocPtr;
// Write span header as size of bytecode in uint32s
currSpirvAllocPtr += write_span_header_into_buffer(
currSpirvAllocPtr,
rive::math::lossless_numeric_cast<uint32_t>(currFileSize /
sizeof(uint32_t)));
// Try to open the file
std::ifstream shaderBytecodeFile;
shaderBytecodeFile.open(spirvFileNames[i],
std::ios::in | std::ios::binary);
if (!shaderBytecodeFile.is_open())
{
fprintf(stderr,
"Failed to open shader bytecode binary file. Giving up.\n");
return rive::make_span<const uint32_t>(0, 0);
}
currSpirvAllocPtr += load_bytecode_file_into_buffer(shaderBytecodeFile,
currFileSize,
currSpirvAllocPtr);
if (numExpectedBytesToProcess !=
(currSpirvAllocPtr - prevSpirvAllocPtr))
{
fprintf(stderr,
"Error while reading spirv file: %s. Giving up.\n",
spirvFileNames[i].string().c_str());
shaderBytecodeFile.close();
return rive::make_span<const uint32_t>(0, 0);
}
shaderBytecodeFile.close();
}
printf("...done.\n");
rive::Span<const uint32_t> bytecodeSpan =
rive::make_span<const uint32_t>(spirvAllocation.data(),
spirvAllocation.size());
assert(bytecodeSpan.data());
assert(bytecodeSpan.size() > 0);
return bytecodeSpan;
}