blob: 13c7698ee7714bffced895fa5e0a70ee4900da4d [file] [log] [blame]
// Copyright (C) 2018 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 <errno.h>
#include <hardware/hwvulkan.h>
#include <log/log.h>
#include <string.h>
#ifdef VK_USE_PLATFORM_FUCHSIA
#include <fidl/fuchsia.logger/cpp/wire.h>
#include <lib/syslog/structured_backend/cpp/fuchsia_syslog.h>
#include <lib/zx/channel.h>
#include <lib/zx/socket.h>
#include <lib/zxio/zxio.h>
#include <unistd.h>
#include <zircon/system/public/zircon/process.h>
#include <cstdarg>
#include "TraceProviderFuchsia.h"
#include "services/service_connector.h"
#endif
#include "HostConnection.h"
#include "ProcessPipe.h"
#include "ResourceTracker.h"
#include "VkEncoder.h"
#include "func_table.h"
// Used when there is no Vulkan support on the host.
// Copied from frameworks/native/vulkan/libvulkan/stubhal.cpp
namespace vkstubhal {
[[noreturn]] VKAPI_ATTR void NoOp() { LOG_ALWAYS_FATAL("invalid stub function called"); }
VkResult EnumerateInstanceExtensionProperties(const char* /*layer_name*/, uint32_t* count,
VkExtensionProperties* /*properties*/) {
AEMU_SCOPED_TRACE("vkstubhal::EnumerateInstanceExtensionProperties");
*count = 0;
return VK_SUCCESS;
}
VkResult EnumerateInstanceLayerProperties(uint32_t* count, VkLayerProperties* /*properties*/) {
AEMU_SCOPED_TRACE("vkstubhal::EnumerateInstanceLayerProperties");
*count = 0;
return VK_SUCCESS;
}
VkResult CreateInstance(const VkInstanceCreateInfo* /*create_info*/,
const VkAllocationCallbacks* /*allocator*/, VkInstance* instance) {
AEMU_SCOPED_TRACE("vkstubhal::CreateInstance");
auto dispatch = new hwvulkan_dispatch_t;
dispatch->magic = HWVULKAN_DISPATCH_MAGIC;
*instance = reinterpret_cast<VkInstance>(dispatch);
return VK_SUCCESS;
}
void DestroyInstance(VkInstance instance, const VkAllocationCallbacks* /*allocator*/) {
AEMU_SCOPED_TRACE("vkstubhal::DestroyInstance");
auto dispatch = reinterpret_cast<hwvulkan_dispatch_t*>(instance);
ALOG_ASSERT(dispatch->magic == HWVULKAN_DISPATCH_MAGIC,
"DestroyInstance: invalid instance handle");
delete dispatch;
}
VkResult EnumeratePhysicalDevices(VkInstance /*instance*/, uint32_t* count,
VkPhysicalDevice* /*gpus*/) {
AEMU_SCOPED_TRACE("vkstubhal::EnumeratePhysicalDevices");
*count = 0;
return VK_SUCCESS;
}
VkResult EnumerateInstanceVersion(uint32_t* pApiVersion) {
AEMU_SCOPED_TRACE("vkstubhal::EnumerateInstanceVersion");
*pApiVersion = VK_API_VERSION_1_0;
return VK_SUCCESS;
}
VkResult EnumeratePhysicalDeviceGroups(VkInstance /*instance*/, uint32_t* count,
VkPhysicalDeviceGroupProperties* /*properties*/) {
AEMU_SCOPED_TRACE("vkstubhal::EnumeratePhysicalDeviceGroups");
*count = 0;
return VK_SUCCESS;
}
VkResult CreateDebugReportCallbackEXT(VkInstance /*instance*/,
const VkDebugReportCallbackCreateInfoEXT* /*pCreateInfo*/,
const VkAllocationCallbacks* /*pAllocator*/,
VkDebugReportCallbackEXT* pCallback) {
AEMU_SCOPED_TRACE("vkstubhal::CreateDebugReportCallbackEXT");
*pCallback = VK_NULL_HANDLE;
return VK_SUCCESS;
}
void DestroyDebugReportCallbackEXT(VkInstance /*instance*/, VkDebugReportCallbackEXT /*callback*/,
const VkAllocationCallbacks* /*pAllocator*/) {
AEMU_SCOPED_TRACE("vkstubhal::DestroyDebugReportCallbackEXT");
}
void DebugReportMessageEXT(VkInstance /*instance*/, VkDebugReportFlagsEXT /*flags*/,
VkDebugReportObjectTypeEXT /*objectType*/, uint64_t /*object*/,
size_t /*location*/, int32_t /*messageCode*/,
const char* /*pLayerPrefix*/, const char* /*pMessage*/) {
AEMU_SCOPED_TRACE("vkstubhal::DebugReportMessageEXT");
}
VkResult CreateDebugUtilsMessengerEXT(VkInstance /*instance*/,
const VkDebugUtilsMessengerCreateInfoEXT* /*pCreateInfo*/,
const VkAllocationCallbacks* /*pAllocator*/,
VkDebugUtilsMessengerEXT* pMessenger) {
AEMU_SCOPED_TRACE("vkstubhal::CreateDebugUtilsMessengerEXT");
*pMessenger = VK_NULL_HANDLE;
return VK_SUCCESS;
}
void DestroyDebugUtilsMessengerEXT(VkInstance /*instance*/, VkDebugUtilsMessengerEXT /*messenger*/,
const VkAllocationCallbacks* /*pAllocator*/) {
AEMU_SCOPED_TRACE("vkstubhal::DestroyDebugUtilsMessengerkEXT");
}
void SubmitDebugUtilsMessageEXT(VkInstance /*instance*/,
VkDebugUtilsMessageSeverityFlagBitsEXT /*messageSeverity*/,
VkDebugUtilsMessageTypeFlagsEXT /*messageTypes*/,
const VkDebugUtilsMessengerCallbackDataEXT* /*pCallbackData*/) {
AEMU_SCOPED_TRACE("vkstubhal::SubmitDebugUtilsMessageEXT");
}
#ifdef VK_USE_PLATFORM_FUCHSIA
VkResult GetMemoryZirconHandleFUCHSIA(VkDevice /*device*/,
const VkMemoryGetZirconHandleInfoFUCHSIA* /*pInfo*/,
uint32_t* pHandle) {
AEMU_SCOPED_TRACE("vkstubhal::GetMemoryZirconHandleFUCHSIA");
*pHandle = 0;
return VK_SUCCESS;
}
VkResult GetMemoryZirconHandlePropertiesFUCHSIA(
VkDevice /*device*/, VkExternalMemoryHandleTypeFlagBits /*handleType*/, uint32_t /*handle*/,
VkMemoryZirconHandlePropertiesFUCHSIA* /*pProperties*/) {
AEMU_SCOPED_TRACE("vkstubhal::GetMemoryZirconHandlePropertiesFUCHSIA");
return VK_SUCCESS;
}
VkResult GetSemaphoreZirconHandleFUCHSIA(VkDevice /*device*/,
const VkSemaphoreGetZirconHandleInfoFUCHSIA* /*pInfo*/,
uint32_t* pHandle) {
AEMU_SCOPED_TRACE("vkstubhal::GetSemaphoreZirconHandleFUCHSIA");
*pHandle = 0;
return VK_SUCCESS;
}
VkResult ImportSemaphoreZirconHandleFUCHSIA(
VkDevice /*device*/, const VkImportSemaphoreZirconHandleInfoFUCHSIA* /*pInfo*/) {
AEMU_SCOPED_TRACE("vkstubhal::ImportSemaphoreZirconHandleFUCHSIA");
return VK_SUCCESS;
}
VkResult CreateBufferCollectionFUCHSIA(VkDevice /*device*/,
const VkBufferCollectionCreateInfoFUCHSIA* /*pInfo*/,
const VkAllocationCallbacks* /*pAllocator*/,
VkBufferCollectionFUCHSIA* /*pCollection*/) {
AEMU_SCOPED_TRACE("vkstubhal::CreateBufferCollectionFUCHSIA");
return VK_SUCCESS;
}
void DestroyBufferCollectionFUCHSIA(VkDevice /*device*/, VkBufferCollectionFUCHSIA /*collection*/,
const VkAllocationCallbacks* /*pAllocator*/) {
AEMU_SCOPED_TRACE("vkstubhal::DestroyBufferCollectionFUCHSIA");
}
VkResult SetBufferCollectionImageConstraintsFUCHSIA(
VkDevice /*device*/, VkBufferCollectionFUCHSIA /*collection*/,
const VkImageConstraintsInfoFUCHSIA* /*pImageConstraintsInfo*/) {
AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionImageConstraintsFUCHSIA");
return VK_SUCCESS;
}
VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
VkDevice /*device*/, VkBufferCollectionFUCHSIA /*collection*/,
const VkBufferConstraintsInfoFUCHSIA* /*pBufferConstraintsInfo*/) {
AEMU_SCOPED_TRACE("vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA");
return VK_SUCCESS;
}
VkResult GetBufferCollectionPropertiesFUCHSIA(
VkDevice /*device*/, VkBufferCollectionFUCHSIA /*collection*/,
VkBufferCollectionPropertiesFUCHSIA* /*pProperties*/) {
AEMU_SCOPED_TRACE("vkstubhal::GetBufferCollectionPropertiesFUCHSIA");
return VK_SUCCESS;
}
#endif
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
AEMU_SCOPED_TRACE("vkstubhal::GetInstanceProcAddr");
if (strcmp(name, "vkCreateInstance") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
if (strcmp(name, "vkDestroyInstance") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance);
if (strcmp(name, "vkEnumerateInstanceExtensionProperties") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties);
if (strcmp(name, "vkEnumeratePhysicalDevices") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices);
if (strcmp(name, "vkEnumerateInstanceVersion") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
if (strcmp(name, "vkEnumeratePhysicalDeviceGroups") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups);
if (strcmp(name, "vkEnumeratePhysicalDeviceGroupsKHR") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups);
if (strcmp(name, "vkGetInstanceProcAddr") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr);
if (strcmp(name, "vkCreateDebugReportCallbackEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugReportCallbackEXT);
if (strcmp(name, "vkDestroyDebugReportCallbackEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugReportCallbackEXT);
if (strcmp(name, "vkDebugReportMessageEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(DebugReportMessageEXT);
if (strcmp(name, "vkCreateDebugUtilsMessengerEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(CreateDebugUtilsMessengerEXT);
if (strcmp(name, "vkDestroyDebugUtilsMessengerEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(DestroyDebugUtilsMessengerEXT);
if (strcmp(name, "vkSubmitDebugUtilsMessageEXT") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(SubmitDebugUtilsMessageEXT);
#ifdef VK_USE_PLATFORM_FUCHSIA
if (strcmp(name, "vkGetMemoryZirconHandleFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryZirconHandleFUCHSIA);
if (strcmp(name, "vkGetMemoryZirconHandlePropertiesFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetMemoryZirconHandlePropertiesFUCHSIA);
if (strcmp(name, "vkGetSemaphoreZirconHandleFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreZirconHandleFUCHSIA);
if (strcmp(name, "vkImportSemaphoreZirconHandleFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(ImportSemaphoreZirconHandleFUCHSIA);
if (strcmp(name, "vkCreateBufferCollectionFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(CreateBufferCollectionFUCHSIA);
if (strcmp(name, "vkDestroyBufferCollectionFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(DestroyBufferCollectionFUCHSIA);
if (strcmp(name, "vkSetBufferCollectionImageConstraintsFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionImageConstraintsFUCHSIA);
if (strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(SetBufferCollectionBufferConstraintsFUCHSIA);
if (strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(GetBufferCollectionPropertiesFUCHSIA);
#endif
// Return NoOp for entrypoints that should never be called.
if (strcmp(name, "vkGetPhysicalDeviceFeatures") == 0 ||
strcmp(name, "vkGetPhysicalDeviceProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceFormatProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceImageFormatProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceMemoryProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceQueueFamilyProperties") == 0 ||
strcmp(name, "vkGetDeviceProcAddr") == 0 || strcmp(name, "vkCreateDevice") == 0 ||
strcmp(name, "vkEnumerateDeviceExtensionProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceSparseImageFormatProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceFeatures2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceFormatProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceImageFormatProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceQueueFamilyProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceMemoryProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceSparseImageFormatProperties2") == 0 ||
strcmp(name, "vkGetPhysicalDeviceExternalBufferProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceExternalFenceProperties") == 0 ||
strcmp(name, "vkGetPhysicalDeviceExternalSemaphoreProperties") == 0)
return reinterpret_cast<PFN_vkVoidFunction>(NoOp);
// Per the spec, return NULL for nonexistent entrypoints.
return nullptr;
}
} // namespace vkstubhal
namespace {
#ifdef VK_USE_PLATFORM_ANDROID_KHR
int OpenDevice(const hw_module_t* module, const char* id, hw_device_t** device);
hw_module_methods_t goldfish_vulkan_module_methods = {.open = OpenDevice};
extern "C" __attribute__((visibility("default"))) hwvulkan_module_t HAL_MODULE_INFO_SYM = {
.common =
{
.tag = HARDWARE_MODULE_TAG,
.module_api_version = HWVULKAN_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = HWVULKAN_HARDWARE_MODULE_ID,
.name = "Goldfish Vulkan Driver",
.author = "The Android Open Source Project",
.methods = &goldfish_vulkan_module_methods,
},
};
int CloseDevice(struct hw_device_t* /*device*/) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetInstanceProcAddr");
// nothing to do - opening a device doesn't allocate any resources
return 0;
}
#endif
#define VK_HOST_CONNECTION(ret) \
HostConnection* hostCon = HostConnection::getOrCreate(VIRTIO_GPU_CAPSET_GFXSTREAM); \
if (!hostCon) { \
ALOGE("vulkan: Failed to get host connection\n"); \
return ret; \
} \
ExtendedRCEncoderContext* rcEnc = hostCon->rcEncoder(); \
if (!rcEnc) { \
ALOGE("vulkan: Failed to get renderControl encoder context\n"); \
return ret; \
} \
goldfish_vk::ResourceTracker::ThreadingCallbacks threadingCallbacks = { \
[] { \
auto hostCon = HostConnection::get(); \
hostCon->rcEncoder(); \
return hostCon; \
}, \
[](HostConnection* hostCon) { return hostCon->vkEncoder(); }, \
}; \
goldfish_vk::ResourceTracker::get()->setThreadingCallbacks(threadingCallbacks); \
goldfish_vk::ResourceTracker::get()->setupFeatures(rcEnc->featureInfo_const()); \
goldfish_vk::ResourceTracker::get()->setSeqnoPtr(getSeqnoPtrForProcess()); \
auto hostSupportsVulkan = goldfish_vk::ResourceTracker::get()->hostSupportsVulkan(); \
goldfish_vk::VkEncoder* vkEnc = hostCon->vkEncoder(); \
if (!vkEnc) { \
ALOGE("vulkan: Failed to get Vulkan encoder\n"); \
return ret; \
}
VKAPI_ATTR
VkResult EnumerateInstanceExtensionProperties(const char* layer_name, uint32_t* count,
VkExtensionProperties* properties) {
AEMU_SCOPED_TRACE("goldfish_vulkan::EnumerateInstanceExtensionProperties");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::EnumerateInstanceExtensionProperties(layer_name, count, properties);
}
if (layer_name) {
ALOGW(
"Driver vkEnumerateInstanceExtensionProperties shouldn't be called "
"with a layer name ('%s')",
layer_name);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkEnumerateInstanceExtensionProperties(
vkEnc, VK_SUCCESS, layer_name, count, properties);
return res;
}
VKAPI_ATTR
VkResult CreateInstance(const VkInstanceCreateInfo* create_info,
const VkAllocationCallbacks* allocator, VkInstance* out_instance) {
AEMU_SCOPED_TRACE("goldfish_vulkan::CreateInstance");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::CreateInstance(create_info, allocator, out_instance);
}
VkResult res = vkEnc->vkCreateInstance(create_info, nullptr, out_instance, true /* do lock */);
return res;
}
#ifdef VK_USE_PLATFORM_FUCHSIA
VKAPI_ATTR
VkResult GetMemoryZirconHandleFUCHSIA(VkDevice device,
const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
uint32_t* pHandle) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetMemoryZirconHandleFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::GetMemoryZirconHandleFUCHSIA(device, pInfo, pHandle);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkGetMemoryZirconHandleFUCHSIA(
vkEnc, VK_SUCCESS, device, pInfo, pHandle);
return res;
}
VKAPI_ATTR
VkResult GetMemoryZirconHandlePropertiesFUCHSIA(
VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, uint32_t handle,
VkMemoryZirconHandlePropertiesFUCHSIA* pProperties) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetMemoryZirconHandlePropertiesFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::GetMemoryZirconHandlePropertiesFUCHSIA(device, handleType, handle,
pProperties);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
vkEnc, VK_SUCCESS, device, handleType, handle, pProperties);
return res;
}
VKAPI_ATTR
VkResult GetSemaphoreZirconHandleFUCHSIA(VkDevice device,
const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
uint32_t* pHandle) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetSemaphoreZirconHandleFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::GetSemaphoreZirconHandleFUCHSIA(device, pInfo, pHandle);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkGetSemaphoreZirconHandleFUCHSIA(
vkEnc, VK_SUCCESS, device, pInfo, pHandle);
return res;
}
VKAPI_ATTR
VkResult ImportSemaphoreZirconHandleFUCHSIA(VkDevice device,
const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo) {
AEMU_SCOPED_TRACE("goldfish_vulkan::ImportSemaphoreZirconHandleFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::ImportSemaphoreZirconHandleFUCHSIA(device, pInfo);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkImportSemaphoreZirconHandleFUCHSIA(
vkEnc, VK_SUCCESS, device, pInfo);
return res;
}
VKAPI_ATTR
VkResult CreateBufferCollectionFUCHSIA(VkDevice device,
const VkBufferCollectionCreateInfoFUCHSIA* pInfo,
const VkAllocationCallbacks* pAllocator,
VkBufferCollectionFUCHSIA* pCollection) {
AEMU_SCOPED_TRACE("goldfish_vulkan::CreateBufferCollectionFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::CreateBufferCollectionFUCHSIA(device, pInfo, pAllocator, pCollection);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkCreateBufferCollectionFUCHSIA(
vkEnc, VK_SUCCESS, device, pInfo, pAllocator, pCollection);
return res;
}
VKAPI_ATTR
void DestroyBufferCollectionFUCHSIA(VkDevice device, VkBufferCollectionFUCHSIA collection,
const VkAllocationCallbacks* pAllocator) {
AEMU_SCOPED_TRACE("goldfish_vulkan::DestroyBufferCollectionFUCHSIA");
VK_HOST_CONNECTION()
if (!hostSupportsVulkan) {
vkstubhal::DestroyBufferCollectionFUCHSIA(device, collection, pAllocator);
return;
}
goldfish_vk::ResourceTracker::get()->on_vkDestroyBufferCollectionFUCHSIA(
vkEnc, VK_SUCCESS, device, collection, pAllocator);
}
VKAPI_ATTR
VkResult SetBufferCollectionBufferConstraintsFUCHSIA(
VkDevice device, VkBufferCollectionFUCHSIA collection,
const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo) {
AEMU_SCOPED_TRACE("goldfish_vulkan::SetBufferCollectionBufferConstraintsFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::SetBufferCollectionBufferConstraintsFUCHSIA(device, collection,
pBufferConstraintsInfo);
}
VkResult res =
goldfish_vk::ResourceTracker::get()->on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
vkEnc, VK_SUCCESS, device, collection, pBufferConstraintsInfo);
return res;
}
VKAPI_ATTR
VkResult SetBufferCollectionImageConstraintsFUCHSIA(
VkDevice device, VkBufferCollectionFUCHSIA collection,
const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo) {
AEMU_SCOPED_TRACE("goldfish_vulkan::SetBufferCollectionBufferConstraintsFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::SetBufferCollectionImageConstraintsFUCHSIA(device, collection,
pImageConstraintsInfo);
}
VkResult res =
goldfish_vk::ResourceTracker::get()->on_vkSetBufferCollectionImageConstraintsFUCHSIA(
vkEnc, VK_SUCCESS, device, collection, pImageConstraintsInfo);
return res;
}
VKAPI_ATTR
VkResult GetBufferCollectionPropertiesFUCHSIA(VkDevice device, VkBufferCollectionFUCHSIA collection,
VkBufferCollectionPropertiesFUCHSIA* pProperties) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetBufferCollectionPropertiesFUCHSIA");
VK_HOST_CONNECTION(VK_ERROR_DEVICE_LOST)
if (!hostSupportsVulkan) {
return vkstubhal::GetBufferCollectionPropertiesFUCHSIA(device, collection, pProperties);
}
VkResult res = goldfish_vk::ResourceTracker::get()->on_vkGetBufferCollectionPropertiesFUCHSIA(
vkEnc, VK_SUCCESS, device, collection, pProperties);
return res;
}
#endif
uint64_t currGuestTimeNs() {
struct timespec ts;
#ifdef __APPLE__
clock_gettime(CLOCK_REALTIME, &ts);
#else
clock_gettime(CLOCK_BOOTTIME, &ts);
#endif
uint64_t res = (uint64_t)(ts.tv_sec * 1000000000ULL + ts.tv_nsec);
return res;
}
struct FrameTracingState {
uint32_t frameNumber = 0;
bool tracingEnabled = false;
void onSwapBuffersSuccessful(ExtendedRCEncoderContext* rcEnc) {
#ifdef GFXSTREAM
bool current = android::base::isTracingEnabled();
// edge trigger
if (current && !tracingEnabled) {
if (rcEnc->hasHostSideTracing()) {
rcEnc->rcSetTracingForPuid(rcEnc, getPuid(), 1, currGuestTimeNs());
}
}
if (!current && tracingEnabled) {
if (rcEnc->hasHostSideTracing()) {
rcEnc->rcSetTracingForPuid(rcEnc, getPuid(), 0, currGuestTimeNs());
}
}
tracingEnabled = current;
#endif
++frameNumber;
}
};
static FrameTracingState sFrameTracingState;
static PFN_vkVoidFunction sQueueSignalReleaseImageAndroidImpl = 0;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
static VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount,
const VkSemaphore* pWaitSemaphores, VkImage image,
int* pNativeFenceFd) {
sFrameTracingState.onSwapBuffersSuccessful(HostConnection::get()->rcEncoder());
((PFN_vkQueueSignalReleaseImageANDROID)sQueueSignalReleaseImageAndroidImpl)(
queue, waitSemaphoreCount, pWaitSemaphores, image, pNativeFenceFd);
return VK_SUCCESS;
}
#endif
static PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* name) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetDeviceProcAddr");
VK_HOST_CONNECTION(nullptr)
if (!hostSupportsVulkan) {
return nullptr;
}
#ifdef VK_USE_PLATFORM_FUCHSIA
if (!strcmp(name, "vkGetMemoryZirconHandleFUCHSIA")) {
return (PFN_vkVoidFunction)GetMemoryZirconHandleFUCHSIA;
}
if (!strcmp(name, "vkGetMemoryZirconHandlePropertiesFUCHSIA")) {
return (PFN_vkVoidFunction)GetMemoryZirconHandlePropertiesFUCHSIA;
}
if (!strcmp(name, "vkGetSemaphoreZirconHandleFUCHSIA")) {
return (PFN_vkVoidFunction)GetSemaphoreZirconHandleFUCHSIA;
}
if (!strcmp(name, "vkImportSemaphoreZirconHandleFUCHSIA")) {
return (PFN_vkVoidFunction)ImportSemaphoreZirconHandleFUCHSIA;
}
if (!strcmp(name, "vkCreateBufferCollectionFUCHSIA")) {
return (PFN_vkVoidFunction)CreateBufferCollectionFUCHSIA;
}
if (!strcmp(name, "vkDestroyBufferCollectionFUCHSIA")) {
return (PFN_vkVoidFunction)DestroyBufferCollectionFUCHSIA;
}
if (!strcmp(name, "vkSetBufferCollectionImageConstraintsFUCHSIA")) {
return (PFN_vkVoidFunction)SetBufferCollectionImageConstraintsFUCHSIA;
}
if (!strcmp(name, "vkSetBufferCollectionBufferConstraintsFUCHSIA")) {
return (PFN_vkVoidFunction)SetBufferCollectionBufferConstraintsFUCHSIA;
}
if (!strcmp(name, "vkGetBufferCollectionPropertiesFUCHSIA")) {
return (PFN_vkVoidFunction)GetBufferCollectionPropertiesFUCHSIA;
}
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
if (!strcmp(name, "vkQueueSignalReleaseImageANDROID")) {
if (!sQueueSignalReleaseImageAndroidImpl) {
sQueueSignalReleaseImageAndroidImpl =
(PFN_vkVoidFunction)(goldfish_vk::goldfish_vulkan_get_device_proc_address(
device, "vkQueueSignalReleaseImageANDROID"));
}
return (PFN_vkVoidFunction)QueueSignalReleaseImageANDROID;
}
#endif
if (!strcmp(name, "vkGetDeviceProcAddr")) {
return (PFN_vkVoidFunction)(GetDeviceProcAddr);
}
return (PFN_vkVoidFunction)(goldfish_vk::goldfish_vulkan_get_device_proc_address(device, name));
}
VKAPI_ATTR
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
AEMU_SCOPED_TRACE("goldfish_vulkan::GetInstanceProcAddr");
VK_HOST_CONNECTION(nullptr)
if (!hostSupportsVulkan) {
return vkstubhal::GetInstanceProcAddr(instance, name);
}
if (!strcmp(name, "vkEnumerateInstanceExtensionProperties")) {
return (PFN_vkVoidFunction)EnumerateInstanceExtensionProperties;
}
if (!strcmp(name, "vkCreateInstance")) {
return (PFN_vkVoidFunction)CreateInstance;
}
if (!strcmp(name, "vkGetDeviceProcAddr")) {
return (PFN_vkVoidFunction)(GetDeviceProcAddr);
}
#ifdef VK_USE_PLATFORM_ANDROID_KHR
if (!strcmp(name, "vkQueueSignalReleaseImageANDROID")) {
if (!sQueueSignalReleaseImageAndroidImpl) {
sQueueSignalReleaseImageAndroidImpl =
(PFN_vkVoidFunction)(goldfish_vk::goldfish_vulkan_get_instance_proc_address(
instance, "vkQueueSignalReleaseImageANDROID"));
}
return (PFN_vkVoidFunction)QueueSignalReleaseImageANDROID;
}
#endif
return (
PFN_vkVoidFunction)(goldfish_vk::goldfish_vulkan_get_instance_proc_address(instance, name));
}
#ifdef VK_USE_PLATFORM_ANDROID_KHR
hwvulkan_device_t goldfish_vulkan_device = {
.common =
{
.tag = HARDWARE_DEVICE_TAG,
.version = HWVULKAN_DEVICE_API_VERSION_0_1,
.module = &HAL_MODULE_INFO_SYM.common,
.close = CloseDevice,
},
.EnumerateInstanceExtensionProperties = EnumerateInstanceExtensionProperties,
.CreateInstance = CreateInstance,
.GetInstanceProcAddr = GetInstanceProcAddr,
};
int OpenDevice(const hw_module_t* /*module*/, const char* id, hw_device_t** device) {
AEMU_SCOPED_TRACE("goldfish_vulkan::OpenDevice");
if (strcmp(id, HWVULKAN_DEVICE_0) == 0) {
*device = &goldfish_vulkan_device.common;
goldfish_vk::ResourceTracker::get();
return 0;
}
return -ENOENT;
}
#elif VK_USE_PLATFORM_FUCHSIA
class VulkanDevice {
public:
VulkanDevice() : mHostSupportsGoldfish(IsAccessible(QEMU_PIPE_PATH)) {
InitLogger();
InitTraceProvider();
goldfish_vk::ResourceTracker::get();
}
static void InitLogger();
static bool IsAccessible(const char* name) {
zx_handle_t handle = GetConnectToServiceFunction()(name);
if (handle == ZX_HANDLE_INVALID) return false;
zxio_storage_t io_storage;
zx_status_t status = zxio_create(handle, &io_storage);
if (status != ZX_OK) return false;
status = zxio_close(&io_storage.io, /*should_wait=*/true);
if (status != ZX_OK) return false;
return true;
}
static VulkanDevice& GetInstance() {
static VulkanDevice g_instance;
return g_instance;
}
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
if (!mHostSupportsGoldfish) {
return vkstubhal::GetInstanceProcAddr(instance, name);
}
return ::GetInstanceProcAddr(instance, name);
}
private:
void InitTraceProvider();
TraceProviderFuchsia mTraceProvider;
const bool mHostSupportsGoldfish;
};
zx::socket g_log_socket = zx::socket(ZX_HANDLE_INVALID);
void VulkanDevice::InitLogger() {
auto log_socket = ([]() -> std::optional<zx::socket> {
fidl::ClientEnd<fuchsia_logger::LogSink> channel{
zx::channel{GetConnectToServiceFunction()("/svc/fuchsia.logger.LogSink")}};
if (!channel.is_valid()) return std::nullopt;
zx::socket local_socket, remote_socket;
zx_status_t status = zx::socket::create(ZX_SOCKET_DATAGRAM, &local_socket, &remote_socket);
if (status != ZX_OK) return std::nullopt;
auto result = fidl::WireCall(channel)->ConnectStructured(std::move(remote_socket));
if (!result.ok()) return std::nullopt;
return local_socket;
})();
if (!log_socket) return;
g_log_socket = std::move(*log_socket);
}
namespace {
zx_koid_t GetKoid(zx_handle_t handle) {
zx_info_handle_basic_t info;
zx_status_t status =
zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr);
return status == ZX_OK ? info.koid : ZX_KOID_INVALID;
}
static zx_koid_t pid = GetKoid(zx_process_self());
static thread_local zx_koid_t tid = GetKoid(zx_thread_self());
cpp17::optional<cpp17::string_view> CStringToStringView(const char* cstr) {
if (!cstr) {
return cpp17::nullopt;
}
return cstr;
}
const char* StripDots(const char* path) {
while (strncmp(path, "../", 3) == 0) {
path += 3;
}
return path;
}
const char* StripPath(const char* path) {
auto p = strrchr(path, '/');
if (p) {
return p + 1;
} else {
return path;
}
}
const char* StripFile(const char* file, FuchsiaLogSeverity severity) {
return severity > FUCHSIA_LOG_INFO ? StripDots(file) : StripPath(file);
}
extern "C" void goldfish_fuchsia_log(int8_t severity, const char* tag, const char* file, int line,
const char* format, va_list va) {
if (!g_log_socket.is_valid()) {
abort();
}
fuchsia_syslog::LogBuffer buffer;
constexpr size_t kFormatStringLength = 1024;
char fmt_string[kFormatStringLength];
fmt_string[kFormatStringLength - 1] = 0;
int n = kFormatStringLength;
// Format
// Number of bytes written not including null terminator
int count = vsnprintf(fmt_string, n, format, va) + 1;
if (count < 0) {
// No message to write.
return;
}
if (count >= n) {
// truncated
constexpr char kEllipsis[] = "...";
constexpr size_t kEllipsisSize = sizeof(kEllipsis);
snprintf(fmt_string + kFormatStringLength - 1 - kEllipsisSize, kEllipsisSize, kEllipsis);
}
if (file) {
file = StripFile(file, severity);
}
buffer.BeginRecord(severity, CStringToStringView(file), line, fmt_string, g_log_socket.borrow(),
0, pid, tid);
if (tag) {
buffer.WriteKeyValue("tag", tag);
}
buffer.FlushRecord();
}
} // namespace
void VulkanDevice::InitTraceProvider() {
if (!mTraceProvider.Initialize()) {
ALOGE("Trace provider failed to initialize");
}
}
extern "C" __attribute__((visibility("default"))) PFN_vkVoidFunction vk_icdGetInstanceProcAddr(
VkInstance instance, const char* name) {
return VulkanDevice::GetInstance().GetInstanceProcAddr(instance, name);
}
extern "C" __attribute__((visibility("default"))) VkResult vk_icdNegotiateLoaderICDInterfaceVersion(
uint32_t* pSupportedVersion) {
*pSupportedVersion = std::min(*pSupportedVersion, 3u);
return VK_SUCCESS;
}
typedef VkResult(VKAPI_PTR* PFN_vkOpenInNamespaceAddr)(const char* pName, uint32_t handle);
namespace {
PFN_vkOpenInNamespaceAddr g_vulkan_connector;
zx_handle_t LocalConnectToServiceFunction(const char* pName) {
zx::channel remote_endpoint, local_endpoint;
zx_status_t status;
if ((status = zx::channel::create(0, &remote_endpoint, &local_endpoint)) != ZX_OK) {
ALOGE("zx::channel::create failed: %d", status);
return ZX_HANDLE_INVALID;
}
if ((status = g_vulkan_connector(pName, remote_endpoint.release())) != ZX_OK) {
ALOGE("vulkan_connector failed: %d", status);
return ZX_HANDLE_INVALID;
}
return local_endpoint.release();
}
} // namespace
extern "C" __attribute__((visibility("default"))) void vk_icdInitializeOpenInNamespaceCallback(
PFN_vkOpenInNamespaceAddr callback) {
g_vulkan_connector = callback;
SetConnectToServiceFunction(&LocalConnectToServiceFunction);
}
#else
class VulkanDevice {
public:
VulkanDevice() { goldfish_vk::ResourceTracker::get(); }
static VulkanDevice& GetInstance() {
static VulkanDevice g_instance;
return g_instance;
}
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* name) {
return ::GetInstanceProcAddr(instance, name);
}
};
extern "C" __attribute__((visibility("default"))) PFN_vkVoidFunction vk_icdGetInstanceProcAddr(
VkInstance instance, const char* name) {
return VulkanDevice::GetInstance().GetInstanceProcAddr(instance, name);
}
extern "C" __attribute__((visibility("default"))) VkResult vk_icdNegotiateLoaderICDInterfaceVersion(
uint32_t* pSupportedVersion) {
*pSupportedVersion = std::min(*pSupportedVersion, 3u);
return VK_SUCCESS;
}
#endif
} // namespace