1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "host-common/MediaCudaDriverHelper.h"
16 #include <cstdint>
17 #include <string>
18 #include <vector>
19 #include "android/main-emugl.h"
20 
21 #ifdef _WIN32
22 #define WIN32_LEAN_AND_MEAN 1
23 #include <windows.h>
24 #include <winioctl.h>
25 #endif
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 extern "C" {
31 #define INIT_CUDA_GL 1
32 #include "host-common/dynlink_cuda.h"
33 #include "host-common/dynlink_cudaGL.h"
34 #include "host-common/dynlink_nvcuvid.h"
35 }
36 #define MEDIA_CUDA_DEBUG 0
37 
38 #if MEDIA_CUDA_DEBUG
39 #define CUDA_DPRINT(fmt, ...)                                               \
40     fprintf(stderr, "media-cuda--driver-helper: %s:%d " fmt "\n", __func__, \
41             __LINE__, ##__VA_ARGS__);
42 #else
43 #define CUDA_DPRINT(fmt, ...)
44 #endif
45 
46 #define NVDEC_API_CALL(cuvidAPI)                                     \
47     do {                                                             \
48         CUresult errorCode = cuvidAPI;                               \
49         if (errorCode != CUDA_SUCCESS) {                             \
50             CUDA_DPRINT("%s failed with error code %d\n", #cuvidAPI, \
51                         (int)errorCode);                             \
52         }                                                            \
53     } while (0)
54 
55 namespace android {
56 namespace emulation {
57 
58 bool MediaCudaDriverHelper::s_isCudaInitialized = false;
59 
initCudaDrivers()60 bool MediaCudaDriverHelper::initCudaDrivers() {
61     if (s_isCudaInitialized) {
62         return true;
63     }
64 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
65     typedef HMODULE CUDADRIVER;
66 #else
67     typedef void* CUDADRIVER;
68 #endif
69     CUDADRIVER hHandleDriver = 0;
70     int initResult = CUDA_SUCCESS;
71     // try 3 times: especially important after reboot
72     // the cuda ko might not be loaded in the firs try
73     for (int i = 0; i < 3; ++ i) {
74         initResult = cuInit(0, __CUDA_API_VERSION, hHandleDriver);
75         if (CUDA_SUCCESS == initResult) {
76             break;
77         }
78     }
79 
80     if (initResult != CUDA_SUCCESS) {
81         fprintf(stderr,
82                 "Failed to call cuInit, cannot use nvidia cuvid decoder for "
83                 "h264 stream\n");
84         return false;
85     }
86 
87     if (CUDA_SUCCESS != cuvidInit(0)) {
88         fprintf(stderr,
89                 "Failed to call cuvidInit, cannot use nvidia cuvid decoder for "
90                 "h264 stream\n");
91         return false;
92     }
93 
94     int numGpuCards = 0;
95     CUresult myres = cuDeviceGetCount(&numGpuCards);
96     if (myres != CUDA_SUCCESS) {
97         CUDA_DPRINT(
98                 "Failed to get number of GPU cards installed on host; error "
99                 "code %d",
100                 (int)myres);
101         return false;
102     }
103 
104     if (numGpuCards <= 0) {
105         CUDA_DPRINT("There are no nvidia GPU cards on this host.");
106         return false;
107     }
108 
109     // lukily, we get cuda initialized.
110     s_isCudaInitialized = true;
111 
112     return true;
113 }
114 
115 }  // namespace emulation
116 }  // namespace android
117