7#if BLI_SUBPROCESS_SUPPORT
34class SubprocessShader {
40 bool success_ =
false;
43 SubprocessShader(
const char *comp_src,
49 program_ = glCreateProgram();
51 auto compile_stage = [&](
const char *src, GLenum stage) -> GLuint {
58 GLuint shader = glCreateShader(stage);
59 glShaderSource(shader, 1, &src,
nullptr);
60 glCompileShader(shader);
61 glGetShaderiv(shader, GL_COMPILE_STATUS, &
status);
62 glAttachShader(program_, shader);
66 comp_ = compile_stage(comp_src, GL_COMPUTE_SHADER);
71 vert_ = compile_stage(vert_src, GL_VERTEX_SHADER);
76 geom_ = compile_stage(geom_src, GL_GEOMETRY_SHADER);
81 frag_ = compile_stage(frag_src, GL_FRAGMENT_SHADER);
86 glLinkProgram(program_);
87 glGetProgramiv(program_, GL_LINK_STATUS, &
status);
97 glDeleteShader(comp_);
98 glDeleteShader(vert_);
99 glDeleteShader(geom_);
100 glDeleteShader(frag_);
101 glDeleteProgram(program_);
104 ShaderBinaryHeader *get_binary(
void *memory)
106 ShaderBinaryHeader *bin =
reinterpret_cast<ShaderBinaryHeader *
>(memory);
111 glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &bin->size);
112 if (bin->size >
sizeof(ShaderBinaryHeader::data)) {
116 glGetProgramBinary(program_, bin->size,
nullptr, &bin->format, bin->data);
124static bool validate_binary(
void *binary)
126 ShaderBinaryHeader *bin =
reinterpret_cast<ShaderBinaryHeader *
>(binary);
127 GLuint program = glCreateProgram();
128 glProgramBinary(program, bin->format, bin->data, bin->size);
130 glGetProgramiv(program, GL_LINK_STATUS, &
status);
131 glDeleteProgram(program);
135std::string GL_shader_cache_dir_get()
137 static char tmp_dir_buffer[1024];
140 std::string cache_dir = std::string(tmp_dir_buffer) +
"gl-shader-cache" +
SEP_STR;
148void GPU_compilation_subprocess_run(
const char *subprocess_name)
155 pid_t ppid = getppid();
162 GCaps.use_main_context_workaround =
true;
164 std::string
name = subprocess_name;
165 SharedMemory shared_mem(
name, compilation_subprocess_shared_memory_size,
false);
166 if (!shared_mem.get_data()) {
167 std::cerr <<
"Compilation Subprocess: Failed to open shared memory " << subprocess_name
171 SharedSemaphore start_semaphore(
name +
"_START",
true);
172 SharedSemaphore end_semaphore(
name +
"_END",
true);
173 SharedSemaphore close_semaphore(
name +
"_CLOSE",
true);
179 gpu_settings.
context_type = GHOST_kDrawingContextTypeOpenGL;
181 if (ghost_context ==
nullptr) {
182 std::cerr <<
"Compilation Subprocess: Failed to initialize GHOST context for "
183 << subprocess_name <<
"\n";
191 std::string cache_dir = GL_shader_cache_dir_get();
199 start_semaphore.decrement();
201 bool lost_parent =
false;
202 while (!lost_parent && !start_semaphore.try_decrement(1000)) {
203 lost_parent = getppid() != ppid;
206 std::cerr <<
"Compilation Subprocess: Lost parent process\n";
211 if (close_semaphore.try_decrement()) {
215 ShaderSourceHeader *source =
reinterpret_cast<ShaderSourceHeader *
>(shared_mem.get_data());
216 const char *next_src = source->sources;
217 const char *comp_src =
nullptr;
218 const char *vert_src =
nullptr;
219 const char *geom_src =
nullptr;
220 const char *frag_src =
nullptr;
223 std::string hash_str =
"_";
225 auto get_src = [&]() {
226 const char *src = next_src;
227 next_src += strlen(src) +
sizeof(
'\0');
228 hash_str += std::to_string(hasher(src)) +
"_";
232 if (source->type == ShaderSourceHeader::Type::COMPUTE) {
233 comp_src = get_src();
236 vert_src = get_src();
237 if (source->type == ShaderSourceHeader::Type::GRAPHICS_WITH_GEOMETRY_STAGE) {
238 geom_src = get_src();
240 frag_src = get_src();
243 std::string cache_path = cache_dir +
SEP_STR + hash_str;
250 std::string source_hash =
"SOURCE_HASH:" + hash_str;
251 BLI_strncpy(
reinterpret_cast<char *
>(shared_mem.get_data()),
253 source_hash.size() + 1);
258 fstream file(cache_path, std::ios::binary | std::ios::in | std::ios::ate);
259 std::streamsize
size = file.tellg();
260 if (
size <= compilation_subprocess_shared_memory_size) {
261 file.seekg(0, std::ios::beg);
263 static char tmp_mem[compilation_subprocess_shared_memory_size];
264 file.read(tmp_mem,
size);
268 if (!validate_binary(tmp_mem)) {
269 std::cout <<
"Compilation Subprocess: Failed to load cached shader binary " << hash_str
278 memcpy(shared_mem.get_data(), tmp_mem,
size);
279 end_semaphore.increment();
285 std::cerr <<
"Compilation Subprocess: Wrong size for cached shader binary " << hash_str
291 SubprocessShader
shader(comp_src, vert_src, geom_src, frag_src);
292 ShaderBinaryHeader *binary =
shader.get_binary(shared_mem.get_data());
295 fstream file(cache_path, std::ios::binary | std::ios::out);
296 file.write(
reinterpret_cast<char *
>(shared_mem.get_data()),
300 end_semaphore.increment();
310void GL_shader_cache_dir_clear_old()
312 std::string cache_dir = GL_shader_cache_dir_get();
314 direntry *entries =
nullptr;
316 for (
int i : blender::IndexRange(dir_len)) {
317 direntry entry = entries[
i];
321 const time_t ts_now = time(
nullptr);
322 const time_t delete_threshold = 60 * 60 * 24 * 30 ;
323 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.
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void BLI_threadapi_init(void)
Compatibility-like things for windows.
GHOST C-API function and type declarations.
GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle, GHOST_GPUSettings gpu_settings)
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)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
GHOST_TDrawingContextType context_type