7#if BLI_SUBPROCESS_SUPPORT
31class SubprocessShader {
37 bool success_ =
false;
40 SubprocessShader(
const char *comp_src,
46 program_ = glCreateProgram();
48 auto compile_stage = [&](
const char *src, GLenum
stage) -> GLuint {
55 GLuint shader = glCreateShader(
stage);
56 glShaderSource(shader, 1, &src,
nullptr);
57 glCompileShader(shader);
58 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
59 glAttachShader(program_, shader);
63 comp_ = compile_stage(comp_src, GL_COMPUTE_SHADER);
68 vert_ = compile_stage(vert_src, GL_VERTEX_SHADER);
73 geom_ = compile_stage(geom_src, GL_GEOMETRY_SHADER);
78 frag_ = compile_stage(frag_src, GL_FRAGMENT_SHADER);
83 glLinkProgram(program_);
84 glGetProgramiv(program_, GL_LINK_STATUS, &status);
94 glDeleteShader(comp_);
95 glDeleteShader(vert_);
96 glDeleteShader(geom_);
97 glDeleteShader(frag_);
98 glDeleteProgram(program_);
101 ShaderBinaryHeader *get_binary(
void *memory)
103 ShaderBinaryHeader *bin =
reinterpret_cast<ShaderBinaryHeader *
>(memory);
108 glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &bin->size);
109 if (bin->size >
sizeof(ShaderBinaryHeader::data)) {
113 glGetProgramBinary(program_, bin->size,
nullptr, &bin->format, bin->data);
121static bool validate_binary(
void *binary)
123 ShaderBinaryHeader *bin =
reinterpret_cast<ShaderBinaryHeader *
>(binary);
124 GLuint program = glCreateProgram();
125 glProgramBinary(program, bin->format, bin->data, bin->size);
127 glGetProgramiv(program, GL_LINK_STATUS, &status);
128 glDeleteProgram(program);
134static std::string cache_dir_get()
136 static char tmp_dir_buffer[1024];
139 std::string cache_dir = std::string(tmp_dir_buffer) +
"gl-shader-cache" +
SEP_STR;
145void GPU_compilation_subprocess_run(
const char *subprocess_name)
152 pid_t ppid = getppid();
157 std::string name = subprocess_name;
158 SharedMemory shared_mem(name, compilation_subprocess_shared_memory_size,
false);
159 if (!shared_mem.get_data()) {
160 std::cerr <<
"Compilation Subprocess: Failed to open shared memory " << subprocess_name
164 SharedSemaphore start_semaphore(name +
"_START",
true);
165 SharedSemaphore end_semaphore(name +
"_END",
true);
166 SharedSemaphore close_semaphore(name +
"_CLOSE",
true);
172 gpu_settings.
context_type = GHOST_kDrawingContextTypeOpenGL;
174 if (ghost_context ==
nullptr) {
175 std::cerr <<
"Compilation Subprocess: Failed to initialize GHOST context for "
176 << subprocess_name <<
"\n";
184 std::string cache_dir = cache_dir_get();
192 start_semaphore.decrement();
194 bool lost_parent =
false;
195 while (!lost_parent && !start_semaphore.try_decrement(1000)) {
196 lost_parent = getppid() != ppid;
199 std::cerr <<
"Compilation Subprocess: Lost parent process\n";
204 if (close_semaphore.try_decrement()) {
208 ShaderSourceHeader *source =
reinterpret_cast<ShaderSourceHeader *
>(shared_mem.get_data());
209 const char *next_src = source->sources;
210 const char *comp_src =
nullptr;
211 const char *vert_src =
nullptr;
212 const char *geom_src =
nullptr;
213 const char *frag_src =
nullptr;
216 std::string hash_str =
"_";
218 auto get_src = [&]() {
219 const char *src = next_src;
220 next_src += strlen(src) +
sizeof(
'\0');
221 hash_str += std::to_string(hasher(src)) +
"_";
225 if (source->type == ShaderSourceHeader::Type::COMPUTE) {
226 comp_src = get_src();
229 vert_src = get_src();
230 if (source->type == ShaderSourceHeader::Type::GRAPHICS_WITH_GEOMETRY_STAGE) {
231 geom_src = get_src();
233 frag_src = get_src();
236 std::string cache_path = cache_dir +
SEP_STR + hash_str;
243 fstream file(cache_path, std::ios::binary | std::ios::in | std::ios::ate);
244 std::streamsize size = file.tellg();
245 if (size <= compilation_subprocess_shared_memory_size) {
246 file.seekg(0, std::ios::beg);
247 file.read(
reinterpret_cast<char *
>(shared_mem.get_data()), size);
249 if (!validate_binary(shared_mem.get_data())) {
250 std::cout <<
"Compilation Subprocess: Failed to load cached shader binary " << hash_str
257 end_semaphore.increment();
263 std::cerr <<
"Compilation Subprocess: Wrong size for cached shader binary " << hash_str
269 SubprocessShader shader(comp_src, vert_src, geom_src, frag_src);
270 ShaderBinaryHeader *binary = shader.get_binary(shared_mem.get_data());
272 end_semaphore.increment();
275 fstream file(cache_path, std::ios::binary | std::ios::out);
276 file.write(
reinterpret_cast<char *
>(shared_mem.get_data()),
277 binary->size +
offsetof(ShaderBinaryHeader, data));
288void GL_shader_cache_dir_clear_old()
299 const time_t ts_now =
time(
nullptr);
300 const time_t delete_threshold = 60 * 60 * 24 * 30 ;
301 if (entry.
s.st_mtime + delete_threshold < ts_now) {
bool BKE_appdir_folder_caches(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
#define BLI_assert_unreachable()
bool BLI_file_touch(const char *filepath) ATTR_NONNULL(1)
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
File and directory operations.
Compatibility-like things for windows.
GHOST C-API function and type declarations.
GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle, GHOST_GPUSettings gpuSettings)
GHOST_SystemHandle GHOST_CreateSystemBackground(void)
bool GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, bool waitForEvent)
GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle)
GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle, GHOST_ContextHandle contexthandle)
GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle)
static GHOST_SystemCocoa * ghost_system
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
void GPU_context_discard(GPUContext *)
void GPU_backend_ghost_system_set(void *ghost_system_handle)
struct GPUContext GPUContext
static std::optional< std::string > cache_dir_get()
GHOST_TDrawingContextType context_type