1 /*
2  * Copyright (C) 2021 The Android Open Source Project
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 <inttypes.h>
17 #include <android-base/parseint.h>
18 #include <android-base/properties.h>
19 #include <android-base/strings.h>
20 #include <log/log.h>
21 #include <gralloc_cb_bp.h>
22 #include <cb_handle_30.h>
23 #include <xf86drm.h>
24 
25 #include <C2AllocatorGralloc.h>
26 
27 #include "cros_gralloc_handle.h"
28 #include "virtgpu_drm.h"
29 
isMinigbmFromProperty()30 static bool isMinigbmFromProperty() {
31   static constexpr const auto kGrallocProp = "ro.hardware.gralloc";
32 
33   const auto grallocProp = android::base::GetProperty(kGrallocProp, "");
34   ALOGD("%s:codecs: minigbm query prop value is: %s", __FUNCTION__, grallocProp.c_str());
35 
36   if (grallocProp == "minigbm") {
37     ALOGD("%s:codecs: Using minigbm, in minigbm mode.\n", __FUNCTION__);
38     return true;
39   } else {
40     ALOGD("%s:codecs: Is not using minigbm, in goldfish mode.\n", __FUNCTION__);
41     return false;
42   }
43 }
44 
45 class ColorBufferUtilsGlobalState {
46 public:
ColorBufferUtilsGlobalState()47     ColorBufferUtilsGlobalState() {
48         m_isMinigbm = isMinigbmFromProperty();
49 
50         if (m_isMinigbm) {
51             static constexpr int kRendernodeMinor = 128;
52             m_rendernodeFd = drmOpenRender(kRendernodeMinor);
53         }
54     }
55 
getColorBufferHandle(native_handle_t const * handle)56     uint32_t getColorBufferHandle(native_handle_t const* handle) {
57         if (m_isMinigbm) {
58             struct drm_virtgpu_resource_info info;
59             if (!getResInfo(handle, &info)) {
60                 ALOGE("%s: Error gtting color buffer handle (minigbm case)", __func__);
61                 return -1;
62             }
63             return info.res_handle;
64         } else {
65             return cb_handle_t::from(handle)->hostHandle;
66         }
67     }
68 
getClientUsage(const std::shared_ptr<C2BlockPool> & pool)69     uint64_t getClientUsage(const std::shared_ptr<C2BlockPool> &pool) {
70         std::shared_ptr<C2GraphicBlock> myOutBlock;
71         const C2MemoryUsage usage = {0, 0};
72         const uint32_t format = HAL_PIXEL_FORMAT_YV12;
73         pool->fetchGraphicBlock(2, 2, format, usage, &myOutBlock);
74         auto myc2Handle = myOutBlock->handle();
75         native_handle_t *mygrallocHandle =
76         android::UnwrapNativeCodec2GrallocHandle(myc2Handle);
77         if (m_isMinigbm) {
78             cros_gralloc_handle const* cros_handle =
79                 reinterpret_cast<cros_gralloc_handle const*>(mygrallocHandle);
80             return cros_handle->usage;
81         } else {
82             cb_handle_30_t* mycb = (cb_handle_30_t*)(mygrallocHandle);
83             return mycb->usage;
84         }
85     }
86 
87 private:
88 
getResInfo(native_handle_t const * handle,struct drm_virtgpu_resource_info * info)89     bool getResInfo(native_handle_t const* handle,
90                     struct drm_virtgpu_resource_info* info) {
91         memset(info, 0x0, sizeof(*info));
92         if (m_rendernodeFd < 0) {
93             ALOGE("%s: Error, rendernode fd missing\n", __func__);
94             return false;
95         }
96 
97         struct drm_gem_close gem_close;
98         memset(&gem_close, 0x0, sizeof(gem_close));
99 
100         cros_gralloc_handle const* cros_handle =
101             reinterpret_cast<cros_gralloc_handle const*>(handle);
102 
103         uint32_t prime_handle;
104         int ret = drmPrimeFDToHandle(m_rendernodeFd, cros_handle->fds[0], &prime_handle);
105         if (ret) {
106             ALOGE("%s: DRM_IOCTL_PRIME_FD_TO_HANDLE failed: %s (errno %d)\n",
107                   __func__, strerror(errno), errno);
108             return false;
109         }
110 
111         info->bo_handle = prime_handle;
112         gem_close.handle = prime_handle;
113 
114         ret = drmIoctl(m_rendernodeFd, DRM_IOCTL_VIRTGPU_RESOURCE_INFO, info);
115         if (ret) {
116             ALOGE("%s: DRM_IOCTL_VIRTGPU_RESOURCE_INFO failed: %s (errno %d)\n",
117                   __func__, strerror(errno), errno);
118             drmIoctl(m_rendernodeFd, DRM_IOCTL_GEM_CLOSE, &gem_close);
119             return false;
120         }
121 
122         drmIoctl(m_rendernodeFd, DRM_IOCTL_GEM_CLOSE, &gem_close);
123         return true;
124     }
125 
126     bool m_isMinigbm;
127     int m_rendernodeFd = -1; // to be closed when this process dies
128 };
129 
getGlobals()130 static ColorBufferUtilsGlobalState* getGlobals() {
131     static ColorBufferUtilsGlobalState* globals = new ColorBufferUtilsGlobalState;
132     return globals;
133 }
134 
getColorBufferHandle(native_handle_t const * handle)135 uint32_t getColorBufferHandle(native_handle_t const* handle) {
136     return getGlobals()->getColorBufferHandle(handle);
137 }
138 
getClientUsage(const std::shared_ptr<C2BlockPool> & pool)139 uint64_t getClientUsage(const std::shared_ptr<C2BlockPool> &pool) {
140     return getGlobals()->getClientUsage(pool);
141 }
142 
143