1 // Copyright (C) 2020 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/MediaCudaUtils.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 
37 #define MEDIA_CUVID_DEBUG 0
38 
39 #if MEDIA_CUVID_DEBUG
40 #define CUVID_DPRINT(fmt, ...)                                          \
41     fprintf(stderr, "cuvid-utils: %s:%d " fmt "\n", __func__, __LINE__, \
42             ##__VA_ARGS__);
43 #else
44 #define CUVID_DPRINT(fmt, ...)
45 #endif
46 
47 #define NVDEC_API_CALL(cuvidAPI)                                      \
48     do {                                                              \
49         CUresult errorCode = cuvidAPI;                                \
50         if (errorCode != CUDA_SUCCESS) {                              \
51             CUVID_DPRINT("%s failed with error code %d\n", #cuvidAPI, \
52                          (int)errorCode);                             \
53         }                                                             \
54     } while (0)
55 
56 extern "C" {
57 
58 #define MEDIA_CUDA_COPY_Y_TEXTURE 1
59 #define MEDIA_CUDA_COPY_UV_TEXTURE 2
60 
media_cuda_copy_decoded_frame(void * privData,int mode,uint32_t dest_texture_handle)61 static void media_cuda_copy_decoded_frame(void* privData,
62                                           int mode,
63                                           uint32_t dest_texture_handle) {
64     media_cuda_utils_copy_context* copy_context =
65             static_cast<media_cuda_utils_copy_context*>(privData);
66 
67     const unsigned int GL_TEXTURE_2D = 0x0DE1;
68     const unsigned int cudaGraphicsMapFlagsNone = 0x0;
69     CUgraphicsResource CudaRes{0};
70     CUVID_DPRINT("cuda copy decoded frame testure %d",
71                  (int)dest_texture_handle);
72     NVDEC_API_CALL(cuGraphicsGLRegisterImage(&CudaRes, dest_texture_handle,
73                                              GL_TEXTURE_2D, 0x0));
74     CUarray texture_ptr;
75     NVDEC_API_CALL(cuGraphicsMapResources(1, &CudaRes, 0));
76     NVDEC_API_CALL(
77             cuGraphicsSubResourceGetMappedArray(&texture_ptr, CudaRes, 0, 0));
78     CUdeviceptr dpSrcFrame = copy_context->src_frame;
79     CUDA_MEMCPY2D m = {0};
80     m.srcMemoryType = CU_MEMORYTYPE_DEVICE;
81     m.srcDevice = dpSrcFrame;
82     m.srcPitch = copy_context->src_pitch;
83     m.dstMemoryType = CU_MEMORYTYPE_ARRAY;
84     m.dstArray = texture_ptr;
85     m.dstPitch = copy_context->dest_width * 1;
86     m.WidthInBytes = copy_context->dest_width * 1;
87     m.Height = copy_context->dest_height;
88     CUVID_DPRINT("dstPitch %d, WidthInBytes %d Height %d surface-height %d",
89                  (int)m.dstPitch, (int)m.WidthInBytes, (int)m.Height,
90                  (int)copy_context->src_surface_height);
91 
92     if (mode == MEDIA_CUDA_COPY_Y_TEXTURE) {  // copy Y data
93         NVDEC_API_CALL(cuMemcpy2D(&m));
94     } else if (mode == MEDIA_CUDA_COPY_UV_TEXTURE) {  // copy UV data
95         m.srcDevice =
96                 (CUdeviceptr)((uint8_t*)dpSrcFrame +
97                               m.srcPitch * copy_context->src_surface_height);
98         m.Height = m.Height / 2;
99         NVDEC_API_CALL(cuMemcpy2D(&m));
100     }
101     NVDEC_API_CALL(cuGraphicsUnmapResources(1, &CudaRes, 0));
102     NVDEC_API_CALL(cuGraphicsUnregisterResource(CudaRes));
103 }
104 
media_cuda_utils_nv12_updater(void * privData,uint32_t type,uint32_t * textures,void * callerData)105 void media_cuda_utils_nv12_updater(void* privData,
106                                    uint32_t type,
107                                    uint32_t* textures,
108                                    void* callerData) {
109     constexpr uint32_t kFRAMEWORK_FORMAT_NV12 = 3;
110     if (type != kFRAMEWORK_FORMAT_NV12) {
111         return;
112     }
113     CUVID_DPRINT("copyiong Ytex %d", textures[0]);
114     CUVID_DPRINT("copyiong UVtex %d", textures[1]);
115     media_cuda_copy_decoded_frame(privData, MEDIA_CUDA_COPY_Y_TEXTURE,
116                                   textures[0]);
117     media_cuda_copy_decoded_frame(privData, MEDIA_CUDA_COPY_UV_TEXTURE,
118                                   textures[1]);
119 }
120 
121 }  // end extern C
122