| /* |
| * Copyright 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <cutils/log.h> |
| #include <pthread.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| |
| #include <cerrno> |
| #include <cstring> |
| #include <fstream> |
| #include <string> |
| |
| #include "VirtGpuKumquat.h" |
| #include "virtgpu_gfxstream_protocol.h" |
| #include "virtgpu_kumquat/virtgpu_kumquat_ffi.h" |
| |
| #define PARAM(x) \ |
| (struct VirtGpuParam) { x, #x, 0 } |
| |
| static inline uint32_t align_up(uint32_t n, uint32_t a) { return ((n + a - 1) / a) * a; } |
| |
| VirtGpuKumquatDevice::VirtGpuKumquatDevice(enum VirtGpuCapset capset, int fd) |
| : VirtGpuDevice(capset) { |
| struct VirtGpuParam params[] = { |
| PARAM(VIRTGPU_KUMQUAT_PARAM_3D_FEATURES), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_CAPSET_QUERY_FIX), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_RESOURCE_BLOB), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_HOST_VISIBLE), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_CROSS_DEVICE), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_CONTEXT_INIT), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_SUPPORTED_CAPSET_IDs), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_EXPLICIT_DEBUG_NAME), |
| PARAM(VIRTGPU_KUMQUAT_PARAM_CREATE_GUEST_HANDLE), |
| }; |
| |
| int ret; |
| struct drm_kumquat_get_caps get_caps = {0}; |
| struct drm_kumquat_context_init init = {0}; |
| struct drm_kumquat_context_set_param ctx_set_params[3] = {{0}}; |
| const char* processName = nullptr; |
| |
| memset(&mCaps, 0, sizeof(struct VirtGpuCaps)); |
| |
| #ifdef __ANDROID__ |
| processName = getprogname(); |
| #endif |
| |
| ret = virtgpu_kumquat_init(&mVirtGpu); |
| if (ret) { |
| ALOGV("Failed to init virtgpu kumquat"); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < kParamMax; i++) { |
| struct drm_kumquat_getparam get_param = {0}; |
| get_param.param = params[i].param; |
| get_param.value = (uint64_t)(uintptr_t)¶ms[i].value; |
| |
| ret = virtgpu_kumquat_get_param(mVirtGpu, &get_param); |
| if (ret) { |
| ALOGV("virtgpu backend not enabling %s", params[i].name); |
| continue; |
| } |
| |
| mCaps.params[i] = params[i].value; |
| } |
| |
| get_caps.cap_set_id = static_cast<uint32_t>(capset); |
| switch (capset) { |
| case kCapsetGfxStreamVulkan: |
| get_caps.size = sizeof(struct vulkanCapset); |
| get_caps.addr = (unsigned long long)&mCaps.vulkanCapset; |
| break; |
| case kCapsetGfxStreamMagma: |
| get_caps.size = sizeof(struct magmaCapset); |
| get_caps.addr = (unsigned long long)&mCaps.magmaCapset; |
| break; |
| case kCapsetGfxStreamGles: |
| get_caps.size = sizeof(struct vulkanCapset); |
| get_caps.addr = (unsigned long long)&mCaps.glesCapset; |
| break; |
| case kCapsetGfxStreamComposer: |
| get_caps.size = sizeof(struct vulkanCapset); |
| get_caps.addr = (unsigned long long)&mCaps.composerCapset; |
| break; |
| default: |
| get_caps.size = 0; |
| } |
| |
| ret = virtgpu_kumquat_get_caps(mVirtGpu, &get_caps); |
| if (ret) { |
| // Don't fail get capabilities just yet, AEMU doesn't use this API |
| // yet (b/272121235); |
| ALOGE("DRM_IOCTL_VIRTGPU_KUMQUAT_GET_CAPS failed with %s", strerror(errno)); |
| } |
| |
| // We always need an ASG blob in some cases, so always define blobAlignment |
| if (!mCaps.vulkanCapset.blobAlignment) { |
| mCaps.vulkanCapset.blobAlignment = 4096; |
| } |
| |
| ctx_set_params[0].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_NUM_RINGS; |
| ctx_set_params[0].value = 2; |
| init.num_params = 1; |
| |
| if (capset != kCapsetNone) { |
| ctx_set_params[init.num_params].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_CAPSET_ID; |
| ctx_set_params[init.num_params].value = static_cast<uint32_t>(capset); |
| init.num_params++; |
| } |
| |
| if (mCaps.params[kParamExplicitDebugName] && processName) { |
| ctx_set_params[init.num_params].param = VIRTGPU_KUMQUAT_CONTEXT_PARAM_DEBUG_NAME; |
| ctx_set_params[init.num_params].value = reinterpret_cast<uint64_t>(processName); |
| init.num_params++; |
| } |
| |
| init.ctx_set_params = (unsigned long long)&ctx_set_params[0]; |
| ret = virtgpu_kumquat_context_init(mVirtGpu, &init); |
| if (ret) { |
| ALOGE( |
| "DRM_IOCTL_VIRTGPU_KUMQUAT_CONTEXT_INIT failed with %s, continuing without context...", |
| strerror(errno)); |
| } |
| } |
| |
| VirtGpuKumquatDevice::~VirtGpuKumquatDevice() { virtgpu_kumquat_finish(&mVirtGpu); } |
| |
| struct VirtGpuCaps VirtGpuKumquatDevice::getCaps(void) { return mCaps; } |
| |
| int64_t VirtGpuKumquatDevice::getDeviceHandle(void) { return -1; } |
| |
| VirtGpuResourcePtr VirtGpuKumquatDevice::createResource(uint32_t width, uint32_t height, |
| uint32_t virglFormat, uint32_t target, |
| uint32_t bind, uint32_t bpp) { |
| struct drm_kumquat_resource_create_3d create = { |
| .target = target, |
| .format = virglFormat, |
| .bind = bind, |
| .width = width, |
| .height = height, |
| .depth = 1U, |
| .array_size = 1U, |
| .last_level = 0, |
| .nr_samples = 0, |
| .size = width * height * bpp, |
| .stride = width * bpp, |
| }; |
| |
| int ret = virtgpu_kumquat_resource_create_3d(mVirtGpu, &create); |
| if (ret) { |
| ALOGE("DRM_IOCTL_VIRTGPU_KUMQUAT_RESOURCE_CREATE failed with %s", strerror(errno)); |
| return nullptr; |
| } |
| |
| return std::make_shared<VirtGpuKumquatResource>(mVirtGpu, create.bo_handle, create.res_handle, |
| static_cast<uint64_t>(create.size)); |
| } |
| |
| VirtGpuResourcePtr VirtGpuKumquatDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) { |
| int ret; |
| struct drm_kumquat_resource_create_blob create = {0}; |
| |
| create.size = blobCreate.size; |
| create.blob_mem = blobCreate.blobMem; |
| create.blob_flags = blobCreate.flags; |
| create.blob_id = blobCreate.blobId; |
| create.cmd = (uint64_t)(uintptr_t)blobCreate.blobCmd; |
| create.cmd_size = blobCreate.blobCmdSize; |
| |
| ret = virtgpu_kumquat_resource_create_blob(mVirtGpu, &create); |
| if (ret < 0) { |
| ALOGE("DRM_VIRTGPU_KUMQUAT_RESOURCE_CREATE_BLOB failed with %s", strerror(errno)); |
| return nullptr; |
| } |
| |
| return std::make_shared<VirtGpuKumquatResource>(mVirtGpu, create.bo_handle, create.res_handle, |
| blobCreate.size); |
| } |
| |
| VirtGpuResourcePtr VirtGpuKumquatDevice::importBlob(const struct VirtGpuExternalHandle& handle) { |
| int ret; |
| struct drm_kumquat_resource_import resource_import = {0}; |
| |
| resource_import.os_handle = static_cast<uint64_t>(handle.osHandle); |
| resource_import.handle_type = static_cast<uint32_t>(handle.type); |
| |
| ret = virtgpu_kumquat_resource_import(mVirtGpu, &resource_import); |
| if (ret < 0) { |
| ALOGE("DRM_VIRTGPU_KUMQUAT_RESOURCE_IMPORT failed with %s", strerror(errno)); |
| return nullptr; |
| } |
| |
| return std::make_shared<VirtGpuKumquatResource>( |
| mVirtGpu, resource_import.bo_handle, resource_import.res_handle, resource_import.size); |
| return nullptr; |
| } |
| |
| int VirtGpuKumquatDevice::execBuffer(struct VirtGpuExecBuffer& execbuffer, |
| const VirtGpuResource* blob) { |
| int ret; |
| struct drm_kumquat_execbuffer exec = {0}; |
| uint32_t blobHandle; |
| |
| exec.flags = execbuffer.flags; |
| exec.size = execbuffer.command_size; |
| exec.ring_idx = execbuffer.ring_idx; |
| exec.command = (uint64_t)(uintptr_t)(execbuffer.command); |
| exec.fence_fd = -1; |
| |
| if (blob) { |
| blobHandle = blob->getBlobHandle(); |
| exec.bo_handles = (uint64_t)(uintptr_t)(&blobHandle); |
| exec.num_bo_handles = 1; |
| } |
| |
| ret = virtgpu_kumquat_execbuffer(mVirtGpu, &exec); |
| if (ret) { |
| ALOGE("DRM_IOCTL_VIRTGPU_KUMQUAT_EXECBUFFER failed: %s", strerror(errno)); |
| return ret; |
| } |
| |
| if (execbuffer.flags & kFenceOut) { |
| execbuffer.handle.osHandle = exec.fence_fd; |
| execbuffer.handle.type = kFenceHandleSyncFd; |
| } |
| |
| return 0; |
| } |
| |
| VirtGpuDevice* createPlatformVirtGpuDevice(enum VirtGpuCapset capset, int fd) { |
| return new VirtGpuKumquatDevice(capset, fd); |
| } |