From 36d09f70ce75eef33b044a99639eb22010becdc1 Mon Sep 17 00:00:00 2001 From: C Stout Date: Sun, 25 Feb 2024 09:55:09 -0800 Subject: [PATCH] [guest] Fuchsia: open magma device Reviewed-by: Aaron Ruby Acked-by: Yonggang Luo Acked-by: Adam Jackson Part-of: --- .../guest/platform/fuchsia/FuchsiaVirtGpu.h | 7 +- .../platform/fuchsia/FuchsiaVirtGpuDevice.cpp | 63 +++++++++-- .../platform/fuchsia/os_dirent_fuchsia.cpp | 104 ++++++++++++++++++ 3 files changed, 165 insertions(+), 9 deletions(-) create mode 100644 src/gfxstream/guest/platform/fuchsia/os_dirent_fuchsia.cpp diff --git a/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpu.h b/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpu.h index 10f6d40387f..eef3e5c59e4 100644 --- a/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpu.h +++ b/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpu.h @@ -16,6 +16,8 @@ #pragma once +#include + #include "VirtGpu.h" class FuchsiaVirtGpuBlob : public std::enable_shared_from_this, @@ -46,7 +48,7 @@ class FuchsiaVirtGpuBlobMapping : public VirtGpuBlobMapping { class FuchsiaVirtGpuDevice : public VirtGpuDevice { public: - FuchsiaVirtGpuDevice(enum VirtGpuCapset capset); + FuchsiaVirtGpuDevice(enum VirtGpuCapset capset, magma_device_t device); ~FuchsiaVirtGpuDevice(); int64_t getDeviceHandle(void) override; @@ -58,4 +60,7 @@ class FuchsiaVirtGpuDevice : public VirtGpuDevice { VirtGpuBlobPtr importBlob(const struct VirtGpuExternalHandle& handle) override; int execBuffer(struct VirtGpuExecBuffer& execbuffer, const VirtGpuBlob* blob) override; + + private: + magma_device_t device_; }; diff --git a/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpuDevice.cpp b/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpuDevice.cpp index d6964f5eb3e..000ebb3247a 100644 --- a/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpuDevice.cpp +++ b/src/gfxstream/guest/platform/fuchsia/FuchsiaVirtGpuDevice.cpp @@ -15,18 +15,22 @@ */ #include -#include +#include +#include +#include + +#include +#include +#include #include "FuchsiaVirtGpu.h" -FuchsiaVirtGpuDevice::FuchsiaVirtGpuDevice(enum VirtGpuCapset capset) : VirtGpuDevice(capset) {} +FuchsiaVirtGpuDevice::FuchsiaVirtGpuDevice(enum VirtGpuCapset capset, magma_device_t device) + : VirtGpuDevice(capset), device_(device) {} -FuchsiaVirtGpuDevice::~FuchsiaVirtGpuDevice() {} +FuchsiaVirtGpuDevice::~FuchsiaVirtGpuDevice() { magma_device_release(device_); } -int64_t FuchsiaVirtGpuDevice::getDeviceHandle(void) { - ALOGE("%s: unimplemented", __func__); - return 0; -} +int64_t FuchsiaVirtGpuDevice::getDeviceHandle(void) { return device_; } VirtGpuBlobPtr FuchsiaVirtGpuDevice::createBlob(const struct VirtGpuCreateBlob& blobCreate) { ALOGE("%s: unimplemented", __func__); @@ -57,6 +61,49 @@ VirtGpuDevice* createPlatformVirtGpuDevice(enum VirtGpuCapset capset, int fd) { if (fd >= 0) { ALOGE("Fuchsia: fd not handled"); abort(); + return nullptr; } - return new FuchsiaVirtGpuDevice(capset); + + const char kDevGpu[] = "/loader-gpu-devices/class/gpu"; + + struct os_dirent* de; + os_dir_t* dir = os_opendir(kDevGpu); + if (!dir) { + ALOGE("Error opening %s", kDevGpu); + return nullptr; + } + + ALOGD("Opened dir %s", kDevGpu); + + VirtGpuDevice* gpu_device = nullptr; + + while ((de = os_readdir(dir)) != NULL) { + ALOGD("Got name %s", de->d_name); + + if (strcmp(de->d_name, ".") == 0) { + continue; + } + // extra +1 ensures space for null termination + char name[sizeof(kDevGpu) + sizeof('/') + sizeof(de->d_name) + 1]; + snprintf(name, sizeof(name), "%s/%s", kDevGpu, de->d_name); + + zx_handle_t device_channel = GetConnectToServiceFunction()(name); + if (device_channel == ZX_HANDLE_INVALID) { + ALOGE("Failed to open device: %s", name); + continue; + } + + magma_device_t magma_device; + magma_status_t status = magma_device_import(device_channel, &magma_device); + if (status != MAGMA_STATUS_OK) { + ALOGE("magma_device_import failed: %d", status); + continue; + } + + gpu_device = new FuchsiaVirtGpuDevice(capset, magma_device); + break; + } + os_closedir(dir); + + return gpu_device; } diff --git a/src/gfxstream/guest/platform/fuchsia/os_dirent_fuchsia.cpp b/src/gfxstream/guest/platform/fuchsia/os_dirent_fuchsia.cpp new file mode 100644 index 00000000000..c009c96d11d --- /dev/null +++ b/src/gfxstream/guest/platform/fuchsia/os_dirent_fuchsia.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2024 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 +#include +#include +#include + +#include "os_dirent.h" + +struct os_dir { + ~os_dir() { + if (dir_iterator_init_) { + zxio_dirent_iterator_destroy(&iterator_); + } + if (zxio_init_) { + zxio_close(&io_storage_.io, /*should_wait=*/true); + } + } + + // Always consumes |dir_channel| + bool Init(zx_handle_t dir_channel) { + zx_status_t status = zxio_create(dir_channel, &io_storage_); + if (status != ZX_OK) { + ALOGE("zxio_create failed: %d", status); + return false; + } + + zxio_init_ = true; + + status = zxio_dirent_iterator_init(&iterator_, &io_storage_.io); + if (status != ZX_OK) { + ALOGE("zxio_dirent_iterator_init failed: %d", status); + return false; + } + + dir_iterator_init_ = true; + return true; + } + + bool Next(struct os_dirent* entry) { + // dirent is an in-out parameter. + // name must be initialized to point to a buffer of at least ZXIO_MAX_FILENAME bytes. + static_assert(sizeof(entry->d_name) >= ZXIO_MAX_FILENAME); + zxio_dirent_t dirent = {.name = entry->d_name}; + + zx_status_t status = zxio_dirent_iterator_next(&iterator_, &dirent); + if (status != ZX_OK) { + if (status != ZX_ERR_NOT_FOUND) ALOGE("zxio_dirent_iterator_next failed: %d", status); + return false; + } + + entry->d_ino = dirent.has.id ? dirent.id : OS_INO_UNKNOWN; + entry->d_name[dirent.name_length] = '\0'; + + return true; + } + + private: + bool zxio_init_ = false; + bool dir_iterator_init_ = false; + zxio_storage_t io_storage_; + zxio_dirent_iterator_t iterator_; +}; + +os_dir_t* os_opendir(const char* path) { + zx_handle_t dir_channel = GetConnectToServiceFunction()(path); + if (dir_channel == ZX_HANDLE_INVALID) { + ALOGE("fuchsia_open(%s) failed", path); + return nullptr; + } + + auto dir = new os_dir(); + + if (!dir->Init(dir_channel)) { + delete dir; + return nullptr; + } + + return dir; +} + +int os_closedir(os_dir_t* dir) { + delete dir; + return 0; +} + +struct os_dirent* os_readdir(os_dir_t* dir) { + static struct os_dirent dirent = {}; + return reinterpret_cast(dir->Next(&dirent)) ? &dirent : nullptr; +}