blob: 0bb42b248727f8150b46fbfda748452633a61876 [file] [log] [blame]
// Copyright (C) 2018 The Android Open Source Project
// Copyright (C) 2018 Google Inc.
//
// 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 "ResourceTracker.h"
#include "Resources.h"
#include "VkEncoder.h"
#include "android/base/AlignedBuf.h"
#include "android/base/synchronization/AndroidLock.h"
#include <unordered_map>
#include <log/log.h>
#define RESOURCE_TRACKER_DEBUG 0
#if RESOURCE_TRACKER_DEBUG
#define D(fmt,...) ALOGD("%s: " fmt, __func__, ##__VA_ARGS__);
#else
#ifndef D
#define D(fmt,...)
#endif
#endif
using android::aligned_buf_alloc;
using android::aligned_buf_free;
using android::base::guest::AutoLock;
using android::base::guest::Lock;
namespace goldfish_vk {
#define MAKE_HANDLE_MAPPING_FOREACH(type_name, map_impl, map_to_u64_impl, map_from_u64_impl) \
void mapHandles_##type_name(type_name* handles, size_t count) override { \
for (size_t i = 0; i < count; ++i) { \
map_impl; \
} \
} \
void mapHandles_##type_name##_u64(const type_name* handles, uint64_t* handle_u64s, size_t count) override { \
for (size_t i = 0; i < count; ++i) { \
map_to_u64_impl; \
} \
} \
void mapHandles_u64_##type_name(const uint64_t* handle_u64s, type_name* handles, size_t count) override { \
for (size_t i = 0; i < count; ++i) { \
map_from_u64_impl; \
} \
} \
#define DEFINE_RESOURCE_TRACKING_CLASS(class_name, impl) \
class class_name : public VulkanHandleMapping { \
public: \
virtual ~class_name() { } \
GOLDFISH_VK_LIST_HANDLE_TYPES(impl) \
}; \
#define CREATE_MAPPING_IMPL_FOR_TYPE(type_name) \
MAKE_HANDLE_MAPPING_FOREACH(type_name, \
handles[i] = new_from_host_##type_name(handles[i]); ResourceTracker::get()->register_##type_name(handles[i]);, \
handle_u64s[i] = (uint64_t)(uintptr_t)new_from_host_##type_name(handles[i]), \
handles[i] = (type_name)(uintptr_t)new_from_host_u64_##type_name(handle_u64s[i]); ResourceTracker::get()->register_##type_name(handles[i]);)
#define UNWRAP_MAPPING_IMPL_FOR_TYPE(type_name) \
MAKE_HANDLE_MAPPING_FOREACH(type_name, \
handles[i] = get_host_##type_name(handles[i]), \
handle_u64s[i] = (uint64_t)(uintptr_t)get_host_u64_##type_name(handles[i]), \
handles[i] = (type_name)(uintptr_t)get_host_##type_name((type_name)(uintptr_t)handle_u64s[i]))
#define DESTROY_MAPPING_IMPL_FOR_TYPE(type_name) \
MAKE_HANDLE_MAPPING_FOREACH(type_name, \
ResourceTracker::get()->unregister_##type_name(handles[i]); delete_goldfish_##type_name(handles[i]), \
(void)handle_u64s[i]; delete_goldfish_##type_name(handles[i]), \
(void)handles[i]; delete_goldfish_##type_name((type_name)(uintptr_t)handle_u64s[i]))
DEFINE_RESOURCE_TRACKING_CLASS(CreateMapping, CREATE_MAPPING_IMPL_FOR_TYPE)
DEFINE_RESOURCE_TRACKING_CLASS(UnwrapMapping, UNWRAP_MAPPING_IMPL_FOR_TYPE)
DEFINE_RESOURCE_TRACKING_CLASS(DestroyMapping, DESTROY_MAPPING_IMPL_FOR_TYPE)
class ResourceTracker::Impl {
public:
Impl() = default;
CreateMapping createMapping;
UnwrapMapping unwrapMapping;
DestroyMapping destroyMapping;
DefaultHandleMapping defaultMapping;
#define HANDLE_DEFINE_TRIVIAL_INFO_STRUCT(type) \
struct type##_Info { \
uint32_t unused; \
}; \
GOLDFISH_VK_LIST_TRIVIAL_HANDLE_TYPES(HANDLE_DEFINE_TRIVIAL_INFO_STRUCT)
struct VkDevice_Info {
VkPhysicalDevice physdev;
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memProps;
};
struct VkDeviceMemory_Info {
VkDeviceSize allocationSize;
uint32_t memoryTypeIndex;
};
#define HANDLE_REGISTER_IMPL_IMPL(type) \
std::unordered_map<type, type##_Info> info_##type; \
void register_##type(type obj) { \
AutoLock lock(mLock); \
info_##type[obj] = type##_Info(); \
} \
void unregister_##type(type obj) { \
AutoLock lock(mLock); \
info_##type.erase(obj); \
} \
GOLDFISH_VK_LIST_HANDLE_TYPES(HANDLE_REGISTER_IMPL_IMPL)
void setDeviceInfo(VkDevice device,
VkPhysicalDevice physdev,
VkPhysicalDeviceProperties props,
VkPhysicalDeviceMemoryProperties memProps) {
AutoLock lock(mLock);
auto& info = info_VkDevice[device];
info.physdev = physdev;
info.props = props;
info.memProps = memProps;
}
bool isMemoryTypeHostVisible(VkDevice device, uint32_t typeIndex) const {
AutoLock lock(mLock);
const auto it = info_VkDevice.find(device);
if (it == info_VkDevice.end()) return false;
const auto& info = it->second;
return info.memProps.memoryTypes[typeIndex].propertyFlags &
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
}
VkDeviceSize getNonCoherentExtendedSize(VkDevice device, VkDeviceSize basicSize) const {
AutoLock lock(mLock);
const auto it = info_VkDevice.find(device);
if (it == info_VkDevice.end()) return basicSize;
const auto& info = it->second;
VkDeviceSize nonCoherentAtomSize =
info.props.limits.nonCoherentAtomSize;
VkDeviceSize atoms =
(basicSize + nonCoherentAtomSize - 1) / nonCoherentAtomSize;
return atoms * nonCoherentAtomSize;
}
VkResult on_vkCreateDevice(
void* context,
VkResult input_result,
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo*,
const VkAllocationCallbacks*,
VkDevice* pDevice) {
if (input_result != VK_SUCCESS) return input_result;
VkEncoder* enc = (VkEncoder*)context;
VkPhysicalDeviceProperties props;
VkPhysicalDeviceMemoryProperties memProps;
enc->vkGetPhysicalDeviceProperties(physicalDevice, &props);
enc->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);
setDeviceInfo(*pDevice, physicalDevice, props, memProps);
return input_result;
}
VkResult on_vkAllocateMemory(
void*,
VkResult input_result,
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks*,
VkDeviceMemory* pMemory) {
if (input_result != VK_SUCCESS) return input_result;
// Assumes pMemory has already been allocated.
goldfish_VkDeviceMemory* mem = as_goldfish_VkDeviceMemory(*pMemory);
VkDeviceSize size = pAllocateInfo->allocationSize;
// assume memory is not host visible.
mem->ptr = nullptr;
mem->size = size;
mem->mappedSize = getNonCoherentExtendedSize(device, size);
if (!isMemoryTypeHostVisible(device, pAllocateInfo->memoryTypeIndex)) {
return input_result;
}
// This is a strict alignment; we do not expect any
// actual device to have more stringent requirements
// than this.
mem->ptr = (uint8_t*)aligned_buf_alloc(4096, mem->mappedSize);
D("host visible alloc: size 0x%llx host ptr %p mapped size 0x%llx",
(unsigned long long)size, mem->ptr,
(unsigned long long)mem->mappedSize);
return input_result;
}
private:
mutable Lock mLock;
};
ResourceTracker::ResourceTracker() : mImpl(new ResourceTracker::Impl()) { }
ResourceTracker::~ResourceTracker() { }
VulkanHandleMapping* ResourceTracker::createMapping() {
return &mImpl->createMapping;
}
VulkanHandleMapping* ResourceTracker::unwrapMapping() {
return &mImpl->unwrapMapping;
}
VulkanHandleMapping* ResourceTracker::destroyMapping() {
return &mImpl->destroyMapping;
}
VulkanHandleMapping* ResourceTracker::defaultMapping() {
return &mImpl->defaultMapping;
}
static ResourceTracker* sTracker = nullptr;
// static
ResourceTracker* ResourceTracker::get() {
if (!sTracker) {
// To be initialized once on vulkan device open.
sTracker = new ResourceTracker;
}
return sTracker;
}
#define HANDLE_REGISTER_IMPL(type) \
void ResourceTracker::register_##type(type obj) { \
mImpl->register_##type(obj); \
} \
void ResourceTracker::unregister_##type(type obj) { \
mImpl->unregister_##type(obj); \
} \
GOLDFISH_VK_LIST_HANDLE_TYPES(HANDLE_REGISTER_IMPL)
void ResourceTracker::setDeviceInfo(
VkDevice device,
VkPhysicalDevice physdev,
VkPhysicalDeviceProperties props,
VkPhysicalDeviceMemoryProperties memProps) {
mImpl->setDeviceInfo(device, physdev, props, memProps);
}
bool ResourceTracker::isMemoryTypeHostVisible(
VkDevice device, uint32_t typeIndex) const {
return mImpl->isMemoryTypeHostVisible(device, typeIndex);
}
VkDeviceSize ResourceTracker::getNonCoherentExtendedSize(VkDevice device, VkDeviceSize basicSize) const {
return mImpl->getNonCoherentExtendedSize(device, basicSize);
}
VkResult ResourceTracker::on_vkCreateDevice(
void* context,
VkResult input_result,
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice) {
return mImpl->on_vkCreateDevice(
context, input_result, physicalDevice, pCreateInfo, pAllocator, pDevice);
}
VkResult ResourceTracker::on_vkAllocateMemory(
void* context,
VkResult input_result,
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory) {
return mImpl->on_vkAllocateMemory(
context, input_result, device, pAllocateInfo, pAllocator, pMemory);
}
} // namespace goldfish_vk