1 /*
2 * Copyright 2022 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
17 #include <fcntl.h>
18 #include <sys/mman.h>
19 #include <unistd.h>
20 #include <xf86drm.h>
21 #include <cerrno>
22 #include <cstring>
23
24 #include <cutils/log.h>
25
26 #include "VirtGpu.h"
27 #include "virtgpu_drm.h"
28
VirtGpuBlob(int64_t deviceHandle,uint32_t blobHandle,uint32_t resourceHandle,uint64_t size)29 VirtGpuBlob::VirtGpuBlob(int64_t deviceHandle, uint32_t blobHandle, uint32_t resourceHandle,
30 uint64_t size)
31 : mDeviceHandle(deviceHandle),
32 mBlobHandle(blobHandle),
33 mResourceHandle(resourceHandle),
34 mSize(size) {}
35
~VirtGpuBlob(void)36 VirtGpuBlob::~VirtGpuBlob(void) {
37 struct drm_gem_close gem_close {
38 .handle = mBlobHandle, .pad = 0,
39 };
40
41 int ret = drmIoctl(mDeviceHandle, DRM_IOCTL_GEM_CLOSE, &gem_close);
42 if (ret) {
43 ALOGE("DRM_IOCTL_GEM_CLOSE failed with : [%s, blobHandle %u, resourceHandle: %u]",
44 strerror(errno), mBlobHandle, mResourceHandle);
45 }
46 }
47
getBlobHandle(void)48 uint32_t VirtGpuBlob::getBlobHandle(void) {
49 return mBlobHandle;
50 }
51
getResourceHandle(void)52 uint32_t VirtGpuBlob::getResourceHandle(void) {
53 return mResourceHandle;
54 }
55
createMapping(void)56 VirtGpuBlobMappingPtr VirtGpuBlob::createMapping(void) {
57 int ret;
58 struct drm_virtgpu_map map {
59 .handle = mBlobHandle, .pad = 0,
60 };
61
62 ret = drmIoctl(mDeviceHandle, DRM_IOCTL_VIRTGPU_MAP, &map);
63 if (ret) {
64 ALOGE("DRM_IOCTL_VIRTGPU_MAP failed with %s", strerror(errno));
65 return nullptr;
66 }
67
68 uint8_t* ptr = static_cast<uint8_t*>(
69 mmap64(nullptr, mSize, PROT_WRITE | PROT_READ, MAP_SHARED, mDeviceHandle, map.offset));
70
71 if (ptr == MAP_FAILED) {
72 ALOGE("mmap64 failed with (%s)", strerror(errno));
73 return nullptr;
74 }
75
76 return std::make_shared<VirtGpuBlobMapping>(shared_from_this(), ptr, mSize);
77 }
78
exportBlob(struct VirtGpuExternalHandle & handle)79 int VirtGpuBlob::exportBlob(struct VirtGpuExternalHandle& handle) {
80 int ret, fd;
81
82 ret = drmPrimeHandleToFD(mDeviceHandle, mBlobHandle, DRM_CLOEXEC | DRM_RDWR, &fd);
83 if (ret) {
84 ALOGE("drmPrimeHandleToFD failed with %s", strerror(errno));
85 return ret;
86 }
87
88 handle.osHandle = static_cast<int64_t>(fd);
89 handle.type = kMemHandleDmabuf;
90 return 0;
91 }
92
wait()93 int VirtGpuBlob::wait() {
94 int ret;
95 struct drm_virtgpu_3d_wait wait_3d = {0};
96
97 int retry = 0;
98 do {
99 if (retry > 0 && (retry % 10 == 0)) {
100 ALOGE("DRM_IOCTL_VIRTGPU_WAIT failed with EBUSY for %d times.", retry);
101 }
102 wait_3d.handle = mBlobHandle;
103 ret = drmIoctl(mDeviceHandle, DRM_IOCTL_VIRTGPU_WAIT, &wait_3d);
104 ++retry;
105 } while (ret < 0 && errno == EBUSY);
106
107 if (ret < 0) {
108 ALOGE("DRM_IOCTL_VIRTGPU_WAIT failed with %s", strerror(errno));
109 return ret;
110 }
111
112 return 0;
113 }
114