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