From d6ec4b874b99f096ce2aa1c2864609bb2e4b58ad Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 3 Sep 2012 12:52:21 +0000 Subject: Compositor: initialize OpenCL only when the option is enabled. This eliminates error prints or even crashes for poor OpenCL implementations when not using it. --- .../compositor/intern/COM_WorkScheduler.cpp | 143 +++++++++++++-------- .../blender/compositor/intern/COM_WorkScheduler.h | 4 +- .../blender/compositor/intern/COM_compositor.cpp | 20 ++- 3 files changed, 107 insertions(+), 60 deletions(-) (limited to 'source/blender') diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index 5f133fe071f..f9af23faea8 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -54,6 +54,7 @@ static vector g_cpudevices; #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE /// @brief list of all thread for every CPUDevice in cpudevices a thread exists static ListBase g_cputhreads; +static bool g_cpuInitialized = false; /// @brief all scheduled work for the cpu static ThreadQueue *g_cpuqueue; static ThreadQueue *g_gpuqueue; @@ -67,11 +68,13 @@ static ListBase g_gputhreads; /// @brief all scheduled work for the gpu #ifdef COM_OPENCL_ENABLED static bool g_openclActive = false; +static bool g_openclInitialized = false; #endif #endif #endif #define MAX_HIGHLIGHT 8 +static bool g_highlightInitialized = false; extern "C" { int g_highlightIndex; void **g_highlightedNodes; @@ -255,40 +258,59 @@ extern void clContextError(const char *errinfo, const void *private_info, size_t printf("OPENCL error: %s\n", errinfo); } -void WorkScheduler::initialize() +void WorkScheduler::initialize(bool use_opencl) { - if (g_highlightedNodesRead) MEM_freeN(g_highlightedNodesRead); - if (g_highlightedNodes) MEM_freeN(g_highlightedNodes); + /* initialize highlighting */ + if (!g_highlightInitialized) { + if (g_highlightedNodesRead) MEM_freeN(g_highlightedNodesRead); + if (g_highlightedNodes) MEM_freeN(g_highlightedNodes); - g_highlightedNodesRead = NULL; - g_highlightedNodes = NULL; + g_highlightedNodesRead = NULL; + g_highlightedNodes = NULL; + + COM_startReadHighlights(); + + g_highlightInitialized = true; + } - COM_startReadHighlights(); #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - int numberOfCPUThreads = BLI_system_thread_count(); + /* initialize CPU threads */ + if (!g_cpuInitialized) { + int numberOfCPUThreads = BLI_system_thread_count(); - for (int index = 0; index < numberOfCPUThreads; index++) { - CPUDevice *device = new CPUDevice(); - device->initialize(); - g_cpudevices.push_back(device); + for (int index = 0; index < numberOfCPUThreads; index++) { + CPUDevice *device = new CPUDevice(); + device->initialize(); + g_cpudevices.push_back(device); + } + + g_cpuInitialized = true; } + #ifdef COM_OPENCL_ENABLED - g_context = NULL; - g_program = NULL; - if (clCreateContextFromType) { - cl_uint numberOfPlatforms = 0; - cl_int error; - error = clGetPlatformIDs(0, 0, &numberOfPlatforms); - if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } - if (G.f & G_DEBUG) printf("%d number of platforms\n", numberOfPlatforms); - cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN(sizeof(cl_platform_id) * numberOfPlatforms, __func__); - error = clGetPlatformIDs(numberOfPlatforms, platforms, 0); - unsigned int indexPlatform; - for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) { - cl_platform_id platform = platforms[indexPlatform]; - cl_uint numberOfDevices = 0; - clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, 0, &numberOfDevices); - if (numberOfDevices > 0) { + /* deinitialize OpenCL GPU's */ + if (use_opencl && !g_openclInitialized) { + g_context = NULL; + g_program = NULL; + + OCL_init(); /* this will check and skip if already initialized */ + + if (clCreateContextFromType) { + cl_uint numberOfPlatforms = 0; + cl_int error; + error = clGetPlatformIDs(0, 0, &numberOfPlatforms); + if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); } + if (G.f & G_DEBUG) printf("%d number of platforms\n", numberOfPlatforms); + cl_platform_id *platforms = (cl_platform_id *)MEM_mallocN(sizeof(cl_platform_id) * numberOfPlatforms, __func__); + error = clGetPlatformIDs(numberOfPlatforms, platforms, 0); + unsigned int indexPlatform; + for (indexPlatform = 0; indexPlatform < numberOfPlatforms; indexPlatform++) { + cl_platform_id platform = platforms[indexPlatform]; + cl_uint numberOfDevices = 0; + clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, 0, &numberOfDevices); + if (numberOfDevices <= 0) + continue; + cl_device_id *cldevices = (cl_device_id *)MEM_mallocN(sizeof(cl_device_id) * numberOfDevices, __func__); clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numberOfDevices, cldevices, 0); @@ -324,8 +346,10 @@ void WorkScheduler::initialize() } MEM_freeN(cldevices); } + MEM_freeN(platforms); } - MEM_freeN(platforms); + + g_openclInitialized = true; } #endif #endif @@ -334,37 +358,52 @@ void WorkScheduler::initialize() void WorkScheduler::deinitialize() { #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE - Device *device; - while (g_cpudevices.size() > 0) { - device = g_cpudevices.back(); - g_cpudevices.pop_back(); - device->deinitialize(); - delete device; + /* deinitialize CPU threads */ + if (g_cpuInitialized) { + Device *device; + while (g_cpudevices.size() > 0) { + device = g_cpudevices.back(); + g_cpudevices.pop_back(); + device->deinitialize(); + delete device; + } + + g_cpuInitialized = false; } + #ifdef COM_OPENCL_ENABLED - while (g_gpudevices.size() > 0) { - device = g_gpudevices.back(); - g_gpudevices.pop_back(); - device->deinitialize(); - delete device; - } - if (g_program) { - clReleaseProgram(g_program); - g_program = NULL; - } - if (g_context) { - clReleaseContext(g_context); - g_context = NULL; + /* deinitialize OpenCL GPU's */ + if (g_openclInitialized) { + Device *device; + while (g_gpudevices.size() > 0) { + device = g_gpudevices.back(); + g_gpudevices.pop_back(); + device->deinitialize(); + delete device; + } + if (g_program) { + clReleaseProgram(g_program); + g_program = NULL; + } + if (g_context) { + clReleaseContext(g_context); + g_context = NULL; + } + + g_openclInitialized = false; } #endif #endif - if (g_highlightedNodes) { - MEM_freeN(g_highlightedNodes); - } + /* deinitialize highlighting */ + if (g_highlightInitialized) { + if (g_highlightedNodes) + MEM_freeN(g_highlightedNodes); - if (g_highlightedNodesRead) { - MEM_freeN(g_highlightedNodesRead); + if (g_highlightedNodesRead) + MEM_freeN(g_highlightedNodesRead); + + g_highlightInitialized = false; } } diff --git a/source/blender/compositor/intern/COM_WorkScheduler.h b/source/blender/compositor/intern/COM_WorkScheduler.h index f56fe94201e..4ab23cf9ae4 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.h +++ b/source/blender/compositor/intern/COM_WorkScheduler.h @@ -74,8 +74,10 @@ public: * After mutex initialization the system is queried in order to count the number of CPUDevices and GPUDevices to be created. * For every hardware thread a CPUDevice and for every OpenCL GPU device a OpenCLDevice is created. * these devices are stored in a separate list (cpudevices & gpudevices) + * + * This function can be called multiple times to lazily initialize OpenCL. */ - static void initialize(); + static void initialize(bool use_opencl); /** * @brief deinitialize the WorkScheduler diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp index 7dcb3572a14..daf48d65caf 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cpp @@ -36,24 +36,29 @@ extern "C" { static ThreadMutex s_compositorMutex; static char is_compositorMutex_init = FALSE; + void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering) { - if (is_compositorMutex_init == FALSE) { /// TODO: move to blender startup phase - memset(&s_compositorMutex, 0, sizeof(s_compositorMutex)); + /* initialize mutex, TODO this mutex init is actually not thread safe and + * should be done somewhere as part of blender startup, all the other + * initializations can be done lazily */ + if (is_compositorMutex_init == FALSE) { BLI_mutex_init(&s_compositorMutex); - OCL_init(); - WorkScheduler::initialize(); ///TODO: call workscheduler.deinitialize somewhere is_compositorMutex_init = TRUE; } + BLI_mutex_lock(&s_compositorMutex); + if (editingtree->test_break(editingtree->tbh)) { // during editing multiple calls to this method can be triggered. // make sure one the last one will be doing the work. BLI_mutex_unlock(&s_compositorMutex); return; - } + /* initialize workscheduler, will check if already done. TODO deinitialize somewhere */ + bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL); + WorkScheduler::initialize(use_opencl); /* set progress bar to 0% and status to init compositing */ editingtree->progress(editingtree->prh, 0.0); @@ -83,11 +88,12 @@ void COM_execute(RenderData *rd, bNodeTree *editingtree, int rendering) void COM_deinitialize() { - if (is_compositorMutex_init) - { + if (is_compositorMutex_init) { BLI_mutex_lock(&s_compositorMutex); + deintializeDistortionCache(); WorkScheduler::deinitialize(); + is_compositorMutex_init = FALSE; BLI_mutex_unlock(&s_compositorMutex); BLI_mutex_end(&s_compositorMutex); -- cgit v1.2.3