Spaces:
Build error
Build error
/* | |
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* 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 | |
* | |
* http://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. | |
*/ | |
/** @file common_host.cu | |
* @author Thomas Müller, NVIDIA | |
*/ | |
namespace ngp { | |
bool is_wsl() { | |
return false; | |
fs::path path = "/proc/sys/kernel/osrelease"; | |
if (!path.exists()) { | |
return false; | |
} | |
std::ifstream f{native_string(path)}; | |
std::string content((std::istreambuf_iterator<char>(f)), (std::istreambuf_iterator<char>())); | |
return content.find("microsoft") != std::string::npos; | |
} | |
std::string utf16_to_utf8(const std::wstring& utf16) { | |
std::string utf8; | |
if (!utf16.empty()) { | |
int size = WideCharToMultiByte(CP_UTF8, 0, &utf16[0], (int)utf16.size(), NULL, 0, NULL, NULL); | |
utf8.resize(size, 0); | |
WideCharToMultiByte(CP_UTF8, 0, &utf16[0], (int)utf16.size(), &utf8[0], size, NULL, NULL); | |
} | |
return utf8; | |
} | |
std::wstring utf8_to_utf16(const std::string& utf8) { | |
std::wstring utf16; | |
if (!utf8.empty()) { | |
int size = MultiByteToWideChar(CP_UTF8, 0, &utf8[0], (int)utf8.size(), NULL, 0); | |
utf16.resize(size, 0); | |
MultiByteToWideChar(CP_UTF8, 0, &utf8[0], (int)utf8.size(), &utf16[0], size); | |
} | |
return utf16; | |
} | |
std::wstring native_string(const fs::path& path) { return path.wstr(); } | |
std::string native_string(const fs::path& path) { return path.str(); } | |
fs::path discover_executable_dir() { | |
WCHAR path[1024]; | |
if (GetModuleFileNameW(NULL, path, 1024) == 0) { | |
return "."; | |
} | |
return fs::path{std::wstring{path}}.parent_path(); | |
char path[PATH_MAX]; | |
ssize_t count = readlink("/proc/self/exe", path, PATH_MAX); | |
if (count == -1) { | |
return "."; | |
} | |
return fs::path{std::string{path}}.parent_path(); | |
} | |
fs::path discover_root_dir() { | |
auto executable_dir = discover_executable_dir(); | |
fs::path exists_in_root_dir = "scripts"; | |
for (const auto& candidate : { | |
fs::path{"."} / exists_in_root_dir, | |
fs::path{".."} / exists_in_root_dir, | |
executable_dir / exists_in_root_dir, | |
executable_dir / ".." / exists_in_root_dir, | |
}) { | |
if (candidate.exists()) { | |
return candidate.parent_path(); | |
} | |
} | |
tlog::warning() << "Could not find root directory."; | |
return "."; | |
} | |
bool ends_with(const std::string& str, const std::string& ending) { | |
if (ending.length() > str.length()) { | |
return false; | |
} | |
return std::equal(std::rbegin(ending), std::rend(ending), std::rbegin(str)); | |
} | |
bool ends_with_case_insensitive(const std::string& str, const std::string& ending) { return ends_with(to_lower(str), to_lower(ending)); } | |
ETestbedMode mode_from_scene(const std::string& scene) { | |
return ETestbedMode::None; | |
} | |
ETestbedMode mode_from_string(const std::string& str) { | |
if (equals_case_insensitive(str, "image")) { | |
return ETestbedMode::Gen3c; | |
} else { | |
return ETestbedMode::None; | |
} | |
} | |
std::string to_string(ETestbedMode mode) { | |
switch (mode) { | |
case ETestbedMode::Gen3c: return "gen3c"; | |
case ETestbedMode::None: return "none"; | |
default: throw std::runtime_error{fmt::format("Can not convert mode {} to string.", (int)mode)}; | |
} | |
} | |
static const stbi_io_callbacks istream_stbi_callbacks = { | |
// Read | |
[](void* context, char* data, int size) { | |
auto stream = reinterpret_cast<std::istream*>(context); | |
stream->read(data, size); | |
return (int)stream->gcount(); | |
}, | |
// Seek | |
[](void* context, int size) { reinterpret_cast<std::istream*>(context)->seekg(size, std::ios_base::cur); }, | |
// EOF | |
[](void* context) { return (int)!!(*reinterpret_cast<std::istream*>(context)); }, | |
}; | |
void istream_stbi_write_func(void* context, void* data, int size) { | |
reinterpret_cast<std::ostream*>(context)->write(reinterpret_cast<char*>(data), size); | |
} | |
uint8_t* load_stbi(const fs::path& path, int* width, int* height, int* comp, int req_comp) { | |
std::ifstream f{native_string(path), std::ios::in | std::ios::binary}; | |
return stbi_load_from_callbacks(&istream_stbi_callbacks, &f, width, height, comp, req_comp); | |
} | |
float* load_stbi_float(const fs::path& path, int* width, int* height, int* comp, int req_comp) { | |
std::ifstream f{native_string(path), std::ios::in | std::ios::binary}; | |
return stbi_loadf_from_callbacks(&istream_stbi_callbacks, &f, width, height, comp, req_comp); | |
} | |
uint16_t* load_stbi_16(const fs::path& path, int* width, int* height, int* comp, int req_comp) { | |
std::ifstream f{native_string(path), std::ios::in | std::ios::binary}; | |
return stbi_load_16_from_callbacks(&istream_stbi_callbacks, &f, width, height, comp, req_comp); | |
} | |
bool is_hdr_stbi(const fs::path& path) { | |
std::ifstream f{native_string(path), std::ios::in | std::ios::binary}; | |
return stbi_is_hdr_from_callbacks(&istream_stbi_callbacks, &f); | |
} | |
int write_stbi(const fs::path& path, int width, int height, int comp, const uint8_t* pixels, int quality) { | |
std::ofstream f{native_string(path), std::ios::out | std::ios::binary}; | |
if (equals_case_insensitive(path.extension(), "jpg") || equals_case_insensitive(path.extension(), "jpeg")) { | |
return stbi_write_jpg_to_func(istream_stbi_write_func, &f, width, height, comp, pixels, quality); | |
} else if (equals_case_insensitive(path.extension(), "png")) { | |
return stbi_write_png_to_func(istream_stbi_write_func, &f, width, height, comp, pixels, width * comp); | |
} else if (equals_case_insensitive(path.extension(), "tga")) { | |
return stbi_write_tga_to_func(istream_stbi_write_func, &f, width, height, comp, pixels); | |
} else if (equals_case_insensitive(path.extension(), "bmp")) { | |
return stbi_write_bmp_to_func(istream_stbi_write_func, &f, width, height, comp, pixels); | |
} else { | |
throw std::runtime_error{fmt::format("write_stbi: unknown image extension '{}'", path.extension())}; | |
} | |
} | |
FILE* native_fopen(const fs::path& path, const char* mode) { | |
return _wfopen(path.wstr().c_str(), utf8_to_utf16(mode).c_str()); | |
return fopen(path.str().c_str(), mode); | |
} | |
GPUMemory<float> load_stbi_gpu(const fs::path& path, int* width, int* height) { | |
bool is_hdr = is_hdr_stbi(path); | |
void* data; // width * height * RGBA | |
int comp; | |
if (is_hdr) { | |
data = load_stbi_float(path, width, height, &comp, 4); | |
} else { | |
data = load_stbi(path, width, height, &comp, 4); | |
} | |
if (!data) { | |
throw std::runtime_error{std::string{stbi_failure_reason()}}; | |
} | |
ScopeGuard mem_guard{[&]() { stbi_image_free(data); }}; | |
if (*width == 0 || *height == 0) { | |
throw std::runtime_error{"Image has zero pixels."}; | |
} | |
GPUMemory<float> result((*width) * (*height) * 4); | |
if (is_hdr) { | |
result.copy_from_host((float*)data); | |
} else { | |
GPUMemory<uint8_t> bytes((*width) * (*height) * 4); | |
bytes.copy_from_host((uint8_t*)data); | |
linear_kernel(from_rgba32<float>, 0, nullptr, (*width) * (*height), bytes.data(), result.data(), false, false, 0); | |
} | |
return result; | |
} | |
std::ostream& operator<<(std::ostream& os, const BoundingBox& bb) { | |
os << "["; | |
os << "min=[" << bb.min.x << "," << bb.min.y << "," << bb.min.z << "], "; | |
os << "max=[" << bb.max.x << "," << bb.max.y << "," << bb.max.z << "]"; | |
os << "]"; | |
return os; | |
} | |
std::ostream& operator<<(std::ostream& os, const Triangle& triangle) { | |
os << "["; | |
os << "a=[" << triangle.a.x << "," << triangle.a.y << "," << triangle.a.z << "], "; | |
os << "b=[" << triangle.b.x << "," << triangle.b.y << "," << triangle.b.z << "], "; | |
os << "c=[" << triangle.c.x << "," << triangle.c.y << "," << triangle.c.z << "]"; | |
os << "]"; | |
return os; | |
} | |
} // namespace ngp | |