1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "utils.h"
17 
interop_user_sync(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements,unsigned int width,unsigned int height,TContextFuncType functionCreate,cl_dx9_media_adapter_type_khr adapterType,TSurfaceFormat surfaceFormat,TSharedHandleType sharedHandle,cl_bool userSync)18 int interop_user_sync(cl_device_id deviceID, cl_context context,
19                       cl_command_queue queue, int num_elements,
20                       unsigned int width, unsigned int height,
21                       TContextFuncType functionCreate,
22                       cl_dx9_media_adapter_type_khr adapterType,
23                       TSurfaceFormat surfaceFormat,
24                       TSharedHandleType sharedHandle, cl_bool userSync)
25 {
26     CResult result;
27 
28     // create device
29     std::auto_ptr<CDeviceWrapper> deviceWrapper;
30     if (!DeviceCreate(adapterType, deviceWrapper))
31     {
32         result.ResultSub(CResult::TEST_ERROR);
33         return result.Result();
34     }
35 
36     // generate input data
37     std::vector<cl_uchar> bufferIn(width * height * 3 / 2, 0);
38     if (!YUVGenerate(surfaceFormat, bufferIn, width, height, 0, 255))
39     {
40         result.ResultSub(CResult::TEST_ERROR);
41         return result.Result();
42     }
43 
44     while (deviceWrapper->AdapterNext())
45     {
46         cl_int error;
47         // check if the test can be run on the adapter
48         if (CL_SUCCESS
49             != (error = deviceExistForCLTest(gPlatformIDdetected, adapterType,
50                                              deviceWrapper->Device(), result,
51                                              sharedHandle)))
52         {
53             return result.Result();
54         }
55 
56         if (surfaceFormat != SURFACE_FORMAT_NV12
57             && !SurfaceFormatCheck(adapterType, *deviceWrapper, surfaceFormat))
58         {
59             std::string sharedHandleStr =
60                 (sharedHandle == SHARED_HANDLE_ENABLED) ? "yes" : "no";
61             std::string syncStr = (userSync == CL_TRUE) ? "yes" : "no";
62             std::string formatStr;
63             std::string adapterStr;
64             SurfaceFormatToString(surfaceFormat, formatStr);
65             AdapterToString(adapterType, adapterStr);
66             log_info("Skipping test case, image format is not supported by a "
67                      "device (adapter type: %s, format: %s, shared handle: %s, "
68                      "user sync: %s)\n",
69                      adapterStr.c_str(), formatStr.c_str(),
70                      sharedHandleStr.c_str(), syncStr.c_str());
71             return result.Result();
72         }
73 
74         void *objectSharedHandle = 0;
75         std::auto_ptr<CSurfaceWrapper> surface;
76         if (!MediaSurfaceCreate(
77                 adapterType, width, height, surfaceFormat, *deviceWrapper,
78                 surface, (sharedHandle == SHARED_HANDLE_ENABLED) ? true : false,
79                 &objectSharedHandle))
80         {
81             log_error("Media surface creation failed for %i adapter\n",
82                       deviceWrapper->AdapterIdx());
83             result.ResultSub(CResult::TEST_ERROR);
84             return result.Result();
85         }
86 
87         cl_context_properties contextProperties[] = {
88             CL_CONTEXT_PLATFORM,
89             (cl_context_properties)gPlatformIDdetected,
90             AdapterTypeToContextInfo(adapterType),
91             (cl_context_properties)deviceWrapper->Device(),
92             CL_CONTEXT_INTEROP_USER_SYNC,
93             userSync,
94             0,
95         };
96 
97 
98         clContextWrapper ctx;
99         switch (functionCreate)
100         {
101             case CONTEXT_CREATE_DEFAULT:
102                 ctx = clCreateContext(&contextProperties[0], 1,
103                                       &gDeviceIDdetected, NULL, NULL, &error);
104                 break;
105             case CONTEXT_CREATE_FROM_TYPE:
106                 ctx = clCreateContextFromType(&contextProperties[0],
107                                               gDeviceTypeSelected, NULL, NULL,
108                                               &error);
109                 break;
110             default:
111                 log_error("Unknown context creation function enum\n");
112                 result.ResultSub(CResult::TEST_ERROR);
113                 return result.Result();
114                 break;
115         }
116 
117         if (error != CL_SUCCESS)
118         {
119             std::string functionName;
120             FunctionContextCreateToString(functionCreate, functionName);
121             log_error("%s failed: %s\n", functionName.c_str(),
122                       IGetErrorString(error));
123             result.ResultSub(CResult::TEST_FAIL);
124             return result.Result();
125         }
126 
127         if (!YUVSurfaceSet(surfaceFormat, surface, bufferIn, width, height))
128         {
129             result.ResultSub(CResult::TEST_ERROR);
130             return result.Result();
131         }
132 
133 #if defined(_WIN32)
134         cl_dx9_surface_info_khr surfaceInfo;
135         surfaceInfo.resource =
136             *(static_cast<CD3D9SurfaceWrapper *>(surface.get()));
137         surfaceInfo.shared_handle = objectSharedHandle;
138 #else
139         void *surfaceInfo = 0;
140         return TEST_NOT_IMPLEMENTED;
141 #endif
142 
143         std::vector<cl_mem> memObjList;
144         unsigned int planesNum = PlanesNum(surfaceFormat);
145         std::vector<clMemWrapper> planesList(planesNum);
146         for (unsigned int planeIdx = 0; planeIdx < planesNum; ++planeIdx)
147         {
148             planesList[planeIdx] = clCreateFromDX9MediaSurfaceKHR(
149                 ctx, CL_MEM_READ_WRITE, adapterType, &surfaceInfo, planeIdx,
150                 &error);
151             if (error != CL_SUCCESS)
152             {
153                 log_error(
154                     "clCreateFromDX9MediaSurfaceKHR failed for plane %i: %s\n",
155                     planeIdx, IGetErrorString(error));
156                 result.ResultSub(CResult::TEST_FAIL);
157                 return result.Result();
158             }
159             memObjList.push_back(planesList[planeIdx]);
160         }
161 
162         clCommandQueueWrapper cmdQueue = clCreateCommandQueueWithProperties(
163             ctx, gDeviceIDdetected, 0, &error);
164         if (error != CL_SUCCESS)
165         {
166             log_error("Unable to create command queue: %s\n",
167                       IGetErrorString(error));
168             result.ResultSub(CResult::TEST_FAIL);
169             return result.Result();
170         }
171 
172         if (!ImageInfoVerify(adapterType, memObjList, width, height, surface,
173                              objectSharedHandle))
174         {
175             log_error("Image info verification failed\n");
176             result.ResultSub(CResult::TEST_FAIL);
177         }
178 
179         if (userSync == CL_TRUE)
180         {
181 #if defined(_WIN32)
182             IDirect3DQuery9 *eventQuery = NULL;
183             switch (adapterType)
184             {
185                 case CL_ADAPTER_D3D9_KHR: {
186                     LPDIRECT3DDEVICE9 device =
187                         (LPDIRECT3DDEVICE9)deviceWrapper->Device();
188                     device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
189                     eventQuery->Issue(D3DISSUE_END);
190 
191                     while (S_FALSE
192                            == eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
193                         ;
194                 }
195                 break;
196                 case CL_ADAPTER_D3D9EX_KHR: {
197                     LPDIRECT3DDEVICE9EX device =
198                         (LPDIRECT3DDEVICE9EX)deviceWrapper->Device();
199                     device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
200                     eventQuery->Issue(D3DISSUE_END);
201 
202                     while (S_FALSE
203                            == eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
204                         ;
205                 }
206                 break;
207                 case CL_ADAPTER_DXVA_KHR: {
208                     CDXVAWrapper *DXVADevice =
209                         dynamic_cast<CDXVAWrapper *>(&(*deviceWrapper));
210                     LPDIRECT3DDEVICE9EX device =
211                         (LPDIRECT3DDEVICE9EX)(DXVADevice->D3D9()).Device();
212                     device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
213                     eventQuery->Issue(D3DISSUE_END);
214 
215                     while (S_FALSE
216                            == eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH))
217                         ;
218                 }
219                 break;
220                 default:
221                     log_error("Unknown adapter type\n");
222                     return false;
223                     break;
224             }
225             if (eventQuery)
226             {
227                 eventQuery->Release();
228             }
229 #else
230             return TEST_NOT_IMPLEMENTED;
231 #endif
232         }
233 
234         error = clEnqueueAcquireDX9MediaSurfacesKHR(
235             cmdQueue, static_cast<cl_uint>(memObjList.size()),
236             &memObjList.at(0), 0, NULL, NULL);
237         if (error != CL_SUCCESS)
238         {
239             log_error("clEnqueueAcquireDX9MediaSurfacesKHR failed: %s\n",
240                       IGetErrorString(error));
241             result.ResultSub(CResult::TEST_FAIL);
242             return result.Result();
243         }
244 
245         size_t origin[3] = { 0, 0, 0 };
246         size_t offset = 0;
247         size_t frameSize = width * height * 3 / 2;
248         std::vector<cl_uchar> out(frameSize, 0);
249         for (size_t i = 0; i < memObjList.size(); ++i)
250         {
251             size_t planeWidth = (i == 0) ? width : width / 2;
252             size_t planeHeight = (i == 0) ? height : height / 2;
253             size_t regionPlane[3] = { planeWidth, planeHeight, 1 };
254 
255             error =
256                 clEnqueueReadImage(cmdQueue, memObjList.at(i), CL_TRUE, origin,
257                                    regionPlane, 0, 0, &out.at(offset), 0, 0, 0);
258             if (error != CL_SUCCESS)
259             {
260                 log_error("clEnqueueReadImage failed: %s\n",
261                           IGetErrorString(error));
262                 result.ResultSub(CResult::TEST_FAIL);
263             }
264 
265             offset += planeWidth * planeHeight;
266         }
267 
268         if (!YUVCompare(surfaceFormat, out, bufferIn, width, height))
269         {
270             log_error("OCL object verification failed - clEnqueueReadImage\n");
271             result.ResultSub(CResult::TEST_FAIL);
272         }
273 
274         error = clEnqueueReleaseDX9MediaSurfacesKHR(
275             cmdQueue, static_cast<cl_uint>(memObjList.size()),
276             &memObjList.at(0), 0, NULL, NULL);
277         if (error != CL_SUCCESS)
278         {
279             log_error("clEnqueueReleaseDX9MediaSurfacesKHR failed: %s\n",
280                       IGetErrorString(error));
281             result.ResultSub(CResult::TEST_FAIL);
282         }
283 
284         if (userSync == CL_TRUE)
285         {
286             error = clFinish(cmdQueue);
287             if (error != CL_SUCCESS)
288             {
289                 log_error("clFinish failed: %s\n", IGetErrorString(error));
290                 result.ResultSub(CResult::TEST_FAIL);
291             }
292         }
293 
294         // shared object verification
295         std::vector<cl_uchar> bufferOut(frameSize, 0);
296         if (!YUVSurfaceGet(surfaceFormat, surface, bufferOut, width, height))
297         {
298             result.ResultSub(CResult::TEST_FAIL);
299             return result.Result();
300         }
301 
302         if (!YUVCompare(surfaceFormat, bufferOut, bufferIn, width, height))
303         {
304             log_error("Media surface is different than expected\n");
305             result.ResultSub(CResult::TEST_FAIL);
306         }
307     }
308 
309     if (deviceWrapper->Status() != DEVICE_PASS)
310     {
311         std::string adapterName;
312         AdapterToString(adapterType, adapterName);
313 
314         if (deviceWrapper->Status() == DEVICE_FAIL)
315         {
316             log_error("%s init failed\n", adapterName.c_str());
317             result.ResultSub(CResult::TEST_FAIL);
318         }
319         else
320         {
321             log_error("%s init incomplete due to unsupported device\n",
322                       adapterName.c_str());
323             result.ResultSub(CResult::TEST_NOTSUPPORTED);
324         }
325     }
326 
327     return result.Result();
328 }
329 
test_interop_user_sync(cl_device_id deviceID,cl_context context,cl_command_queue queue,int num_elements)330 int test_interop_user_sync(cl_device_id deviceID, cl_context context,
331                            cl_command_queue queue, int num_elements)
332 {
333     const unsigned int WIDTH = 256;
334     const unsigned int HEIGHT = 256;
335 
336     std::vector<cl_dx9_media_adapter_type_khr> adapters;
337 #if defined(_WIN32)
338     adapters.push_back(CL_ADAPTER_D3D9_KHR);
339     adapters.push_back(CL_ADAPTER_D3D9EX_KHR);
340     adapters.push_back(CL_ADAPTER_DXVA_KHR);
341 #else
342     return TEST_NOT_IMPLEMENTED;
343 #endif
344 
345     std::vector<TContextFuncType> contextFuncs;
346     contextFuncs.push_back(CONTEXT_CREATE_DEFAULT);
347     contextFuncs.push_back(CONTEXT_CREATE_FROM_TYPE);
348 
349     std::vector<TSurfaceFormat> formats;
350     formats.push_back(SURFACE_FORMAT_NV12);
351     formats.push_back(SURFACE_FORMAT_YV12);
352 
353     std::vector<TSharedHandleType> sharedHandleTypes;
354     sharedHandleTypes.push_back(SHARED_HANDLE_DISABLED);
355     sharedHandleTypes.push_back(SHARED_HANDLE_ENABLED);
356 
357     std::vector<cl_bool> sync;
358     sync.push_back(CL_FALSE);
359     sync.push_back(CL_TRUE);
360 
361     CResult result;
362     for (size_t adapterIdx = 0; adapterIdx < adapters.size(); ++adapterIdx)
363     {
364         // iteration through all create context functions
365         for (size_t contextFuncIdx = 0; contextFuncIdx < contextFuncs.size();
366              ++contextFuncIdx)
367         {
368             // iteration through YUV formats
369             for (size_t formatIdx = 0; formatIdx < formats.size(); ++formatIdx)
370             {
371                 // shared handle enabled or disabled
372                 for (size_t sharedHandleIdx = 0;
373                      sharedHandleIdx < sharedHandleTypes.size();
374                      ++sharedHandleIdx)
375                 {
376                     // user sync interop disabled or enabled
377                     for (size_t syncIdx = 0; syncIdx < sync.size(); ++syncIdx)
378                     {
379                         if (adapters[adapterIdx] == CL_ADAPTER_D3D9_KHR
380                             && sharedHandleTypes[sharedHandleIdx]
381                                 == SHARED_HANDLE_ENABLED)
382                             continue;
383 
384                         if (interop_user_sync(
385                                 deviceID, context, queue, num_elements, WIDTH,
386                                 HEIGHT, contextFuncs[contextFuncIdx],
387                                 adapters[adapterIdx], formats[formatIdx],
388                                 sharedHandleTypes[sharedHandleIdx],
389                                 sync[syncIdx])
390                             != 0)
391                         {
392                             std::string syncStr = (sync[syncIdx] == CL_TRUE)
393                                 ? "user sync enabled"
394                                 : "user sync disabled";
395                             std::string sharedHandle =
396                                 (sharedHandleTypes[sharedHandleIdx]
397                                  == SHARED_HANDLE_ENABLED)
398                                 ? "shared handle"
399                                 : "no shared handle";
400                             std::string adapterStr;
401                             std::string formatStr;
402                             SurfaceFormatToString(formats[formatIdx],
403                                                   formatStr);
404                             AdapterToString(adapters[adapterIdx], adapterStr);
405 
406                             log_error("\nTest case - clCreateContext (%s, %s, "
407                                       "%s, %s) failed\n\n",
408                                       adapterStr.c_str(), formatStr.c_str(),
409                                       sharedHandle.c_str(), syncStr.c_str());
410                             result.ResultSub(CResult::TEST_FAIL);
411                         }
412                     }
413                 }
414             }
415         }
416     }
417 
418     return result.Result();
419 }
420