16 constexpr std::array<std::uint8_t, 8>
magic{
'M',
'S',
'T',
'U',
'D',
'I',
'O',0};
17 StudioEnvironmentError invalid(
const char* message)
22 return {code, detail && *detail ? detail : message};
24 std::uint32_t
read32(std::span<const std::uint8_t>
bytes, std::size_t
at)
26 return static_cast<std::uint32_t
>(
bytes[
at]) |
27 (
static_cast<std::uint32_t
>(
bytes[
at+1]) << 8U) |
28 (
static_cast<std::uint32_t
>(
bytes[
at+2]) << 16U) |
29 (
static_cast<std::uint32_t
>(
bytes[
at+3]) << 24U);
37 bool validPixels(std::span<const std::uint8_t> pixels)
39 for (std::size_t
at = 0;
at < pixels.size();
at += 2U)
41 const auto bits =
static_cast<std::uint16_t
>(pixels[
at] | (pixels[
at+1] << 8U));
43 if ((
bits & 0x7C00U) == 0x7C00U ||
44 ((
bits & 0x8000U) && (
bits & 0x7FFFU)) ||
45 ((
at % 8U) == 6U &&
bits != 0x3C00U))
return false;
51 std::expected<StudioEnvironmentData, StudioEnvironmentError>
55 return std::unexpected(invalid(
"studio environment size outside bounded format"));
57 return std::unexpected(invalid(
"studio environment magic/version mismatch"));
61 return std::unexpected(invalid(
"studio environment shape/format invalid"));
66 bytes.size() != 32U + expected)
67 return std::unexpected(invalid(
"studio environment mip/payload size mismatch"));
69 return std::unexpected(invalid(
"studio environment requires finite nonnegative RGB and alpha one"));
73 std::vector<std::uint8_t>(
bytes.begin()+32,
bytes.end())};
75 catch (
const std::bad_alloc&)
76 {
return std::unexpected(invalid(
"studio environment host allocation failed")); }
79 std::expected<StudioEnvironmentData, StudioEnvironmentError>
84 std::ifstream stream(
path, std::ios::binary | std::ios::ate);
87 const auto size = stream.tellg();
89 return std::unexpected(invalid(
"studio environment file size outside bounds"));
90 std::vector<std::uint8_t>
bytes(
static_cast<std::size_t
>(size));
92 if (!stream.read(
reinterpret_cast<char*
>(
bytes.data()), size))
97 catch (
const std::bad_alloc&)
98 {
return std::unexpected(invalid(
"studio environment host allocation failed")); }
103 { *
this = std::move(
other); }
109 device_ = std::exchange(
other.device_,
nullptr);
110 texture_ = std::exchange(
other.texture_,
nullptr);
111 sampler_ = std::exchange(
other.sampler_,
nullptr);
119 texture_ =
nullptr; sampler_ =
nullptr; device_ =
nullptr;
122 std::expected<StudioEnvironmentGPU, StudioEnvironmentError>
124 {
return uploadInternal(device,
data,
false); }
126 std::expected<StudioEnvironmentGPU, StudioEnvironmentError>
131 if (!device || !
data.width ||
data.width > 128U || (
data.width & (
data.width-1U)) ||
134 return std::unexpected(invalid(
"invalid studio environment upload"));
140 return std::unexpected(StudioEnvironmentError{
143 result.device_ = device;
148 info.width = info.height =
data.width;
149 info.layer_count_or_depth = 6U;
150 info.num_levels =
data.mipCount;
153 if (!result.texture_)
return std::unexpected(
gpuError(
160 sampler.max_lod =
static_cast<float>(
data.mipCount-1U);
162 if (!result.sampler_)
return std::unexpected(
gpuError(
165 std::array<Region,48>
regions{};
190 for (std::uint32_t
i = 0;
i <
count; ++
i)
206 for (std::uint32_t
i = 0;
i <
count; ++
i)
213 to.texture = result.texture_; to.layer =
region.face; to.mip_level =
region.mip;
214 to.w = to.h =
region.size; to.d = 1U;
220 if (!submitted)
return std::unexpected(
gpuError(
225 std::expected<StudioEnvironmentGPU, StudioEnvironmentError>
230 return uploadInternal(device,
black,
true);
std::vector< std::uint8_t > data
std::vector< std::byte > bytes
std::shared_ptr< const data::HmdTextureImage > source
std::uint32_t transferBytes
SDL_GPUShaderFormat format
static std::expected< StudioEnvironmentGPU, StudioEnvironmentError > upload(SDL_GPUDevice *, const StudioEnvironmentData &)
StudioEnvironmentGPU()=default
static std::expected< StudioEnvironmentGPU, StudioEnvironmentError > blackFallback(SDL_GPUDevice *)
SDL_GPUSampler * sampler() const noexcept
StudioEnvironmentGPU & operator=(const StudioEnvironmentGPU &)=delete
StudioEnvironmentErrorCode
std::expected< StudioEnvironmentData, StudioEnvironmentError > readStudioEnvironment(const std::filesystem::path &path)
std::expected< StudioEnvironmentData, StudioEnvironmentError > parseStudioEnvironment(std::span< const std::uint8_t > bytes)
std::vector< std::uint8_t > rgba16f