Cycles: Support visibility check for inner nodes of QBVH
[blender.git] / intern / opensubdiv / opensubdiv_device_context_opencl.cc
1 /*
2  * Adopted from OpenSubdiv with the following license:
3  *
4  *   Copyright 2015 Pixar
5  *
6  *   Licensed under the Apache License, Version 2.0 (the "Apache License")
7  *   with the following modification; you may not use this file except in
8  *   compliance with the Apache License and the following modification to it:
9  *   Section 6. Trademarks. is deleted and replaced with:
10  *
11  *   6. Trademarks. This License does not grant permission to use the trade
12  *      names, trademarks, service marks, or product names of the Licensor
13  *      and its affiliates, except as required to comply with Section 4(c) of
14  *      the License and to reproduce the content of the NOTICE file.
15  *
16  *   You may obtain a copy of the Apache License at
17  *
18  *       http://www.apache.org/licenses/LICENSE-2.0
19  *
20  *   Unless required by applicable law or agreed to in writing, software
21  *   distributed under the Apache License with the above modification is
22  *   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23  *   KIND, either express or implied. See the Apache License for the specific
24  *   language governing permissions and limitations under the Apache License.
25  *
26  */
27
28 #ifdef OPENSUBDIV_HAS_OPENCL
29
30 #ifdef _MSC_VER
31 #  include "iso646.h"
32 #endif
33
34 #include "opensubdiv_device_context_opencl.h"
35
36 #if defined(_WIN32)
37 #  include <windows.h>
38 #elif defined(__APPLE__)
39 #  include <OpenGL/OpenGL.h>
40 #else
41 #  include <GL/glx.h>
42 #endif
43
44 #include <cstdio>
45 #include <cstring>
46 #include <string>
47
48 #define message(...)    // fprintf(stderr, __VA_ARGS__)
49 #define error(...)  fprintf(stderr, __VA_ARGS__)
50
51 /* Returns the first found platform. */
52 static cl_platform_id findPlatform() {
53         cl_uint numPlatforms;
54         cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
55         if (ciErrNum != CL_SUCCESS) {
56                 error("Error %d in clGetPlatformIDs call.\n", ciErrNum);
57                 return NULL;
58         }
59         if (numPlatforms == 0) {
60                 error("No OpenCL platform found.\n");
61                 return NULL;
62         }
63         cl_platform_id *clPlatformIDs = new cl_platform_id[numPlatforms];
64         ciErrNum = clGetPlatformIDs(numPlatforms, clPlatformIDs, NULL);
65         char chBuffer[1024];
66         for (cl_uint i = 0; i < numPlatforms; ++i) {
67                 ciErrNum = clGetPlatformInfo(clPlatformIDs[i], CL_PLATFORM_NAME,
68                                              1024, chBuffer,NULL);
69                 if (ciErrNum == CL_SUCCESS) {
70                         cl_platform_id platformId = clPlatformIDs[i];
71                         delete[] clPlatformIDs;
72                         return platformId;
73                 }
74         }
75         delete[] clPlatformIDs;
76         return NULL;
77 }
78
79 /* Return. the device in clDevices which supports the extension. */
80 static int findExtensionSupportedDevice(cl_device_id *clDevices,
81                                         int numDevices,
82                                         const char *extensionName) {
83         /* Find a device that supports sharing with GL/D3D11
84          * (SLI / X-fire configurations)
85          */
86         cl_int ciErrNum;
87         for (int i = 0; i < numDevices; ++i) {
88                 /* Get extensions string size. */
89                 size_t extensionSize;
90                 ciErrNum = clGetDeviceInfo(clDevices[i],
91                                            CL_DEVICE_EXTENSIONS, 0, NULL,
92                                            &extensionSize);
93                 if (ciErrNum != CL_SUCCESS) {
94                         error("Error %d in clGetDeviceInfo\n", ciErrNum);
95                         return -1;
96                 }
97                 if (extensionSize > 0) {
98                         /* Get extensions string. */
99                         char *extensions = new char[extensionSize];
100                         ciErrNum = clGetDeviceInfo(clDevices[i], CL_DEVICE_EXTENSIONS,
101                                                    extensionSize, extensions,
102                                                    &extensionSize);
103                         if (ciErrNum != CL_SUCCESS) {
104                                 error("Error %d in clGetDeviceInfo\n", ciErrNum);
105                                 delete[] extensions;
106                                 continue;
107                         }
108                         std::string extString(extensions);
109                         delete[] extensions;
110                         /* Parse string. This is bit deficient since the extentions
111                          * is space separated.
112                          *
113                          * The actual string would be "cl_khr_d3d11_sharing"
114                          *                         or "cl_nv_d3d11_sharing"
115                          */
116                         if (extString.find(extensionName) != std::string::npos) {
117                                 return i;
118                         }
119                 }
120         }
121         return -1;
122 }
123
124 CLDeviceContext::CLDeviceContext()
125     : _clContext(NULL),
126       _clCommandQueue(NULL) {
127 }
128
129 CLDeviceContext::~CLDeviceContext() {
130         if (_clCommandQueue)
131                 clReleaseCommandQueue(_clCommandQueue);
132         if (_clContext)
133                 clReleaseContext(_clContext);
134 }
135
136 bool CLDeviceContext::HAS_CL_VERSION_1_1()
137 {
138 #ifdef OPENSUBDIV_HAS_CLEW
139         static bool clewInitialized = false;
140         static bool clewLoadSuccess;
141         if (not clewInitialized) {
142                 clewInitialized = true;
143                 clewLoadSuccess = clewInit() == CLEW_SUCCESS;
144                 if (!clewLoadSuccess) {
145                         error("Loading OpenCL failed.\n");
146                 }
147         }
148         return clewLoadSuccess;
149 #endif
150         return true;
151 }
152
153 bool CLDeviceContext::Initialize()
154 {
155 #ifdef OPENSUBDIV_HAS_CLEW
156         if (!clGetPlatformIDs) {
157                 error("Error clGetPlatformIDs function not bound.\n");
158                 return false;
159         }
160 #endif
161         cl_int ciErrNum;
162         cl_platform_id cpPlatform = findPlatform();
163
164 #if defined(_WIN32)
165         cl_context_properties props[] = {
166                 CL_GL_CONTEXT_KHR, (cl_context_properties)wglGetCurrentContext(),
167                 CL_WGL_HDC_KHR, (cl_context_properties)wglGetCurrentDC(),
168                 CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
169                 0
170         };
171 #elif defined(__APPLE__)
172         CGLContextObj kCGLContext = CGLGetCurrentContext();
173         CGLShareGroupObj kCGLShareGroup = CGLGetShareGroup(kCGLContext);
174         cl_context_properties props[] = {
175                 CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, (cl_context_properties)kCGLShareGroup,
176                 0
177         };
178 #else
179         cl_context_properties props[] = {
180                 CL_GL_CONTEXT_KHR, (cl_context_properties)glXGetCurrentContext(),
181                 CL_GLX_DISPLAY_KHR, (cl_context_properties)glXGetCurrentDisplay(),
182                 CL_CONTEXT_PLATFORM, (cl_context_properties)cpPlatform,
183                 0
184         };
185 #endif
186
187 #if defined(__APPLE__)
188         _clContext = clCreateContext(props, 0, NULL, clLogMessagesToStdoutAPPLE,
189                                      NULL, &ciErrNum);
190         if (ciErrNum != CL_SUCCESS) {
191                 error("Error %d in clCreateContext\n", ciErrNum);
192                 return false;
193         }
194
195         size_t devicesSize = 0;
196         clGetGLContextInfoAPPLE(_clContext, kCGLContext,
197                                 CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
198                                 0, NULL, &devicesSize);
199         int numDevices = int(devicesSize / sizeof(cl_device_id));
200         if (numDevices == 0) {
201                 error("No sharable devices.\n");
202                 return false;
203         }
204         cl_device_id *clDevices = new cl_device_id[numDevices];
205         clGetGLContextInfoAPPLE(_clContext, kCGLContext,
206                                 CL_CGL_DEVICES_FOR_SUPPORTED_VIRTUAL_SCREENS_APPLE,
207                                 numDevices * sizeof(cl_device_id), clDevices, NULL);
208         int clDeviceUsed = 0;
209
210 #else   // not __APPLE__
211         /* Get the number of GPU devices available to the platform. */
212         cl_uint numDevices = 0;
213         clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
214         if (numDevices == 0) {
215                 error("No CL GPU device found.\n");
216                 return false;
217         }
218
219         /* Create the device list. */
220         cl_device_id *clDevices = new cl_device_id[numDevices];
221         clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, numDevices, clDevices, NULL);
222
223         const char *extension = "cl_khr_gl_sharing";
224         int clDeviceUsed = findExtensionSupportedDevice(clDevices, numDevices,
225                                                         extension);
226
227         if (clDeviceUsed < 0) {
228                 error("No device found that supports CL/GL context sharing\n");
229                 delete[] clDevices;
230                 return false;
231         }
232
233         _clContext = clCreateContext(props, 1, &clDevices[clDeviceUsed],
234                                      NULL, NULL, &ciErrNum);
235 #endif   // not __APPLE__
236         if (ciErrNum != CL_SUCCESS) {
237                 error("Error %d in clCreateContext\n", ciErrNum);
238                 delete[] clDevices;
239                 return false;
240         }
241         _clCommandQueue = clCreateCommandQueue(_clContext, clDevices[clDeviceUsed],
242                                                0, &ciErrNum);
243         delete[] clDevices;
244         if (ciErrNum != CL_SUCCESS) {
245                 error("Error %d in clCreateCommandQueue\n", ciErrNum);
246                 return false;
247         }
248         return true;
249 }
250
251 #endif  /* OPENSUBDIV_HAS_OPENCL */