Rename imported system directory to guest

Reviewed-by: Aaron Ruby <aruby@blackberry.com>
Acked-by: Yonggang Luo <luoyonggang@gmail.com>
Acked-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27246>
This commit is contained in:
Jason Macnak
2023-06-01 11:05:44 -07:00
committed by Marge Bot
parent 757d38a682
commit 9106e8c3c5
29 changed files with 12692 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
# Copyright 2022 Android Open Source Project
# SPDX-License-Identifier: MIT
vk_api_xml = files('vk.xml')
vk_icd_gen = files('vk_icd_gen.py')
files_lib_vulkan_cereal = files(
'goldfish_vulkan.cpp',
)
lib_vulkan_cereal = shared_library(
'vulkan_cereal',
files_lib_vulkan_cereal,
cpp_args: cpp_args,
include_directories: [inc_android_emu, inc_android_compat, inc_opengl_system,
inc_host, inc_opengl_codec, inc_render_enc,
inc_vulkan_enc],
link_with: [lib_android_compat, lib_emu_android_base, lib_stream,
lib_vulkan_enc],
install: true,
)
cereal_icd = custom_target(
'cereal_icd',
input : [vk_icd_gen, vk_api_xml],
output : 'cereal_icd.@0@.json'.format(host_machine.cpu()),
command : [
prog_python, '@INPUT0@',
'--api-version', '1.0', '--xml', '@INPUT1@',
'--lib-path', join_paths(get_option('prefix'), get_option('libdir'),
'libvulkan_cereal.so'),
'--out', '@OUTPUT@',
],
build_by_default : true,
install_dir : with_vulkan_icd_dir,
install : true,
)
@@ -0,0 +1,348 @@
/// Copyright (C) 2019 The Android Open Source Project
// Copyright (C) 2019 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 "AndroidHardwareBuffer.h"
#if !defined(HOST_BUILD)
#if defined(__ANDROID__) || defined(__linux__)
#include <drm_fourcc.h>
#define DRM_FORMAT_YVU420_ANDROID fourcc_code('9', '9', '9', '7')
#endif
#endif
#include "../OpenglSystemCommon/HostConnection.h"
#include "vk_format_info.h"
#include "vk_util.h"
#include <assert.h>
namespace gfxstream {
namespace vk {
// From Intel ANV implementation.
/* Construct ahw usage mask from image usage bits, see
* 'AHardwareBuffer Usage Equivalence' in Vulkan spec.
*/
uint64_t
getAndroidHardwareBufferUsageFromVkUsage(const VkImageCreateFlags vk_create,
const VkImageUsageFlags vk_usage)
{
uint64_t ahw_usage = 0;
if (vk_usage & VK_IMAGE_USAGE_SAMPLED_BIT)
ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
if (vk_usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)
ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
if (vk_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT;
if (vk_create & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
ahw_usage |= AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP;
if (vk_create & VK_IMAGE_CREATE_PROTECTED_BIT)
ahw_usage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT;
/* No usage bits set - set at least one GPU usage. */
if (ahw_usage == 0)
ahw_usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
return ahw_usage;
}
void updateMemoryTypeBits(uint32_t* memoryTypeBits, uint32_t colorBufferMemoryIndex) {
*memoryTypeBits = 1u << colorBufferMemoryIndex;
}
VkResult getAndroidHardwareBufferPropertiesANDROID(
Gralloc* grallocHelper,
const AHardwareBuffer* buffer,
VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
const native_handle_t *handle =
AHardwareBuffer_getNativeHandle(buffer);
VkAndroidHardwareBufferFormatPropertiesANDROID* ahbFormatProps =
vk_find_struct<VkAndroidHardwareBufferFormatPropertiesANDROID>(pProperties);
if (ahbFormatProps) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
const uint64_t gpu_usage =
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
if (!(desc.usage & (gpu_usage))) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
switch(desc.format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
ahbFormatProps->format = VK_FORMAT_R8G8B8A8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
ahbFormatProps->format = VK_FORMAT_R8G8B8A8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
ahbFormatProps->format = VK_FORMAT_R8G8B8_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
ahbFormatProps->format = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
ahbFormatProps->format = VK_FORMAT_R16G16B16A16_SFLOAT;
break;
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
ahbFormatProps->format = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
break;
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
ahbFormatProps->format = VK_FORMAT_D16_UNORM;
break;
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
ahbFormatProps->format = VK_FORMAT_X8_D24_UNORM_PACK32;
break;
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
ahbFormatProps->format = VK_FORMAT_D24_UNORM_S8_UINT;
break;
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
ahbFormatProps->format = VK_FORMAT_D32_SFLOAT;
break;
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
ahbFormatProps->format = VK_FORMAT_D32_SFLOAT_S8_UINT;
break;
case AHARDWAREBUFFER_FORMAT_S8_UINT:
ahbFormatProps->format = VK_FORMAT_S8_UINT;
break;
default:
ahbFormatProps->format = VK_FORMAT_UNDEFINED;
}
ahbFormatProps->externalFormat = desc.format;
// The formatFeatures member must include
// VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT and at least one of
// VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
// VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT, and should include
// VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT and
// VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT.
// org.skia.skqp.SkQPRunner#UnitTest_VulkanHardwareBuffer* requires the following:
// VK_FORMAT_FEATURE_TRANSFER_SRC_BIT
// VK_FORMAT_FEATURE_TRANSFER_DST_BIT
// VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
ahbFormatProps->formatFeatures =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
// "Implementations may not always be able to determine the color model,
// numerical range, or chroma offsets of the image contents, so the values in
// VkAndroidHardwareBufferFormatPropertiesANDROID are only suggestions.
// Applications should treat these values as sensible defaults to use in the
// absence of more reliable information obtained through some other means."
ahbFormatProps->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_IDENTITY;
ahbFormatProps->samplerYcbcrConversionComponents.g = VK_COMPONENT_SWIZZLE_IDENTITY;
ahbFormatProps->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_IDENTITY;
ahbFormatProps->samplerYcbcrConversionComponents.a = VK_COMPONENT_SWIZZLE_IDENTITY;
#if !defined(HOST_BUILD)
#if defined(__ANDROID__) || defined(__linux__)
if (android_format_is_yuv(desc.format)) {
uint32_t drmFormat = grallocHelper->getFormatDrmFourcc(handle);
if (drmFormat) {
// The host renderer is not aware of the plane ordering for YUV formats used
// in the guest and simply knows that the format "layout" is one of:
//
// * VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16
// * VK_FORMAT_G8_B8R8_2PLANE_420_UNORM
// * VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM
//
// With this, the guest needs to adjust the component swizzle based on plane
// ordering to ensure that the channels are interpreted correctly.
//
// From the Vulkan spec's "Sampler Y'CBCR Conversion" section:
//
// * Y comes from the G-channel (after swizzle)
// * U (CB) comes from the B-channel (after swizzle)
// * V (CR) comes from the R-channel (after swizzle)
//
// See https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#textures-sampler-YCbCr-conversion
//
// To match the above, the guest needs to swizzle such that:
//
// * Y ends up in the G-channel
// * U (CB) ends up in the B-channel
// * V (CB) ends up in the R-channel
switch (drmFormat) {
case DRM_FORMAT_NV12:
// NV12 is a Y-plane followed by a interleaved UV-plane and is
// VK_FORMAT_G8_B8R8_2PLANE_420_UNORM on the host.
case DRM_FORMAT_P010:
// P010 is a Y-plane followed by a interleaved UV-plane and is
// VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 on the host.
break;
case DRM_FORMAT_NV21:
// NV21 is a Y-plane followed by a interleaved VU-plane and is
// VK_FORMAT_G8_B8R8_2PLANE_420_UNORM on the host.
case DRM_FORMAT_YVU420:
// YV12 is a Y-plane, then a V-plane, and then a U-plane and is
// VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM on the host.
case DRM_FORMAT_YVU420_ANDROID:
// DRM_FORMAT_YVU420_ANDROID is the same as DRM_FORMAT_YVU420 with
// Android's extra alignement requirements.
ahbFormatProps->samplerYcbcrConversionComponents.r = VK_COMPONENT_SWIZZLE_B;
ahbFormatProps->samplerYcbcrConversionComponents.b = VK_COMPONENT_SWIZZLE_R;
break;
default:
ALOGE("%s: Unhandled YUV drm format:%" PRIu32, __FUNCTION__, drmFormat);
break;
}
}
}
#endif
#endif
ahbFormatProps->suggestedYcbcrModel =
android_format_is_yuv(desc.format) ?
VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 :
VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY;
ahbFormatProps->suggestedYcbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL;
ahbFormatProps->suggestedXChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
ahbFormatProps->suggestedYChromaOffset = VK_CHROMA_LOCATION_MIDPOINT;
}
uint32_t colorBufferHandle =
grallocHelper->getHostHandle(handle);
if (!colorBufferHandle) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
pProperties->allocationSize =
grallocHelper->getAllocatedSize(handle);
return VK_SUCCESS;
}
// Based on Intel ANV implementation.
VkResult getMemoryAndroidHardwareBufferANDROID(struct AHardwareBuffer **pBuffer) {
/* Some quotes from Vulkan spec:
*
* "If the device memory was created by importing an Android hardware
* buffer, vkGetMemoryAndroidHardwareBufferANDROID must return that same
* Android hardware buffer object."
*
* "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID must
* have been included in VkExportMemoryAllocateInfo::handleTypes when
* memory was created."
*/
if (!pBuffer) return VK_ERROR_OUT_OF_HOST_MEMORY;
if (!(*pBuffer)) return VK_ERROR_OUT_OF_HOST_MEMORY;
AHardwareBuffer_acquire(*pBuffer);
return VK_SUCCESS;
}
VkResult importAndroidHardwareBuffer(
Gralloc* grallocHelper,
const VkImportAndroidHardwareBufferInfoANDROID* info,
struct AHardwareBuffer **importOut) {
if (!info || !info->buffer) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
uint32_t colorBufferHandle =
grallocHelper->getHostHandle(
AHardwareBuffer_getNativeHandle(info->buffer));
if (!colorBufferHandle) {
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
}
auto ahb = info->buffer;
AHardwareBuffer_acquire(ahb);
if (importOut) *importOut = ahb;
return VK_SUCCESS;
}
VkResult createAndroidHardwareBuffer(
bool hasDedicatedImage,
bool hasDedicatedBuffer,
const VkExtent3D& imageExtent,
uint32_t imageLayers,
VkFormat imageFormat,
VkImageUsageFlags imageUsage,
VkImageCreateFlags imageCreateFlags,
VkDeviceSize bufferSize,
VkDeviceSize allocationInfoAllocSize,
struct AHardwareBuffer **out) {
uint32_t w = 0;
uint32_t h = 1;
uint32_t layers = 1;
uint32_t format = 0;
uint64_t usage = 0;
/* If caller passed dedicated information. */
if (hasDedicatedImage) {
w = imageExtent.width;
h = imageExtent.height;
layers = imageLayers;
format = android_format_from_vk(imageFormat);
usage = getAndroidHardwareBufferUsageFromVkUsage(imageCreateFlags, imageUsage);
} else if (hasDedicatedBuffer) {
w = bufferSize;
format = AHARDWAREBUFFER_FORMAT_BLOB;
usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
} else {
w = allocationInfoAllocSize;
format = AHARDWAREBUFFER_FORMAT_BLOB;
usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER;
}
struct AHardwareBuffer *ahw = NULL;
struct AHardwareBuffer_Desc desc = {
.width = w,
.height = h,
.layers = layers,
.format = format,
.usage = usage,
};
if (AHardwareBuffer_allocate(&desc, &ahw) != 0) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
*out = ahw;
return VK_SUCCESS;
}
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,63 @@
/// Copyright (C) 2019 The Android Open Source Project
// Copyright (C) 2019 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.
#pragma once
#include "HostVisibleMemoryVirtualization.h"
#include <vulkan/vulkan.h>
#include <vndk/hardware_buffer.h>
// Structure similar to
// https://github.com/mesa3d/mesa/blob/master/src/intel/vulkan/anv_android.c
class Gralloc;
namespace gfxstream {
namespace vk {
uint64_t
getAndroidHardwareBufferUsageFromVkUsage(
const VkImageCreateFlags vk_create,
const VkImageUsageFlags vk_usage);
void updateMemoryTypeBits(uint32_t* memoryTypeBits, uint32_t colorBufferMemoryIndex);
VkResult getAndroidHardwareBufferPropertiesANDROID(
Gralloc* grallocHelper,
const AHardwareBuffer* buffer,
VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VkResult getMemoryAndroidHardwareBufferANDROID(
struct AHardwareBuffer **pBuffer);
VkResult importAndroidHardwareBuffer(
Gralloc* grallocHelper,
const VkImportAndroidHardwareBufferInfoANDROID* info,
struct AHardwareBuffer **importOut);
VkResult createAndroidHardwareBuffer(
bool hasDedicatedImage,
bool hasDedicatedBuffer,
const VkExtent3D& imageExtent,
uint32_t imageLayers,
VkFormat imageFormat,
VkImageUsageFlags imageUsage,
VkImageCreateFlags imageCreateFlags,
VkDeviceSize bufferSize,
VkDeviceSize allocationInfoAllocSize,
struct AHardwareBuffer **out);
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,257 @@
/*
* Copyright (C) 2021 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 "CommandBufferStagingStream.h"
#if PLATFORM_SDK_VERSION < 26
#include <cutils/log.h>
#else
#include <log/log.h>
#endif
#include <cutils/properties.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atomic>
#include <vector>
static const size_t kReadSize = 512 * 1024;
static const size_t kWriteOffset = kReadSize;
namespace gfxstream {
namespace vk {
CommandBufferStagingStream::CommandBufferStagingStream()
: IOStream(1048576), m_size(0), m_writePos(0) {
// use default allocators
m_alloc = [](size_t size) -> Memory {
return {
.deviceMemory = VK_NULL_HANDLE, // no device memory for malloc
.ptr = malloc(size),
};
};
m_free = [](const Memory& mem) { free(mem.ptr); };
m_realloc = [](const Memory& mem, size_t size) -> Memory {
return {.deviceMemory = VK_NULL_HANDLE, .ptr = realloc(mem.ptr, size)};
};
}
CommandBufferStagingStream::CommandBufferStagingStream(const Alloc& allocFn, const Free& freeFn)
: CommandBufferStagingStream() {
m_usingCustomAlloc = true;
// for custom allocation, allocate metadata memory at the beginning.
// m_alloc, m_free and m_realloc wraps sync data logic
// \param size to allocate
// \return ptr starting at data
m_alloc = [&allocFn](size_t size) -> Memory {
// allocation requested size + sync data size
// <---sync bytes--><----Data--->
// |———————————————|————————————|
// |0|1|2|3|4|5|6|7|............|
// |———————————————|————————————|
// ꜛ ꜛ
// allocated ptr ptr to data [dataPtr]
Memory memory;
if (!allocFn) {
ALOGE("Custom allocation (%zu bytes) failed\n", size);
return memory;
}
// custom allocation/free requires metadata for sync between host/guest
const size_t totalSize = size + kSyncDataSize;
memory = allocFn(totalSize);
if (!memory.ptr) {
ALOGE("Custom allocation (%zu bytes) failed\n", size);
return memory;
}
// set sync data to read complete
uint32_t* syncDWordPtr = reinterpret_cast<uint32_t*>(memory.ptr);
__atomic_store_n(syncDWordPtr, kSyncDataReadComplete, __ATOMIC_RELEASE);
return memory;
};
m_free = [&freeFn](const Memory& mem) {
if (!freeFn) {
ALOGE("Custom free for memory(%p) failed\n", mem.ptr);
return;
}
freeFn(mem);
};
// \param ptr is the data pointer currently allocated
// \return dataPtr starting at data
m_realloc = [this](const Memory& mem, size_t size) -> Memory {
// realloc requires freeing previously allocated memory
// read sync DWORD to ensure host is done reading this memory
// before releasing it.
size_t hostWaits = 0;
uint32_t* syncDWordPtr = reinterpret_cast<uint32_t*>(mem.ptr);
while (__atomic_load_n(syncDWordPtr, __ATOMIC_ACQUIRE) != kSyncDataReadComplete) {
hostWaits++;
usleep(10);
if (hostWaits > 1000) {
ALOGD("%s: warning, stalled on host decoding on this command buffer stream\n",
__func__);
}
}
// for custom allocation/free, memory holding metadata must be copied
// along with stream data
// <---sync bytes--><----Data--->
// |———————————————|————————————|
// |0|1|2|3|4|5|6|7|............|
// |———————————————|————————————|
// ꜛ ꜛ
// [copyLocation] ptr to data [ptr]
const size_t toCopySize = m_writePos + kSyncDataSize;
unsigned char* copyLocation = static_cast<unsigned char*>(mem.ptr);
std::vector<uint8_t> tmp(copyLocation, copyLocation + toCopySize);
m_free(mem);
// get new buffer and copy previous stream data to it
Memory newMemory = m_alloc(size);
unsigned char* newBuf = static_cast<unsigned char*>(newMemory.ptr);
if (!newBuf) {
ALOGE("Custom allocation (%zu bytes) failed\n", size);
return newMemory;
}
// copy previous data
memcpy(newBuf, tmp.data(), toCopySize);
return newMemory;
};
}
CommandBufferStagingStream::~CommandBufferStagingStream() {
flush();
if (m_mem.ptr) m_free(m_mem);
}
unsigned char* CommandBufferStagingStream::getDataPtr() {
if (!m_mem.ptr) return nullptr;
const size_t metadataSize = m_usingCustomAlloc ? kSyncDataSize : 0;
return static_cast<unsigned char*>(m_mem.ptr) + metadataSize;
}
void CommandBufferStagingStream::markFlushing() {
if (!m_usingCustomAlloc) {
return;
}
uint32_t* syncDWordPtr = reinterpret_cast<uint32_t*>(m_mem.ptr);
__atomic_store_n(syncDWordPtr, kSyncDataReadPending, __ATOMIC_RELEASE);
}
size_t CommandBufferStagingStream::idealAllocSize(size_t len) {
if (len > 1048576) return len;
return 1048576;
}
void* CommandBufferStagingStream::allocBuffer(size_t minSize) {
size_t allocSize = (1048576 < minSize ? minSize : 1048576);
// Initial case: blank
if (!m_mem.ptr) {
m_mem = m_alloc(allocSize);
m_size = allocSize;
return getDataPtr();
}
// Calculate remaining
size_t remaining = m_size - m_writePos;
// check if there is at least minSize bytes left in buffer
// if not, reallocate a buffer of big enough size
if (remaining < minSize) {
size_t newAllocSize = m_size * 2 + allocSize;
m_mem = m_realloc(m_mem, newAllocSize);
m_size = newAllocSize;
return (void*)(getDataPtr() + m_writePos);
}
// for custom allocations, host should have finished reading
// data from command buffer since command buffers are flushed
// on queue submit.
// allocBuffer should not be called on command buffers that are currently
// being read by the host
if (m_usingCustomAlloc) {
uint32_t* syncDWordPtr = reinterpret_cast<uint32_t*>(m_mem.ptr);
LOG_ALWAYS_FATAL_IF(
__atomic_load_n(syncDWordPtr, __ATOMIC_ACQUIRE) != kSyncDataReadComplete,
"FATAL: allocBuffer() called but previous read not complete");
}
return (void*)(getDataPtr() + m_writePos);
}
int CommandBufferStagingStream::commitBuffer(size_t size)
{
m_writePos += size;
return 0;
}
const unsigned char *CommandBufferStagingStream::readFully(void*, size_t) {
// Not supported
ALOGE("CommandBufferStagingStream::%s: Fatal: not supported\n", __func__);
abort();
return nullptr;
}
const unsigned char *CommandBufferStagingStream::read(void*, size_t*) {
// Not supported
ALOGE("CommandBufferStagingStream::%s: Fatal: not supported\n", __func__);
abort();
return nullptr;
}
int CommandBufferStagingStream::writeFully(const void*, size_t)
{
// Not supported
ALOGE("CommandBufferStagingStream::%s: Fatal: not supported\n", __func__);
abort();
return 0;
}
const unsigned char *CommandBufferStagingStream::commitBufferAndReadFully(
size_t, void *, size_t) {
// Not supported
ALOGE("CommandBufferStagingStream::%s: Fatal: not supported\n", __func__);
abort();
return nullptr;
}
void CommandBufferStagingStream::getWritten(unsigned char** bufOut, size_t* sizeOut) {
*bufOut = getDataPtr();
*sizeOut = m_writePos;
}
void CommandBufferStagingStream::reset() {
m_writePos = 0;
IOStream::rewind();
}
VkDeviceMemory CommandBufferStagingStream::getDeviceMemory() { return m_mem.deviceMemory; }
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,119 @@
/*
* Copyright (C) 2021 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.
*/
#ifndef __COMMAND_BUFFER_STAGING_STREAM_H
#define __COMMAND_BUFFER_STAGING_STREAM_H
#include <vulkan/vulkan_core.h>
#include <functional>
#include "IOStream.h"
namespace gfxstream {
namespace vk {
class CommandBufferStagingStream : public IOStream {
public:
// host will write kSyncDataReadComplete to the sync bytes to indicate memory is no longer being
// used by host. This is only used with custom allocators. The sync bytes are used to ensure that,
// during reallocations the guest does not free memory being read by the host. The guest ensures
// that the sync bytes are marked as read complete before releasing the memory.
static constexpr size_t kSyncDataSize = 8;
// indicates read is complete
static constexpr uint32_t kSyncDataReadComplete = 0X0;
// indicates read is pending
static constexpr uint32_t kSyncDataReadPending = 0X1;
// \struct backing memory structure
struct Memory {
VkDeviceMemory deviceMemory =
VK_NULL_HANDLE; // device memory associated with allocated memory
void* ptr = nullptr; // pointer to allocated memory
bool operator==(const Memory& rhs) const {
return (deviceMemory == rhs.deviceMemory) && (ptr == rhs.ptr);
}
};
// allocator
// param size to allocate
// return allocated memory
using Alloc = std::function<Memory(size_t)>;
// free function
// param memory to free
using Free = std::function<void(const Memory&)>;
// constructor
// \param allocFn is the allocation function provided.
// \param freeFn is the free function provided
explicit CommandBufferStagingStream(const Alloc& allocFn, const Free& freeFn);
// constructor
explicit CommandBufferStagingStream();
~CommandBufferStagingStream();
virtual size_t idealAllocSize(size_t len);
virtual void* allocBuffer(size_t minSize);
virtual int commitBuffer(size_t size);
virtual const unsigned char* readFully(void* buf, size_t len);
virtual const unsigned char* read(void* buf, size_t* inout_len);
virtual int writeFully(const void* buf, size_t len);
virtual const unsigned char* commitBufferAndReadFully(size_t size, void* buf, size_t len);
void getWritten(unsigned char** bufOut, size_t* sizeOut);
void reset();
// marks the command buffer stream as flushing. The owner of CommandBufferStagingStream
// should call markFlushing after finishing writing to the stream.
// This will mark the sync data to kSyncDataReadPending. This is only applicable when
// using custom allocators. markFlushing will be a no-op if called
// when not using custom allocators
void markFlushing();
// gets the device memory associated with the stream. This is VK_NULL_HANDLE for default allocation
// \return device memory
VkDeviceMemory getDeviceMemory();
private:
// underlying memory for data
Memory m_mem;
// size of portion of memory available for data.
// for custom allocation, this size excludes size of sync data.
size_t m_size;
// current write position in data buffer
uint32_t m_writePos;
// alloc function
Alloc m_alloc;
// free function
Free m_free;
// realloc function
// \param size of memory to be allocated
// \ param reference size to update with actual size allocated. This size can be < requested size
// for custom allocation to account for sync data
using Realloc = std::function<Memory(const Memory&, size_t)>;
Realloc m_realloc;
// flag tracking use of custom allocation/free
bool m_usingCustomAlloc = false;
// adjusted memory location to point to start of data after accounting for metadata
// \return pointer to data start
unsigned char* getDataPtr();
};
} // namespace vk
} // namespace gfxstream
#endif
@@ -0,0 +1,499 @@
// Copyright (C) 2021 The Android Open Source Project
// Copyright (C) 2021 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 "DescriptorSetVirtualization.h"
#include "Resources.h"
namespace gfxstream {
namespace vk {
void clearReifiedDescriptorSet(ReifiedDescriptorSet* set) {
set->pool = VK_NULL_HANDLE;
set->setLayout = VK_NULL_HANDLE;
set->poolId = -1;
set->allocationPending = false;
set->allWrites.clear();
set->pendingWriteArrayRanges.clear();
}
void initDescriptorWriteTable(const std::vector<VkDescriptorSetLayoutBinding>& layoutBindings, DescriptorWriteTable& table) {
uint32_t highestBindingNumber = 0;
for (uint32_t i = 0; i < layoutBindings.size(); ++i) {
if (layoutBindings[i].binding > highestBindingNumber) {
highestBindingNumber = layoutBindings[i].binding;
}
}
std::vector<uint32_t> countsEachBinding(highestBindingNumber + 1, 0);
for (uint32_t i = 0; i < layoutBindings.size(); ++i) {
countsEachBinding[layoutBindings[i].binding] =
layoutBindings[i].descriptorCount;
}
table.resize(countsEachBinding.size());
for (uint32_t i = 0; i < table.size(); ++i) {
table[i].resize(countsEachBinding[i]);
for (uint32_t j = 0; j < countsEachBinding[i]; ++j) {
table[i][j].type = DescriptorWriteType::Empty;
table[i][j].dstArrayElement = 0;
}
}
}
static void initializeReifiedDescriptorSet(VkDescriptorPool pool, VkDescriptorSetLayout setLayout, ReifiedDescriptorSet* set) {
set->pendingWriteArrayRanges.clear();
const auto& layoutInfo = *(as_goldfish_VkDescriptorSetLayout(setLayout)->layoutInfo);
initDescriptorWriteTable(layoutInfo.bindings, set->allWrites);
for (size_t i = 0; i < layoutInfo.bindings.size(); ++i) {
// Bindings can be sparsely defined
const auto& binding = layoutInfo.bindings[i];
uint32_t bindingIndex = binding.binding;
if (set->bindingIsImmutableSampler.size() <= bindingIndex) {
set->bindingIsImmutableSampler.resize(bindingIndex + 1, false);
}
set->bindingIsImmutableSampler[bindingIndex] =
binding.descriptorCount > 0 &&
(binding.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER ||
binding.descriptorType ==
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) &&
binding.pImmutableSamplers;
}
set->pool = pool;
set->setLayout = setLayout;
set->allocationPending = true;
set->bindings = layoutInfo.bindings;
}
bool isDescriptorTypeImageInfo(VkDescriptorType descType) {
return (descType == VK_DESCRIPTOR_TYPE_SAMPLER) ||
(descType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) ||
(descType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
(descType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
(descType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
}
bool isDescriptorTypeBufferInfo(VkDescriptorType descType) {
return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
(descType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
(descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
(descType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
}
bool isDescriptorTypeBufferView(VkDescriptorType descType) {
return (descType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) ||
(descType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
}
bool isDescriptorTypeInlineUniformBlock(VkDescriptorType descType) {
return descType == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT;
}
bool isDescriptorTypeAccelerationStructure(VkDescriptorType descType) {
return descType == VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
}
void doEmulatedDescriptorWrite(const VkWriteDescriptorSet* write, ReifiedDescriptorSet* toWrite) {
VkDescriptorType descType = write->descriptorType;
uint32_t dstBinding = write->dstBinding;
uint32_t dstArrayElement = write->dstArrayElement;
uint32_t descriptorCount = write->descriptorCount;
DescriptorWriteTable& table = toWrite->allWrites;
uint32_t arrOffset = dstArrayElement;
if (isDescriptorTypeImageInfo(descType)) {
for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
if (arrOffset >= table[dstBinding].size()) {
++dstBinding;
arrOffset = 0;
}
auto& entry = table[dstBinding][arrOffset];
entry.imageInfo = write->pImageInfo[i];
entry.type = DescriptorWriteType::ImageInfo;
entry.descriptorType = descType;
}
} else if (isDescriptorTypeBufferInfo(descType)) {
for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
if (arrOffset >= table[dstBinding].size()) {
++dstBinding;
arrOffset = 0;
}
auto& entry = table[dstBinding][arrOffset];
entry.bufferInfo = write->pBufferInfo[i];
entry.type = DescriptorWriteType::BufferInfo;
entry.descriptorType = descType;
}
} else if (isDescriptorTypeBufferView(descType)) {
for (uint32_t i = 0; i < descriptorCount; ++i, ++arrOffset) {
if (arrOffset >= table[dstBinding].size()) {
++dstBinding;
arrOffset = 0;
}
auto& entry = table[dstBinding][arrOffset];
entry.bufferView = write->pTexelBufferView[i];
entry.type = DescriptorWriteType::BufferView;
entry.descriptorType = descType;
}
} else if (isDescriptorTypeInlineUniformBlock(descType) ||
isDescriptorTypeAccelerationStructure(descType)) {
// TODO
// Look for pNext inline uniform block or acceleration structure.
// Append new DescriptorWrite entry that holds the buffer
ALOGW("%s: Ignoring emulated write for descriptor type 0x%x\n", __func__, descType);
}
}
void doEmulatedDescriptorCopy(const VkCopyDescriptorSet* copy, const ReifiedDescriptorSet* src, ReifiedDescriptorSet* dst) {
const DescriptorWriteTable& srcTable = src->allWrites;
DescriptorWriteTable& dstTable = dst->allWrites;
// src/dst may be the same descriptor set, so we need to create a temporary array for that case.
// (TODO: Maybe just notice the pointers are the same? can aliasing in any other way happen?)
std::vector<DescriptorWrite> toCopy;
uint32_t currBinding = copy->srcBinding;
uint32_t arrOffset = copy->srcArrayElement;
for (uint32_t i = 0; i < copy->descriptorCount; ++i, ++arrOffset) {
if (arrOffset >= srcTable[currBinding].size()) {
++currBinding;
arrOffset = 0;
}
toCopy.push_back(srcTable[currBinding][arrOffset]);
}
currBinding = copy->dstBinding;
arrOffset = copy->dstArrayElement;
for (uint32_t i = 0; i < copy->descriptorCount; ++i, ++arrOffset) {
if (arrOffset >= dstTable[currBinding].size()) {
++currBinding;
arrOffset = 0;
}
dstTable[currBinding][arrOffset] = toCopy[i];
}
}
void doEmulatedDescriptorImageInfoWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkDescriptorImageInfo* imageInfos,
ReifiedDescriptorSet* set) {
DescriptorWriteTable& table = set->allWrites;
uint32_t currBinding = binding;
uint32_t arrOffset = dstArrayElement;
for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
if (arrOffset >= table[currBinding].size()) {
++currBinding;
arrOffset = 0;
}
auto& entry = table[currBinding][arrOffset];
entry.imageInfo = imageInfos[i];
entry.type = DescriptorWriteType::ImageInfo;
entry.descriptorType = descType;
}
}
void doEmulatedDescriptorBufferInfoWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkDescriptorBufferInfo* bufferInfos,
ReifiedDescriptorSet* set) {
DescriptorWriteTable& table = set->allWrites;
uint32_t currBinding = binding;
uint32_t arrOffset = dstArrayElement;
for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
if (arrOffset >= table[currBinding].size()) {
++currBinding;
arrOffset = 0;
}
auto& entry = table[currBinding][dstArrayElement + i];
entry.bufferInfo = bufferInfos[i];
entry.type = DescriptorWriteType::BufferInfo;
entry.descriptorType = descType;
}
}
void doEmulatedDescriptorBufferViewWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkBufferView* bufferViews,
ReifiedDescriptorSet* set) {
DescriptorWriteTable& table = set->allWrites;
uint32_t currBinding = binding;
uint32_t arrOffset = dstArrayElement;
for (uint32_t i = 0; i < count; ++i, ++arrOffset) {
if (arrOffset >= table[currBinding].size()) {
++currBinding;
arrOffset = 0;
}
auto& entry = table[currBinding][dstArrayElement + i];
entry.bufferView = bufferViews[i];
entry.type = DescriptorWriteType::BufferView;
entry.descriptorType = descType;
}
}
static bool isBindingFeasibleForAlloc(
const DescriptorPoolAllocationInfo::DescriptorCountInfo& countInfo,
const VkDescriptorSetLayoutBinding& binding) {
if (binding.descriptorCount && (countInfo.type != binding.descriptorType)) {
return false;
}
uint32_t availDescriptorCount =
countInfo.descriptorCount - countInfo.used;
if (availDescriptorCount < binding.descriptorCount) {
ALOGV("%s: Ran out of descriptors of type 0x%x. "
"Wanted %u from layout but "
"we only have %u free (total in pool: %u)\n", __func__,
binding.descriptorType,
binding.descriptorCount,
countInfo.descriptorCount - countInfo.used,
countInfo.descriptorCount);
return false;
}
return true;
}
static bool isBindingFeasibleForFree(
const DescriptorPoolAllocationInfo::DescriptorCountInfo& countInfo,
const VkDescriptorSetLayoutBinding& binding) {
if (countInfo.type != binding.descriptorType) return false;
if (countInfo.used < binding.descriptorCount) {
ALOGV("%s: Was a descriptor set double freed? "
"Ran out of descriptors of type 0x%x. "
"Wanted to free %u from layout but "
"we only have %u used (total in pool: %u)\n", __func__,
binding.descriptorType,
binding.descriptorCount,
countInfo.used,
countInfo.descriptorCount);
return false;
}
return true;
}
static void allocBindingFeasible(
const VkDescriptorSetLayoutBinding& binding,
DescriptorPoolAllocationInfo::DescriptorCountInfo& poolState) {
poolState.used += binding.descriptorCount;
}
static void freeBindingFeasible(
const VkDescriptorSetLayoutBinding& binding,
DescriptorPoolAllocationInfo::DescriptorCountInfo& poolState) {
poolState.used -= binding.descriptorCount;
}
static VkResult validateDescriptorSetAllocation(const VkDescriptorSetAllocateInfo* pAllocateInfo) {
VkDescriptorPool pool = pAllocateInfo->descriptorPool;
DescriptorPoolAllocationInfo* poolInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
// Check the number of sets available.
auto setsAvailable = poolInfo->maxSets - poolInfo->usedSets;
if (setsAvailable < pAllocateInfo->descriptorSetCount) {
ALOGV("%s: Error: VkDescriptorSetAllocateInfo wants %u sets "
"but we only have %u available. "
"Bailing with VK_ERROR_OUT_OF_POOL_MEMORY.\n", __func__,
pAllocateInfo->descriptorSetCount,
setsAvailable);
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
// Perform simulated allocation and error out with
// VK_ERROR_OUT_OF_POOL_MEMORY if it fails.
std::vector<DescriptorPoolAllocationInfo::DescriptorCountInfo> descriptorCountCopy =
poolInfo->descriptorCountInfo;
for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; ++i) {
if (!pAllocateInfo->pSetLayouts[i]) {
ALOGV("%s: Error: Tried to allocate a descriptor set with null set layout.\n", __func__);
return VK_ERROR_INITIALIZATION_FAILED;
}
auto setLayoutInfo = as_goldfish_VkDescriptorSetLayout(pAllocateInfo->pSetLayouts[i])->layoutInfo;
if (!setLayoutInfo) {
return VK_ERROR_INITIALIZATION_FAILED;
}
for (const auto& binding : setLayoutInfo->bindings) {
bool success = false;
for (auto& pool : descriptorCountCopy) {
if (!isBindingFeasibleForAlloc(pool, binding)) continue;
success = true;
allocBindingFeasible(binding, pool);
break;
}
if (!success) {
return VK_ERROR_OUT_OF_POOL_MEMORY;
}
}
}
return VK_SUCCESS;
}
void applyDescriptorSetAllocation(VkDescriptorPool pool, VkDescriptorSetLayout setLayout) {
auto allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
auto setLayoutInfo = as_goldfish_VkDescriptorSetLayout(setLayout)->layoutInfo;
++allocInfo->usedSets;
for (const auto& binding : setLayoutInfo->bindings) {
for (auto& countForPool : allocInfo->descriptorCountInfo) {
if (!isBindingFeasibleForAlloc(countForPool, binding)) continue;
allocBindingFeasible(binding, countForPool);
break;
}
}
}
void removeDescriptorSetAllocation(VkDescriptorPool pool, const std::vector<VkDescriptorSetLayoutBinding>& bindings) {
auto allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
if (0 == allocInfo->usedSets) {
ALOGV("%s: Warning: a descriptor set was double freed.\n", __func__);
return;
}
--allocInfo->usedSets;
for (const auto& binding : bindings) {
for (auto& countForPool : allocInfo->descriptorCountInfo) {
if (!isBindingFeasibleForFree(countForPool, binding)) continue;
freeBindingFeasible(binding, countForPool);
break;
}
}
}
void fillDescriptorSetInfoForPool(VkDescriptorPool pool, VkDescriptorSetLayout setLayout, VkDescriptorSet set) {
DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
ReifiedDescriptorSet* newReified = new ReifiedDescriptorSet;
newReified->poolId = as_goldfish_VkDescriptorSet(set)->underlying;
newReified->allocationPending = true;
as_goldfish_VkDescriptorSet(set)->reified = newReified;
allocInfo->allocedPoolIds.insert(newReified->poolId);
allocInfo->allocedSets.insert(set);
initializeReifiedDescriptorSet(pool, setLayout, newReified);
}
VkResult validateAndApplyVirtualDescriptorSetAllocation(const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pSets) {
VkResult validateRes = validateDescriptorSetAllocation(pAllocateInfo);
if (validateRes != VK_SUCCESS) return validateRes;
for (uint32_t i = 0; i < pAllocateInfo->descriptorSetCount; ++i) {
applyDescriptorSetAllocation(pAllocateInfo->descriptorPool, pAllocateInfo->pSetLayouts[i]);
}
VkDescriptorPool pool = pAllocateInfo->descriptorPool;
DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
if (allocInfo->freePoolIds.size() < pAllocateInfo->descriptorSetCount) {
ALOGE("%s: FATAL: Somehow out of descriptor pool IDs. Wanted %u IDs but only have %u free IDs remaining. The count for maxSets was %u and used was %u\n", __func__,
pAllocateInfo->descriptorSetCount,
(uint32_t)allocInfo->freePoolIds.size(),
allocInfo->maxSets,
allocInfo->usedSets);
abort();
}
for (uint32_t i = 0 ; i < pAllocateInfo->descriptorSetCount; ++i) {
uint64_t id = allocInfo->freePoolIds.back();
allocInfo->freePoolIds.pop_back();
VkDescriptorSet newSet = new_from_host_VkDescriptorSet((VkDescriptorSet)id);
pSets[i] = newSet;
fillDescriptorSetInfoForPool(pool, pAllocateInfo->pSetLayouts[i], newSet);
}
return VK_SUCCESS;
}
bool removeDescriptorSetFromPool(VkDescriptorSet set, bool usePoolIds) {
ReifiedDescriptorSet* reified = as_goldfish_VkDescriptorSet(set)->reified;
VkDescriptorPool pool = reified->pool;
DescriptorPoolAllocationInfo* allocInfo = as_goldfish_VkDescriptorPool(pool)->allocInfo;
if (usePoolIds) {
// Look for the set's pool Id in the pool. If not found, then this wasn't really allocated, and bail.
if (allocInfo->allocedPoolIds.find(reified->poolId) == allocInfo->allocedPoolIds.end()) {
return false;
}
}
const std::vector<VkDescriptorSetLayoutBinding>& bindings = reified->bindings;
removeDescriptorSetAllocation(pool, bindings);
if (usePoolIds) {
allocInfo->freePoolIds.push_back(reified->poolId);
allocInfo->allocedPoolIds.erase(reified->poolId);
}
allocInfo->allocedSets.erase(set);
return true;
}
std::vector<VkDescriptorSet> clearDescriptorPool(VkDescriptorPool pool, bool usePoolIds) {
std::vector<VkDescriptorSet> toClear;
for (auto set : as_goldfish_VkDescriptorPool(pool)->allocInfo->allocedSets) {
toClear.push_back(set);
}
for (auto set: toClear) {
removeDescriptorSetFromPool(set, usePoolIds);
}
return toClear;
}
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,153 @@
// Copyright (C) 2021 The Android Open Source Project
// Copyright (C) 2021 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.
#pragma once
#include "aemu/base/containers/EntityManager.h"
#include <vulkan/vulkan.h>
#include <unordered_set>
#include <vector>
namespace gfxstream {
namespace vk {
enum DescriptorWriteType {
Empty = 0,
ImageInfo = 1,
BufferInfo = 2,
BufferView = 3,
InlineUniformBlock = 4,
AccelerationStructure = 5,
};
struct DescriptorWrite {
DescriptorWriteType type;
VkDescriptorType descriptorType;
uint32_t dstArrayElement; // Only used for inlineUniformBlock and accelerationStructure.
union {
VkDescriptorImageInfo imageInfo;
VkDescriptorBufferInfo bufferInfo;
VkBufferView bufferView;
VkWriteDescriptorSetInlineUniformBlockEXT inlineUniformBlock;
VkWriteDescriptorSetAccelerationStructureKHR accelerationStructure;
};
std::vector<uint8_t> inlineUniformBlockBuffer;
};
using DescriptorWriteTable = std::vector<std::vector<DescriptorWrite>>;
struct DescriptorWriteArrayRange {
uint32_t begin;
uint32_t count;
};
using DescriptorWriteDstArrayRangeTable = std::vector<std::vector<DescriptorWriteArrayRange>>;
struct ReifiedDescriptorSet {
VkDescriptorPool pool;
VkDescriptorSetLayout setLayout;
uint64_t poolId;
bool allocationPending;
// Indexed first by binding number
DescriptorWriteTable allWrites;
// Indexed first by binding number
DescriptorWriteDstArrayRangeTable pendingWriteArrayRanges;
// Indexed by binding number
std::vector<bool> bindingIsImmutableSampler;
// Copied from the descriptor set layout
std::vector<VkDescriptorSetLayoutBinding> bindings;
};
struct DescriptorPoolAllocationInfo {
VkDevice device;
VkDescriptorPoolCreateFlags createFlags;
// TODO: This should be in a single fancy data structure of some kind.
std::vector<uint64_t> freePoolIds;
std::unordered_set<uint32_t> allocedPoolIds;
std::unordered_set<VkDescriptorSet> allocedSets;
uint32_t maxSets;
uint32_t usedSets;
// Fine-grained tracking of descriptor counts in individual pools
struct DescriptorCountInfo {
VkDescriptorType type;
uint32_t descriptorCount;
uint32_t used;
};
std::vector<DescriptorCountInfo> descriptorCountInfo;
};
struct DescriptorSetLayoutInfo {
std::vector<VkDescriptorSetLayoutBinding> bindings;
uint32_t refcount;
};
void clearReifiedDescriptorSet(ReifiedDescriptorSet* set);
void initDescriptorWriteTable(const std::vector<VkDescriptorSetLayoutBinding>& layoutBindings, DescriptorWriteTable& table);
bool isDescriptorTypeImageInfo(VkDescriptorType descType);
bool isDescriptorTypeBufferInfo(VkDescriptorType descType);
bool isDescriptorTypeBufferView(VkDescriptorType descType);
bool isDescriptorTypeInlineUniformBlock(VkDescriptorType descType);
bool isDescriptorTypeAccelerationStructure(VkDescriptorType descType);
void doEmulatedDescriptorWrite(const VkWriteDescriptorSet* write, ReifiedDescriptorSet* toWrite);
void doEmulatedDescriptorCopy(const VkCopyDescriptorSet* copy, const ReifiedDescriptorSet* src, ReifiedDescriptorSet* dst);
void doEmulatedDescriptorImageInfoWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkDescriptorImageInfo* imageInfos,
ReifiedDescriptorSet* set);
void doEmulatedDescriptorBufferInfoWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkDescriptorBufferInfo* bufferInfos,
ReifiedDescriptorSet* set);
void doEmulatedDescriptorBufferViewWriteFromTemplate(
VkDescriptorType descType,
uint32_t binding,
uint32_t dstArrayElement,
uint32_t count,
const VkBufferView* bufferViews,
ReifiedDescriptorSet* set);
void applyDescriptorSetAllocation(VkDescriptorPool pool, VkDescriptorSetLayout setLayout);
void fillDescriptorSetInfoForPool(VkDescriptorPool pool, VkDescriptorSetLayout setLayout, VkDescriptorSet set);
VkResult validateAndApplyVirtualDescriptorSetAllocation(const VkDescriptorSetAllocateInfo* pAllocateInfo, VkDescriptorSet* pSets);
// Returns false if set wasn't found in its pool.
bool removeDescriptorSetFromPool(VkDescriptorSet set, bool usePoolIds);
std::vector<VkDescriptorSet> clearDescriptorPool(VkDescriptorPool pool, bool usePoolIds);
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,73 @@
// 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 "HostVisibleMemoryVirtualization.h"
#include <log/log.h>
#include <set>
#include "../OpenglSystemCommon/EmulatorFeatureInfo.h"
#include "ResourceTracker.h"
#include "Resources.h"
#include "VkEncoder.h"
#include "aemu/base/AndroidSubAllocator.h"
using android::base::guest::SubAllocator;
namespace gfxstream {
namespace vk {
bool isHostVisible(const VkPhysicalDeviceMemoryProperties* memoryProps, uint32_t index) {
return memoryProps->memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
}
CoherentMemory::CoherentMemory(VirtGpuBlobMappingPtr blobMapping, uint64_t size, VkDevice device,
VkDeviceMemory memory)
: mSize(size), mBlobMapping(blobMapping), mDevice(device), mMemory(memory) {
mAllocator =
std::make_unique<android::base::guest::SubAllocator>(blobMapping->asRawPtr(), mSize, 4096);
}
CoherentMemory::CoherentMemory(GoldfishAddressSpaceBlockPtr block, uint64_t gpuAddr, uint64_t size,
VkDevice device, VkDeviceMemory memory)
: mSize(size), mBlock(block), mDevice(device), mMemory(memory) {
void* address = block->mmap(gpuAddr);
mAllocator =
std::make_unique<android::base::guest::SubAllocator>(address, mSize, kLargestPageSize);
}
CoherentMemory::~CoherentMemory() {
ResourceTracker::getThreadLocalEncoder()->vkFreeMemorySyncGOOGLE(mDevice, mMemory, nullptr,
false);
}
VkDeviceMemory CoherentMemory::getDeviceMemory() const { return mMemory; }
bool CoherentMemory::subAllocate(uint64_t size, uint8_t** ptr, uint64_t& offset) {
auto address = mAllocator->alloc(size);
if (!address) return false;
*ptr = (uint8_t*)address;
offset = mAllocator->getOffset(address);
return true;
}
bool CoherentMemory::release(uint8_t* ptr) {
mAllocator->free(ptr);
return true;
}
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,70 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#include "VirtGpu.h"
#include "aemu/base/AndroidSubAllocator.h"
#include "goldfish_address_space.h"
constexpr uint64_t kMegaByte = 1048576;
// This needs to be a power of 2 that is at least the min alignment needed
// in HostVisibleMemoryVirtualization.cpp.
// Some Windows drivers require a 64KB alignment for suballocated memory (b:152769369) for YUV
// images.
constexpr uint64_t kLargestPageSize = 65536;
constexpr uint64_t kDefaultHostMemBlockSize = 16 * kMegaByte; // 16 mb
constexpr uint64_t kHostVisibleHeapSize = 512 * kMegaByte; // 512 mb
namespace gfxstream {
namespace vk {
bool isHostVisible(const VkPhysicalDeviceMemoryProperties* memoryProps, uint32_t index);
using GoldfishAddressSpaceBlockPtr = std::shared_ptr<GoldfishAddressSpaceBlock>;
using SubAllocatorPtr = std::unique_ptr<android::base::guest::SubAllocator>;
class CoherentMemory {
public:
CoherentMemory(VirtGpuBlobMappingPtr blobMapping, uint64_t size, VkDevice device,
VkDeviceMemory memory);
CoherentMemory(GoldfishAddressSpaceBlockPtr block, uint64_t gpuAddr, uint64_t size,
VkDevice device, VkDeviceMemory memory);
~CoherentMemory();
VkDeviceMemory getDeviceMemory() const;
bool subAllocate(uint64_t size, uint8_t** ptr, uint64_t& offset);
bool release(uint8_t* ptr);
private:
CoherentMemory(CoherentMemory const&);
void operator=(CoherentMemory const&);
uint64_t mSize;
VirtGpuBlobMappingPtr mBlobMapping = nullptr;
GoldfishAddressSpaceBlockPtr mBlock = nullptr;
VkDevice mDevice;
VkDeviceMemory mMemory;
SubAllocatorPtr mAllocator;
};
using CoherentMemoryPtr = std::shared_ptr<CoherentMemory>;
} // namespace vk
} // namespace gfxstream
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,687 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#include <functional>
#include <memory>
#include "CommandBufferStagingStream.h"
#include "VulkanHandleMapping.h"
#include "VulkanHandles.h"
#include "aemu/base/Tracing.h"
#include "goldfish_vk_transform_guest.h"
struct EmulatorFeatureInfo;
class HostConnection;
namespace gfxstream {
namespace vk {
class VkEncoder;
class ResourceTracker {
public:
ResourceTracker();
virtual ~ResourceTracker();
static ResourceTracker* get();
VulkanHandleMapping* createMapping();
VulkanHandleMapping* unwrapMapping();
VulkanHandleMapping* destroyMapping();
VulkanHandleMapping* defaultMapping();
using HostConnectionGetFunc = HostConnection* (*)();
using VkEncoderGetFunc = VkEncoder* (*)(HostConnection*);
using CleanupCallback = std::function<void()>;
struct ThreadingCallbacks {
HostConnectionGetFunc hostConnectionGetFunc = 0;
VkEncoderGetFunc vkEncoderGetFunc = 0;
};
static uint32_t streamFeatureBits;
static ThreadingCallbacks threadingCallbacks;
#define HANDLE_REGISTER_DECL(type) \
void register_##type(type); \
void unregister_##type(type); \
GOLDFISH_VK_LIST_HANDLE_TYPES(HANDLE_REGISTER_DECL)
VkResult on_vkEnumerateInstanceExtensionProperties(
void* context,
VkResult input_result,
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
VkResult on_vkEnumerateDeviceExtensionProperties(
void* context,
VkResult input_result,
VkPhysicalDevice physicalDevice,
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
VkResult on_vkEnumeratePhysicalDevices(
void* context, VkResult input_result,
VkInstance instance, uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices);
void on_vkGetPhysicalDeviceFeatures2(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2* pFeatures);
void on_vkGetPhysicalDeviceFeatures2KHR(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceFeatures2* pFeatures);
void on_vkGetPhysicalDeviceProperties(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties* pProperties);
void on_vkGetPhysicalDeviceProperties2(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties2* pProperties);
void on_vkGetPhysicalDeviceProperties2KHR(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceProperties2* pProperties);
void on_vkGetPhysicalDeviceMemoryProperties(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties* pMemoryProperties);
void on_vkGetPhysicalDeviceMemoryProperties2(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
void on_vkGetPhysicalDeviceMemoryProperties2KHR(
void* context,
VkPhysicalDevice physicalDevice,
VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
void on_vkGetDeviceQueue(void* context,
VkDevice device,
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue);
void on_vkGetDeviceQueue2(void* context,
VkDevice device,
const VkDeviceQueueInfo2* pQueueInfo,
VkQueue* pQueue);
VkResult on_vkCreateInstance(
void* context,
VkResult input_result,
const VkInstanceCreateInfo* createInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
VkResult on_vkCreateDevice(
void* context,
VkResult input_result,
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice);
void on_vkDestroyDevice_pre(
void* context,
VkDevice device,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkAllocateMemory(
void* context,
VkResult input_result,
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory);
void on_vkFreeMemory(
void* context,
VkDevice device,
VkDeviceMemory memory,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkMapMemory(
void* context,
VkResult input_result,
VkDevice device,
VkDeviceMemory memory,
VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags,
void** ppData);
void on_vkUnmapMemory(
void* context,
VkDevice device,
VkDeviceMemory memory);
VkResult on_vkCreateImage(
void* context, VkResult input_result,
VkDevice device, const VkImageCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkImage *pImage);
void on_vkDestroyImage(
void* context,
VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator);
void on_vkGetImageMemoryRequirements(
void *context, VkDevice device, VkImage image,
VkMemoryRequirements *pMemoryRequirements);
void on_vkGetImageMemoryRequirements2(
void *context, VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
VkMemoryRequirements2 *pMemoryRequirements);
void on_vkGetImageMemoryRequirements2KHR(
void *context, VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo,
VkMemoryRequirements2 *pMemoryRequirements);
VkResult on_vkBindImageMemory(
void* context, VkResult input_result,
VkDevice device, VkImage image, VkDeviceMemory memory,
VkDeviceSize memoryOffset);
VkResult on_vkBindImageMemory2(
void* context, VkResult input_result,
VkDevice device, uint32_t bindingCount, const VkBindImageMemoryInfo* pBindInfos);
VkResult on_vkBindImageMemory2KHR(
void* context, VkResult input_result,
VkDevice device, uint32_t bindingCount, const VkBindImageMemoryInfo* pBindInfos);
VkResult on_vkCreateBuffer(
void* context, VkResult input_result,
VkDevice device, const VkBufferCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkBuffer *pBuffer);
void on_vkDestroyBuffer(
void* context,
VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator);
void on_vkGetBufferMemoryRequirements(
void* context, VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements);
void on_vkGetBufferMemoryRequirements2(
void* context, VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo,
VkMemoryRequirements2* pMemoryRequirements);
void on_vkGetBufferMemoryRequirements2KHR(
void* context, VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo,
VkMemoryRequirements2* pMemoryRequirements);
VkResult on_vkBindBufferMemory(
void* context, VkResult input_result,
VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset);
VkResult on_vkBindBufferMemory2(
void* context, VkResult input_result,
VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos);
VkResult on_vkBindBufferMemory2KHR(
void* context, VkResult input_result,
VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos);
VkResult on_vkCreateSemaphore(
void* context, VkResult,
VkDevice device, const VkSemaphoreCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSemaphore* pSemaphore);
void on_vkDestroySemaphore(
void* context,
VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator);
VkResult on_vkGetSemaphoreFdKHR(
void* context, VkResult,
VkDevice device,
const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
int* pFd);
VkResult on_vkImportSemaphoreFdKHR(
void* context, VkResult,
VkDevice device,
const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo);
VkResult on_vkQueueSubmit(
void* context, VkResult input_result,
VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
VkResult on_vkQueueWaitIdle(
void* context, VkResult input_result,
VkQueue queue);
void unwrap_VkNativeBufferANDROID(
const VkImageCreateInfo* pCreateInfo,
VkImageCreateInfo* local_pCreateInfo);
void unwrap_vkAcquireImageANDROID_nativeFenceFd(int fd, int* fd_out);
#ifdef VK_USE_PLATFORM_FUCHSIA
VkResult on_vkGetMemoryZirconHandleFUCHSIA(
void* context, VkResult input_result,
VkDevice device,
const VkMemoryGetZirconHandleInfoFUCHSIA* pInfo,
uint32_t* pHandle);
VkResult on_vkGetMemoryZirconHandlePropertiesFUCHSIA(
void* context, VkResult input_result,
VkDevice device,
VkExternalMemoryHandleTypeFlagBits handleType,
uint32_t handle,
VkMemoryZirconHandlePropertiesFUCHSIA* pProperties);
VkResult on_vkGetSemaphoreZirconHandleFUCHSIA(
void* context, VkResult input_result,
VkDevice device,
const VkSemaphoreGetZirconHandleInfoFUCHSIA* pInfo,
uint32_t* pHandle);
VkResult on_vkImportSemaphoreZirconHandleFUCHSIA(
void* context, VkResult input_result,
VkDevice device,
const VkImportSemaphoreZirconHandleInfoFUCHSIA* pInfo);
VkResult on_vkCreateBufferCollectionFUCHSIA(
void* context,
VkResult input_result,
VkDevice device,
const VkBufferCollectionCreateInfoFUCHSIA* pInfo,
const VkAllocationCallbacks* pAllocator,
VkBufferCollectionFUCHSIA* pCollection);
void on_vkDestroyBufferCollectionFUCHSIA(
void* context,
VkResult input_result,
VkDevice device,
VkBufferCollectionFUCHSIA collection,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkSetBufferCollectionBufferConstraintsFUCHSIA(
void* context,
VkResult input_result,
VkDevice device,
VkBufferCollectionFUCHSIA collection,
const VkBufferConstraintsInfoFUCHSIA* pBufferConstraintsInfo);
VkResult on_vkSetBufferCollectionImageConstraintsFUCHSIA(
void* context,
VkResult input_result,
VkDevice device,
VkBufferCollectionFUCHSIA collection,
const VkImageConstraintsInfoFUCHSIA* pImageConstraintsInfo);
VkResult on_vkGetBufferCollectionPropertiesFUCHSIA(
void* context,
VkResult input_result,
VkDevice device,
VkBufferCollectionFUCHSIA collection,
VkBufferCollectionPropertiesFUCHSIA* pProperties);
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
VkResult on_vkGetAndroidHardwareBufferPropertiesANDROID(
void* context, VkResult input_result,
VkDevice device,
const AHardwareBuffer* buffer,
VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VkResult on_vkGetMemoryAndroidHardwareBufferANDROID(
void* context, VkResult input_result,
VkDevice device,
const VkMemoryGetAndroidHardwareBufferInfoANDROID *pInfo,
struct AHardwareBuffer** pBuffer);
#endif
VkResult on_vkCreateSamplerYcbcrConversion(
void* context, VkResult input_result,
VkDevice device,
const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSamplerYcbcrConversion* pYcbcrConversion);
void on_vkDestroySamplerYcbcrConversion(
void* context,
VkDevice device,
VkSamplerYcbcrConversion ycbcrConversion,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkCreateSamplerYcbcrConversionKHR(
void* context, VkResult input_result,
VkDevice device,
const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSamplerYcbcrConversion* pYcbcrConversion);
void on_vkDestroySamplerYcbcrConversionKHR(
void* context,
VkDevice device,
VkSamplerYcbcrConversion ycbcrConversion,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkCreateSampler(
void* context, VkResult input_result,
VkDevice device,
const VkSamplerCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSampler* pSampler);
void on_vkGetPhysicalDeviceExternalFenceProperties(
void* context,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
VkExternalFenceProperties* pExternalFenceProperties);
void on_vkGetPhysicalDeviceExternalFencePropertiesKHR(
void* context,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
VkExternalFenceProperties* pExternalFenceProperties);
VkResult on_vkCreateFence(
void* context,
VkResult input_result,
VkDevice device,
const VkFenceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator, VkFence* pFence);
void on_vkDestroyFence(
void* context,
VkDevice device,
VkFence fence,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkResetFences(
void* context,
VkResult input_result,
VkDevice device,
uint32_t fenceCount,
const VkFence* pFences);
VkResult on_vkImportFenceFdKHR(
void* context,
VkResult input_result,
VkDevice device,
const VkImportFenceFdInfoKHR* pImportFenceFdInfo);
VkResult on_vkGetFenceFdKHR(
void* context,
VkResult input_result,
VkDevice device,
const VkFenceGetFdInfoKHR* pGetFdInfo,
int* pFd);
VkResult on_vkWaitForFences(
void* context,
VkResult input_result,
VkDevice device,
uint32_t fenceCount,
const VkFence* pFences,
VkBool32 waitAll,
uint64_t timeout);
VkResult on_vkCreateDescriptorPool(
void* context,
VkResult input_result,
VkDevice device,
const VkDescriptorPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorPool* pDescriptorPool);
void on_vkDestroyDescriptorPool(
void* context,
VkDevice device,
VkDescriptorPool descriptorPool,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkResetDescriptorPool(
void* context,
VkResult input_result,
VkDevice device,
VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags flags);
VkResult on_vkAllocateDescriptorSets(
void* context,
VkResult input_result,
VkDevice device,
const VkDescriptorSetAllocateInfo* pAllocateInfo,
VkDescriptorSet* pDescriptorSets);
VkResult on_vkFreeDescriptorSets(
void* context,
VkResult input_result,
VkDevice device,
VkDescriptorPool descriptorPool,
uint32_t descriptorSetCount,
const VkDescriptorSet* pDescriptorSets);
VkResult on_vkCreateDescriptorSetLayout(
void* context,
VkResult input_result,
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorSetLayout* pSetLayout);
void on_vkUpdateDescriptorSets(
void* context,
VkDevice device,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites,
uint32_t descriptorCopyCount,
const VkCopyDescriptorSet* pDescriptorCopies);
VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE_pre(
void* context,
VkResult input_result,
VkDevice device,
VkDeviceMemory memory,
uint64_t* pAddress);
VkResult on_vkMapMemoryIntoAddressSpaceGOOGLE(
void* context,
VkResult input_result,
VkDevice device,
VkDeviceMemory memory,
uint64_t* pAddress);
VkResult on_vkCreateDescriptorUpdateTemplate(
void* context, VkResult input_result,
VkDevice device,
const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
VkResult on_vkCreateDescriptorUpdateTemplateKHR(
void* context, VkResult input_result,
VkDevice device,
const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
void on_vkUpdateDescriptorSetWithTemplate(
void* context,
VkDevice device,
VkDescriptorSet descriptorSet,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData);
VkResult on_vkGetPhysicalDeviceImageFormatProperties2(
void* context, VkResult input_result,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
VkImageFormatProperties2* pImageFormatProperties);
VkResult on_vkGetPhysicalDeviceImageFormatProperties2KHR(
void* context, VkResult input_result,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
VkImageFormatProperties2* pImageFormatProperties);
void on_vkGetPhysicalDeviceExternalSemaphoreProperties(
void* context,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
void on_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
void* context,
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
void registerEncoderCleanupCallback(const VkEncoder* encoder, void* handle, CleanupCallback callback);
void unregisterEncoderCleanupCallback(const VkEncoder* encoder, void* handle);
void onEncoderDeleted(const VkEncoder* encoder);
uint32_t syncEncodersForCommandBuffer(VkCommandBuffer commandBuffer, VkEncoder* current);
uint32_t syncEncodersForQueue(VkQueue queue, VkEncoder* current);
CommandBufferStagingStream::Alloc getAlloc();
CommandBufferStagingStream::Free getFree();
VkResult on_vkBeginCommandBuffer(
void* context, VkResult input_result,
VkCommandBuffer commandBuffer,
const VkCommandBufferBeginInfo* pBeginInfo);
VkResult on_vkEndCommandBuffer(
void* context, VkResult input_result,
VkCommandBuffer commandBuffer);
VkResult on_vkResetCommandBuffer(
void* context, VkResult input_result,
VkCommandBuffer commandBuffer,
VkCommandBufferResetFlags flags);
VkResult on_vkCreateImageView(
void* context, VkResult input_result,
VkDevice device,
const VkImageViewCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkImageView* pView);
void on_vkCmdExecuteCommands(
void* context,
VkCommandBuffer commandBuffer,
uint32_t commandBufferCount,
const VkCommandBuffer* pCommandBuffers);
void on_vkCmdBindDescriptorSets(
void* context,
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t descriptorSetCount,
const VkDescriptorSet* pDescriptorSets,
uint32_t dynamicOffsetCount,
const uint32_t* pDynamicOffsets);
void on_vkCmdPipelineBarrier(
void* context,
VkCommandBuffer commandBuffer,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier* pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier* pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier* pImageMemoryBarriers);
void on_vkDestroyDescriptorSetLayout(
void* context,
VkDevice device,
VkDescriptorSetLayout descriptorSetLayout,
const VkAllocationCallbacks* pAllocator);
VkResult on_vkAllocateCommandBuffers(
void* context,
VkResult input_result,
VkDevice device,
const VkCommandBufferAllocateInfo* pAllocateInfo,
VkCommandBuffer* pCommandBuffers);
VkResult on_vkQueueSignalReleaseImageANDROID(
void* context,
VkResult input_result,
VkQueue queue,
uint32_t waitSemaphoreCount,
const VkSemaphore* pWaitSemaphores,
VkImage image,
int* pNativeFenceFd);
VkResult on_vkCreateGraphicsPipelines(
void* context,
VkResult input_result,
VkDevice device,
VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkGraphicsPipelineCreateInfo* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines);
uint8_t* getMappedPointer(VkDeviceMemory memory);
VkDeviceSize getMappedSize(VkDeviceMemory memory);
VkDeviceSize getNonCoherentExtendedSize(VkDevice device, VkDeviceSize basicSize) const;
bool isValidMemoryRange(const VkMappedMemoryRange& range) const;
void setupFeatures(const EmulatorFeatureInfo* features);
void setupCaps(void);
void setThreadingCallbacks(const ThreadingCallbacks& callbacks);
bool hostSupportsVulkan() const;
bool usingDirectMapping() const;
uint32_t getStreamFeatures() const;
uint32_t getApiVersionFromInstance(VkInstance instance) const;
uint32_t getApiVersionFromDevice(VkDevice device) const;
bool hasInstanceExtension(VkInstance instance, const std::string& name) const;
bool hasDeviceExtension(VkDevice instance, const std::string& name) const;
VkDevice getDevice(VkCommandBuffer commandBuffer) const;
void addToCommandPool(VkCommandPool commandPool,
uint32_t commandBufferCount,
VkCommandBuffer* pCommandBuffers);
void resetCommandPoolStagingInfo(VkCommandPool commandPool);
#ifdef __GNUC__
#define ALWAYS_INLINE
#elif
#define ALWAYS_INLINE __attribute__((always_inline))
#endif
static VkEncoder* getCommandBufferEncoder(VkCommandBuffer commandBuffer);
static VkEncoder* getQueueEncoder(VkQueue queue);
static VkEncoder* getThreadLocalEncoder();
static void setSeqnoPtr(uint32_t* seqnoptr);
static ALWAYS_INLINE uint32_t nextSeqno();
static ALWAYS_INLINE uint32_t getSeqno();
// Transforms
void deviceMemoryTransform_tohost(
VkDeviceMemory* memory, uint32_t memoryCount,
VkDeviceSize* offset, uint32_t offsetCount,
VkDeviceSize* size, uint32_t sizeCount,
uint32_t* typeIndex, uint32_t typeIndexCount,
uint32_t* typeBits, uint32_t typeBitsCount);
void deviceMemoryTransform_fromhost(
VkDeviceMemory* memory, uint32_t memoryCount,
VkDeviceSize* offset, uint32_t offsetCount,
VkDeviceSize* size, uint32_t sizeCount,
uint32_t* typeIndex, uint32_t typeIndexCount,
uint32_t* typeBits, uint32_t typeBitsCount);
void transformImpl_VkExternalMemoryProperties_fromhost(
VkExternalMemoryProperties* pProperties,
uint32_t);
void transformImpl_VkExternalMemoryProperties_tohost(
VkExternalMemoryProperties* pProperties,
uint32_t);
void transformImpl_VkImageCreateInfo_fromhost(const VkImageCreateInfo*, uint32_t);
void transformImpl_VkImageCreateInfo_tohost(const VkImageCreateInfo*, uint32_t);
#define DEFINE_TRANSFORMED_TYPE_PROTOTYPE(type) \
void transformImpl_##type##_tohost(type*, uint32_t); \
void transformImpl_##type##_fromhost(type*, uint32_t);
LIST_TRIVIAL_TRANSFORMED_TYPES(DEFINE_TRANSFORMED_TYPE_PROTOTYPE)
private:
class Impl;
std::unique_ptr<Impl> mImpl;
};
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,266 @@
// 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 "Resources.h"
#include <log/log.h>
#include <stdlib.h>
#define GOLDFISH_VK_OBJECT_DEBUG 0
#if GOLDFISH_VK_OBJECT_DEBUG
#define D(fmt,...) ALOGD("%s: " fmt, __func__, ##__VA_ARGS__);
#else
#ifndef D
#define D(fmt,...)
#endif
#endif
extern "C" {
#define GOLDFISH_VK_NEW_DISPATCHABLE_FROM_HOST_IMPL(type) \
type new_from_host_##type(type underlying) { \
struct goldfish_##type* res = \
static_cast<goldfish_##type*>(malloc(sizeof(goldfish_##type))); \
if (!res) { \
ALOGE("FATAL: Failed to alloc " #type " handle"); \
abort(); \
} \
res->dispatch.magic = HWVULKAN_DISPATCH_MAGIC; \
res->underlying = (uint64_t)underlying; \
res->lastUsedEncoder = nullptr; \
res->sequenceNumber = 0; \
res->privateEncoder = 0; \
res->privateStream = 0; \
res->flags = 0; \
res->poolObjects = 0; \
res->subObjects = 0; \
res->superObjects = 0; \
res->userPtr = 0; \
return reinterpret_cast<type>(res); \
} \
#define GOLDFISH_VK_NEW_TRIVIAL_NON_DISPATCHABLE_FROM_HOST_IMPL(type) \
type new_from_host_##type(type underlying) { \
struct goldfish_##type* res = \
static_cast<goldfish_##type*>(malloc(sizeof(goldfish_##type))); \
res->underlying = (uint64_t)underlying; \
res->poolObjects = 0; \
res->subObjects = 0; \
res->superObjects = 0; \
res->userPtr = 0; \
return reinterpret_cast<type>(res); \
} \
#define GOLDFISH_VK_AS_GOLDFISH_IMPL(type) \
struct goldfish_##type* as_goldfish_##type(type toCast) { \
return reinterpret_cast<goldfish_##type*>(toCast); \
} \
#define GOLDFISH_VK_GET_HOST_IMPL(type) \
type get_host_##type(type toUnwrap) { \
if (!toUnwrap) return VK_NULL_HANDLE; \
auto as_goldfish = as_goldfish_##type(toUnwrap); \
return (type)(as_goldfish->underlying); \
} \
#define GOLDFISH_VK_DELETE_GOLDFISH_IMPL(type) \
void delete_goldfish_##type(type toDelete) { \
D("guest %p", toDelete); \
free(as_goldfish_##type(toDelete)); \
} \
#define GOLDFISH_VK_IDENTITY_IMPL(type) \
type vk_handle_identity_##type(type handle) { \
return handle; \
} \
#define GOLDFISH_VK_NEW_DISPATCHABLE_FROM_HOST_U64_IMPL(type) \
type new_from_host_u64_##type(uint64_t underlying) { \
struct goldfish_##type* res = \
static_cast<goldfish_##type*>(malloc(sizeof(goldfish_##type))); \
if (!res) { \
ALOGE("FATAL: Failed to alloc " #type " handle"); \
abort(); \
} \
res->dispatch.magic = HWVULKAN_DISPATCH_MAGIC; \
res->underlying = underlying; \
res->lastUsedEncoder = nullptr; \
res->sequenceNumber = 0; \
res->privateEncoder = 0; \
res->privateStream = 0; \
res->flags = 0; \
res->poolObjects = 0; \
res->subObjects = 0; \
res->superObjects = 0; \
res->userPtr = 0; \
return reinterpret_cast<type>(res); \
} \
#define GOLDFISH_VK_NEW_TRIVIAL_NON_DISPATCHABLE_FROM_HOST_U64_IMPL(type) \
type new_from_host_u64_##type(uint64_t underlying) { \
struct goldfish_##type* res = \
static_cast<goldfish_##type*>(malloc(sizeof(goldfish_##type))); \
res->underlying = underlying; \
D("guest %p: host u64: 0x%llx", res, (unsigned long long)res->underlying); \
res->poolObjects = 0; \
res->subObjects = 0; \
res->superObjects = 0; \
res->userPtr = 0; \
return reinterpret_cast<type>(res); \
} \
#define GOLDFISH_VK_GET_HOST_U64_IMPL(type) \
uint64_t get_host_u64_##type(type toUnwrap) { \
if (!toUnwrap) return 0; \
auto as_goldfish = as_goldfish_##type(toUnwrap); \
D("guest %p: host u64: 0x%llx", toUnwrap, (unsigned long long)as_goldfish->underlying); \
return as_goldfish->underlying; \
} \
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_DISPATCHABLE_FROM_HOST_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_AS_GOLDFISH_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DELETE_GOLDFISH_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_IDENTITY_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_DISPATCHABLE_FROM_HOST_U64_IMPL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_U64_IMPL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_AS_GOLDFISH_IMPL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_IMPL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_IDENTITY_IMPL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_U64_IMPL)
GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_TRIVIAL_NON_DISPATCHABLE_FROM_HOST_IMPL)
GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_TRIVIAL_NON_DISPATCHABLE_FROM_HOST_U64_IMPL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DELETE_GOLDFISH_IMPL)
VkDescriptorPool new_from_host_VkDescriptorPool(VkDescriptorPool underlying) {
struct goldfish_VkDescriptorPool* res =
static_cast<goldfish_VkDescriptorPool*>(malloc(sizeof(goldfish_VkDescriptorPool)));
res->underlying = (uint64_t)underlying;
res->allocInfo = nullptr;
return reinterpret_cast<VkDescriptorPool>(res);
}
VkDescriptorPool new_from_host_u64_VkDescriptorPool(uint64_t underlying) {
return new_from_host_VkDescriptorPool((VkDescriptorPool)underlying);
}
VkDescriptorSet new_from_host_VkDescriptorSet(VkDescriptorSet underlying) {
struct goldfish_VkDescriptorSet* res =
static_cast<goldfish_VkDescriptorSet*>(malloc(sizeof(goldfish_VkDescriptorSet)));
res->underlying = (uint64_t)underlying;
res->reified = nullptr;
return reinterpret_cast<VkDescriptorSet>(res);
}
VkDescriptorSet new_from_host_u64_VkDescriptorSet(uint64_t underlying) {
return new_from_host_VkDescriptorSet((VkDescriptorSet)underlying);
}
VkDescriptorSetLayout new_from_host_VkDescriptorSetLayout(VkDescriptorSetLayout underlying) {
struct goldfish_VkDescriptorSetLayout* res =
static_cast<goldfish_VkDescriptorSetLayout*>(malloc(sizeof(goldfish_VkDescriptorSetLayout)));
res->underlying = (uint64_t)underlying;
res->layoutInfo = nullptr;
return reinterpret_cast<VkDescriptorSetLayout>(res);
}
VkDescriptorSetLayout new_from_host_u64_VkDescriptorSetLayout(uint64_t underlying) {
return new_from_host_VkDescriptorSetLayout((VkDescriptorSetLayout)underlying);
}
} // extern "C"
namespace gfxstream {
namespace vk {
void appendObject(struct goldfish_vk_object_list** begin, void* val) {
D("for %p", val);
struct goldfish_vk_object_list* o = new goldfish_vk_object_list;
o->next = nullptr;
o->obj = val;
D("new ptr: %p", o);
if (!*begin) { D("first"); *begin = o; return; }
struct goldfish_vk_object_list* q = *begin;
struct goldfish_vk_object_list* p = q;
while (q) {
p = q;
q = q->next;
}
D("set next of %p to %p", p, o);
p->next = o;
}
void eraseObject(struct goldfish_vk_object_list** begin, void* val) {
D("for val %p", val);
if (!*begin) {
D("val %p notfound", val);
return;
}
struct goldfish_vk_object_list* q = *begin;
struct goldfish_vk_object_list* p = q;
while (q) {
struct goldfish_vk_object_list* n = q->next;
if (val == q->obj) {
D("val %p found, delete", val);
delete q;
if (*begin == q) {
D("val %p set begin to %p:", val, n);
*begin = n;
} else {
D("val %p set pnext to %p:", val, n);
p->next = n;
}
return;
}
p = q;
q = n;
}
D("val %p notfound after looping", val);
}
void eraseObjects(struct goldfish_vk_object_list** begin) {
struct goldfish_vk_object_list* q = *begin;
struct goldfish_vk_object_list* p = q;
while (q) {
p = q;
q = q->next;
delete p;
}
*begin = nullptr;
}
void forAllObjects(struct goldfish_vk_object_list* begin, std::function<void(void*)> func) {
struct goldfish_vk_object_list* q = begin;
struct goldfish_vk_object_list* p = q;
D("call");
while (q) {
D("iter");
p = q;
q = q->next;
func(p->obj);
}
}
} // namespace vk
} // namespace gfxstream
+148
View File
@@ -0,0 +1,148 @@
// 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.
#pragma once
#include <hardware/hwvulkan.h>
#include <vulkan/vulkan.h>
#include "VulkanHandles.h"
#include <inttypes.h>
#include <functional>
namespace gfxstream {
class IOStream;
namespace vk {
class VkEncoder;
struct DescriptorPoolAllocationInfo;
struct ReifiedDescriptorSet;
struct DescriptorSetLayoutInfo;
} // namespace vk
} // namespace gfxstream
extern "C" {
struct goldfish_vk_object_list {
void* obj;
struct goldfish_vk_object_list* next;
};
#define GOLDFISH_VK_DEFINE_DISPATCHABLE_HANDLE_STRUCT(type) \
struct goldfish_##type { \
hwvulkan_dispatch_t dispatch; \
uint64_t underlying; \
gfxstream::vk::VkEncoder* lastUsedEncoder; \
uint32_t sequenceNumber; \
gfxstream::vk::VkEncoder* privateEncoder; \
gfxstream::IOStream* privateStream; \
uint32_t flags; \
struct goldfish_vk_object_list* poolObjects; \
struct goldfish_vk_object_list* subObjects; \
struct goldfish_vk_object_list* superObjects; \
void* userPtr; \
}; \
#define GOLDFISH_VK_DEFINE_TRIVIAL_NON_DISPATCHABLE_HANDLE_STRUCT(type) \
struct goldfish_##type { \
uint64_t underlying; \
struct goldfish_vk_object_list* poolObjects; \
struct goldfish_vk_object_list* subObjects; \
struct goldfish_vk_object_list* superObjects; \
void* userPtr; \
}; \
#define GOLDFISH_VK_NEW_FROM_HOST_DECL(type) \
type new_from_host_##type(type);
#define GOLDFISH_VK_AS_GOLDFISH_DECL(type) \
struct goldfish_##type* as_goldfish_##type(type);
#define GOLDFISH_VK_GET_HOST_DECL(type) \
type get_host_##type(type);
#define GOLDFISH_VK_DELETE_GOLDFISH_DECL(type) \
void delete_goldfish_##type(type);
#define GOLDFISH_VK_IDENTITY_DECL(type) \
type vk_handle_identity_##type(type);
#define GOLDFISH_VK_NEW_FROM_HOST_U64_DECL(type) \
type new_from_host_u64_##type(uint64_t);
#define GOLDFISH_VK_GET_HOST_U64_DECL(type) \
uint64_t get_host_u64_##type(type);
GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DEFINE_DISPATCHABLE_HANDLE_STRUCT)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_FROM_HOST_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_AS_GOLDFISH_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DELETE_GOLDFISH_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_IDENTITY_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_FROM_HOST_U64_DECL)
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_U64_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_FROM_HOST_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_AS_GOLDFISH_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DELETE_GOLDFISH_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_IDENTITY_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_NEW_FROM_HOST_U64_DECL)
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_GET_HOST_U64_DECL)
GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_NON_DISPATCHABLE_HANDLE_TYPES(GOLDFISH_VK_DEFINE_TRIVIAL_NON_DISPATCHABLE_HANDLE_STRUCT)
struct goldfish_VkDescriptorPool {
uint64_t underlying;
gfxstream::vk::DescriptorPoolAllocationInfo* allocInfo;
};
struct goldfish_VkDescriptorSet {
uint64_t underlying;
gfxstream::vk::ReifiedDescriptorSet* reified;
};
struct goldfish_VkDescriptorSetLayout {
uint64_t underlying;
gfxstream::vk::DescriptorSetLayoutInfo* layoutInfo;
};
struct goldfish_VkCommandBuffer {
hwvulkan_dispatch_t dispatch;
uint64_t underlying;
gfxstream::vk::VkEncoder* lastUsedEncoder;
uint32_t sequenceNumber;
gfxstream::vk::VkEncoder* privateEncoder;
gfxstream::IOStream* privateStream;
uint32_t flags;
struct goldfish_vk_object_list* poolObjects;
struct goldfish_vk_object_list* subObjects;
struct goldfish_vk_object_list* superObjects;
void* userPtr;
bool isSecondary;
VkDevice device;
};
} // extern "C"
namespace gfxstream {
namespace vk {
void appendObject(struct goldfish_vk_object_list** begin, void* val);
void eraseObject(struct goldfish_vk_object_list** begin, void* val);
void eraseObjects(struct goldfish_vk_object_list** begin);
void forAllObjects(struct goldfish_vk_object_list* begin, std::function<void(void*)> func);
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,59 @@
// 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 "Validation.h"
#include "Resources.h"
#include "ResourceTracker.h"
namespace gfxstream {
namespace vk {
VkResult Validation::on_vkFlushMappedMemoryRanges(
void*,
VkResult,
VkDevice,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges) {
auto resources = ResourceTracker::get();
for (uint32_t i = 0; i < memoryRangeCount; ++i) {
if (!resources->isValidMemoryRange(pMemoryRanges[i])) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
VkResult Validation::on_vkInvalidateMappedMemoryRanges(
void*,
VkResult,
VkDevice,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges) {
auto resources = ResourceTracker::get();
for (uint32_t i = 0; i < memoryRangeCount; ++i) {
if (!resources->isValidMemoryRange(pMemoryRanges[i])) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
}
return VK_SUCCESS;
}
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,38 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
namespace gfxstream {
namespace vk {
class Validation {
public:
VkResult on_vkFlushMappedMemoryRanges(
void* context,
VkResult input_result,
VkDevice device,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges);
VkResult on_vkInvalidateMappedMemoryRanges(
void* context,
VkResult input_result,
VkDevice device,
uint32_t memoryRangeCount,
const VkMappedMemoryRange* pMemoryRanges);
};
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,90 @@
static ResourceTracker* sResourceTracker = nullptr;
static uint32_t sFeatureBits = 0;
static constexpr uint32_t kWatchdogBufferMax = 1'000;
class VkEncoder::Impl {
public:
Impl(IOStream* stream) : m_stream(stream), m_logEncodes(false) {
if (!sResourceTracker) sResourceTracker = ResourceTracker::get();
m_stream.incStreamRef();
const char* emuVkLogEncodesPropName = "qemu.vk.log";
char encodeProp[PROPERTY_VALUE_MAX];
if (property_get(emuVkLogEncodesPropName, encodeProp, nullptr) > 0) {
m_logEncodes = atoi(encodeProp) > 0;
}
sFeatureBits = m_stream.getFeatureBits();
}
~Impl() { m_stream.decStreamRef(); }
VulkanCountingStream* countingStream() { return &m_countingStream; }
VulkanStreamGuest* stream() { return &m_stream; }
BumpPool* pool() { return &m_pool; }
ResourceTracker* resources() { return ResourceTracker::get(); }
Validation* validation() { return &m_validation; }
void log(const char* text) {
if (!m_logEncodes) return;
ALOGD("encoder log: %s", text);
}
void flush() {
lock();
m_stream.flush();
unlock();
}
// can be recursive
void lock() {
while (mLock.test_and_set(std::memory_order_acquire))
;
}
void unlock() { mLock.clear(std::memory_order_release); }
private:
VulkanCountingStream m_countingStream;
VulkanStreamGuest m_stream;
BumpPool m_pool;
Validation m_validation;
bool m_logEncodes;
std::atomic_flag mLock = ATOMIC_FLAG_INIT;
};
VkEncoder::~VkEncoder() {}
struct EncoderAutoLock {
EncoderAutoLock(VkEncoder* enc) : mEnc(enc) { mEnc->lock(); }
~EncoderAutoLock() { mEnc->unlock(); }
VkEncoder* mEnc;
};
VkEncoder::VkEncoder(IOStream* stream, android::base::guest::HealthMonitor<>* healthMonitor)
: mImpl(new VkEncoder::Impl(stream)), mHealthMonitor(healthMonitor) {}
void VkEncoder::flush() { mImpl->flush(); }
void VkEncoder::lock() { mImpl->lock(); }
void VkEncoder::unlock() { mImpl->unlock(); }
void VkEncoder::incRef() { __atomic_add_fetch(&refCount, 1, __ATOMIC_SEQ_CST); }
bool VkEncoder::decRef() {
if (0 == __atomic_sub_fetch(&refCount, 1, __ATOMIC_SEQ_CST)) {
delete this;
return true;
}
return false;
}
std::string VkEncoder::getPacketContents(const uint8_t* ptr, size_t len) {
std::string result;
std::unique_ptr<char[]> buf(new char[3]);
for (size_t i = 0; i < len; i++) {
std::snprintf(buf.get(), 3, "%02X", ptr[i]);
result += " " + std::string(buf.get(), buf.get() + 2);
}
return result;
}
@@ -0,0 +1,10 @@
void flush();
void lock();
void unlock();
void incRef();
bool decRef();
std::string getPacketContents(const uint8_t* ptr, size_t len);
uint32_t refCount = 1;
#define POOL_CLEAR_INTERVAL 10
uint32_t encodeCount = 0;
uint32_t featureBits = 0;
@@ -0,0 +1,35 @@
// 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 <vulkan/vulkan.h>
#include "VulkanHandleMapping.h"
namespace gfxstream {
namespace vk {
#define DEFAULT_HANDLE_MAP_DEFINE(type) \
void DefaultHandleMapping::mapHandles_##type(type*, size_t) { return; } \
void DefaultHandleMapping::mapHandles_##type##_u64(const type* handles, uint64_t* handle_u64s, size_t count) { \
for (size_t i = 0; i < count; ++i) { handle_u64s[i] = (uint64_t)(uintptr_t)handles[i]; } \
} \
void DefaultHandleMapping::mapHandles_u64_##type(const uint64_t* handle_u64s, type* handles, size_t count) { \
for (size_t i = 0; i < count; ++i) { handles[i] = (type)(uintptr_t)handle_u64s[i]; } \
} \
GOLDFISH_VK_LIST_HANDLE_TYPES(DEFAULT_HANDLE_MAP_DEFINE)
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,50 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#include "VulkanHandles.h"
namespace gfxstream {
namespace vk {
class VulkanHandleMapping {
public:
VulkanHandleMapping() = default;
virtual ~VulkanHandleMapping() { }
#define DECLARE_HANDLE_MAP_PURE_VIRTUAL_METHOD(type) \
virtual void mapHandles_##type(type* handles, size_t count = 1) = 0; \
virtual void mapHandles_##type##_u64(const type* handles, uint64_t* handle_u64s, size_t count = 1) = 0; \
virtual void mapHandles_u64_##type(const uint64_t* handle_u64s, type* handles, size_t count = 1) = 0; \
GOLDFISH_VK_LIST_HANDLE_TYPES(DECLARE_HANDLE_MAP_PURE_VIRTUAL_METHOD)
};
class DefaultHandleMapping : public VulkanHandleMapping {
public:
virtual ~DefaultHandleMapping() { }
#define DECLARE_HANDLE_MAP_OVERRIDE(type) \
void mapHandles_##type(type* handles, size_t count) override; \
void mapHandles_##type##_u64(const type* handles, uint64_t* handle_u64s, size_t count) override; \
void mapHandles_u64_##type(const uint64_t* handle_u64s, type* handles, size_t count) override; \
GOLDFISH_VK_LIST_HANDLE_TYPES(DECLARE_HANDLE_MAP_OVERRIDE)
};
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,172 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
namespace gfxstream {
namespace vk {
#define GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkPhysicalDevice) \
#define GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkInstance) \
f(VkDevice) \
f(VkCommandBuffer) \
f(VkQueue) \
GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f)
#ifdef VK_NVX_binary_import
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_BINARY_IMPORT(f) \
f(VkCuModuleNVX) \
f(VkCuFunctionNVX) \
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_BINARY_IMPORT(f)
#endif // VK_NVX_binary_import
#ifdef VK_NVX_device_generated_commands
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_DEVICE_GENERATED_COMMANDS(f) \
f(VkObjectTableNVX) \
f(VkIndirectCommandsLayoutNVX) \
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_DEVICE_GENERATED_COMMANDS(f)
#endif // VK_NVX_device_generated_commands
#ifdef VK_NV_device_generated_commands
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_DEVICE_GENERATED_COMMANDS(f) \
f(VkIndirectCommandsLayoutNV) \
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_DEVICE_GENERATED_COMMANDS(f)
#endif // VK_NV_device_generated_commands
#ifdef VK_NV_ray_tracing
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_RAY_TRACING(f) \
f(VkAccelerationStructureNV) \
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_RAY_TRACING(f)
#endif // VK_NV_ray_tracing
#ifdef VK_KHR_acceleration_structure
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_KHR_ACCELERATION_STRUCTURE(f) \
f(VkAccelerationStructureKHR) \
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_KHR_ACCELERATION_STRUCTURE(f)
#endif // VK_KHR_acceleration_structure
#ifdef VK_USE_PLATFORM_FUCHSIA
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f) \
f(VkBufferCollectionFUCHSIA)
#else
#define __GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f)
#endif // VK_USE_PLATFORM_FUCHSIA
#define GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkBufferView) \
f(VkImageView) \
f(VkShaderModule) \
f(VkPipeline) \
f(VkPipelineCache) \
f(VkPipelineLayout) \
f(VkRenderPass) \
f(VkFramebuffer) \
f(VkEvent) \
f(VkQueryPool) \
f(VkSamplerYcbcrConversion) \
f(VkSurfaceKHR) \
f(VkSwapchainKHR) \
f(VkDisplayKHR) \
f(VkDisplayModeKHR) \
f(VkValidationCacheEXT) \
f(VkDebugReportCallbackEXT) \
f(VkDebugUtilsMessengerEXT) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_BINARY_IMPORT(f) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NVX_DEVICE_GENERATED_COMMANDS(f) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_DEVICE_GENERATED_COMMANDS(f) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_NV_RAY_TRACING(f) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_KHR_ACCELERATION_STRUCTURE(f) \
#define GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkDeviceMemory) \
f(VkBuffer) \
f(VkImage) \
f(VkSemaphore) \
f(VkDescriptorUpdateTemplate) \
f(VkFence) \
f(VkDescriptorPool) \
f(VkDescriptorSet) \
f(VkDescriptorSetLayout) \
f(VkCommandPool) \
f(VkSampler) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f) \
GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
#define GOLDFISH_VK_LIST_HANDLE_TYPES(f) \
GOLDFISH_VK_LIST_DISPATCHABLE_HANDLE_TYPES(f) \
GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES(f)
#define GOLDFISH_VK_LIST_TRIVIAL_HANDLE_TYPES(f) \
GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f) \
GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f)
#define GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkInstance) \
f(VkDevice) \
f(VkQueue) \
GOLDFISH_VK_LIST_TRIVIAL_DISPATCHABLE_HANDLE_TYPES(f)
#define GOLDFISH_VK_LIST_AUTODEFINED_STRUCT_NON_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkDeviceMemory) \
f(VkBuffer) \
f(VkImage) \
f(VkSemaphore) \
f(VkFence) \
f(VkDescriptorUpdateTemplate) \
f(VkCommandPool) \
f(VkSampler) \
__GOLDFISH_VK_LIST_NON_DISPATCHABLE_HANDLE_TYPES_FUCHSIA(f) \
GOLDFISH_VK_LIST_TRIVIAL_NON_DISPATCHABLE_HANDLE_TYPES(f) \
#define GOLDFISH_VK_LIST_MANUAL_STRUCT_NON_DISPATCHABLE_HANDLE_TYPES(f) \
f(VkDescriptorPool) \
f(VkDescriptorSetLayout) \
f(VkDescriptorSet) \
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,176 @@
// 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 "VulkanStreamGuest.h"
namespace gfxstream {
namespace vk {
VulkanStreamGuest::VulkanStreamGuest(IOStream *stream): mStream(stream) {
unsetHandleMapping();
mFeatureBits = ResourceTracker::get()->getStreamFeatures();
}
VulkanStreamGuest::~VulkanStreamGuest() = default;
bool VulkanStreamGuest::valid() {
return true;
}
void VulkanStreamGuest::alloc(void** ptrAddr, size_t bytes) {
if (!bytes) {
*ptrAddr = nullptr;
return;
}
*ptrAddr = mPool.alloc(bytes);
}
void VulkanStreamGuest::loadStringInPlace(char** forOutput) {
size_t len = getBe32();
alloc((void**)forOutput, len + 1);
memset(*forOutput, 0x0, len + 1);
if (len > 0) read(*forOutput, len);
}
void VulkanStreamGuest::loadStringArrayInPlace(char*** forOutput) {
size_t count = getBe32();
if (!count) {
*forOutput = nullptr;
return;
}
alloc((void**)forOutput, count * sizeof(char*));
char **stringsForOutput = *forOutput;
for (size_t i = 0; i < count; i++) {
loadStringInPlace(stringsForOutput + i);
}
}
void VulkanStreamGuest::loadStringInPlaceWithStreamPtr(char** forOutput, uint8_t** streamPtr) {
uint32_t len;
memcpy(&len, *streamPtr, sizeof(uint32_t));
*streamPtr += sizeof(uint32_t);
android::base::Stream::fromBe32((uint8_t*)&len);
alloc((void**)forOutput, len + 1);
memset(*forOutput, 0x0, len + 1);
if (len > 0) {
memcpy(*forOutput, *streamPtr, len);
*streamPtr += len;
}
}
void VulkanStreamGuest::loadStringArrayInPlaceWithStreamPtr(char*** forOutput, uint8_t** streamPtr) {
uint32_t count;
memcpy(&count, *streamPtr, sizeof(uint32_t));
*streamPtr += sizeof(uint32_t);
android::base::Stream::fromBe32((uint8_t*)&count);
if (!count) {
*forOutput = nullptr;
return;
}
alloc((void**)forOutput, count * sizeof(char*));
char **stringsForOutput = *forOutput;
for (size_t i = 0; i < count; i++) {
loadStringInPlaceWithStreamPtr(stringsForOutput + i, streamPtr);
}
}
ssize_t VulkanStreamGuest::read(void *buffer, size_t size) {
if (!mStream->readback(buffer, size)) {
ALOGE("FATAL: Could not read back %zu bytes", size);
abort();
}
return size;
}
ssize_t VulkanStreamGuest::write(const void *buffer, size_t size) {
uint8_t* streamBuf = (uint8_t*)mStream->alloc(size);
memcpy(streamBuf, buffer, size);
return size;
}
void VulkanStreamGuest::writeLarge(const void* buffer, size_t size) {
mStream->writeFullyAsync(buffer, size);
}
void VulkanStreamGuest::clearPool() {
mPool.freeAll();
}
void VulkanStreamGuest::setHandleMapping(VulkanHandleMapping* mapping) {
mCurrentHandleMapping = mapping;
}
void VulkanStreamGuest::unsetHandleMapping() {
mCurrentHandleMapping = &mDefaultHandleMapping;
}
VulkanHandleMapping* VulkanStreamGuest::handleMapping() const {
return mCurrentHandleMapping;
}
void VulkanStreamGuest::flush() {
AEMU_SCOPED_TRACE("VulkanStreamGuest device write");
mStream->flush();
}
uint32_t VulkanStreamGuest::getFeatureBits() const {
return mFeatureBits;
}
void VulkanStreamGuest::incStreamRef() {
mStream->incRef();
}
bool VulkanStreamGuest::decStreamRef() {
return mStream->decRef();
}
uint8_t* VulkanStreamGuest::reserve(size_t size) {
return (uint8_t*)mStream->alloc(size);
}
VulkanCountingStream::VulkanCountingStream() : VulkanStreamGuest(nullptr) { }
VulkanCountingStream::~VulkanCountingStream() = default;
ssize_t VulkanCountingStream::read(void*, size_t size) {
m_read += size;
return size;
}
ssize_t VulkanCountingStream::write(const void*, size_t size) {
m_written += size;
return size;
}
void VulkanCountingStream::rewind() {
m_written = 0;
m_read = 0;
}
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,107 @@
// 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.
#pragma once
#include "aemu/base/files/Stream.h"
#include "aemu/base/files/StreamSerializing.h"
#include "goldfish_vk_private_defs.h"
#include "VulkanHandleMapping.h"
#include "IOStream.h"
#include "ResourceTracker.h"
#include "aemu/base/BumpPool.h"
#include "aemu/base/Tracing.h"
#include <vector>
#include <memory>
#include <log/log.h>
#include <inttypes.h>
class IOStream;
namespace gfxstream {
namespace vk {
class VulkanStreamGuest : public android::base::Stream {
public:
VulkanStreamGuest(IOStream* stream);
~VulkanStreamGuest();
// Returns whether the connection is valid.
bool valid();
// General allocation function
void alloc(void** ptrAddr, size_t bytes);
// Utility functions to load strings or
// string arrays in place with allocation.
void loadStringInPlace(char** forOutput);
void loadStringArrayInPlace(char*** forOutput);
// When we load a string and are using a reserved pointer.
void loadStringInPlaceWithStreamPtr(char** forOutput, uint8_t** streamPtr);
void loadStringArrayInPlaceWithStreamPtr(char*** forOutput, uint8_t** streamPtr);
ssize_t read(void *buffer, size_t size) override;
ssize_t write(const void *buffer, size_t size) override;
void writeLarge(const void* buffer, size_t size);
// Frees everything that got alloc'ed.
void clearPool();
void setHandleMapping(VulkanHandleMapping* mapping);
void unsetHandleMapping();
VulkanHandleMapping* handleMapping() const;
void flush();
uint32_t getFeatureBits() const;
void incStreamRef();
bool decStreamRef();
uint8_t* reserve(size_t size);
private:
android::base::BumpPool mPool;
std::vector<uint8_t> mWriteBuffer;
IOStream* mStream = nullptr;
DefaultHandleMapping mDefaultHandleMapping;
VulkanHandleMapping* mCurrentHandleMapping;
uint32_t mFeatureBits = 0;
};
class VulkanCountingStream : public VulkanStreamGuest {
public:
VulkanCountingStream();
~VulkanCountingStream();
ssize_t read(void *buffer, size_t size) override;
ssize_t write(const void *buffer, size_t size) override;
size_t bytesWritten() const { return m_written; }
size_t bytesRead() const { return m_read; }
void rewind();
private:
size_t m_written = 0;
size_t m_read = 0;
};
} // namespace vk
} // namespace gfxstream
@@ -0,0 +1,38 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#ifdef __cplusplus
#include <algorithm>
#endif
// VulkanStream features
#define VULKAN_STREAM_FEATURE_NULL_OPTIONAL_STRINGS_BIT (1 << 0)
#define VULKAN_STREAM_FEATURE_IGNORED_HANDLES_BIT (1 << 1)
#define VULKAN_STREAM_FEATURE_SHADER_FLOAT16_INT8_BIT (1 << 2)
#define VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT (1 << 3)
#define VK_YCBCR_CONVERSION_DO_NOTHING ((VkSamplerYcbcrConversion)0x1111111111111111)
#ifdef __cplusplus
template<class T, typename F>
bool arrayany(const T* arr, uint32_t begin, uint32_t end, const F& func) {
const T* e = arr + end;
return std::find_if(arr + begin, e, func) != e;
}
#define DEFINE_ALIAS_FUNCTION(ORIGINAL_FN, ALIAS_FN) \
template <typename... Args> \
inline auto ALIAS_FN(Args&&... args) -> decltype(ORIGINAL_FN(std::forward<Args>(args)...)) { \
return ORIGINAL_FN(std::forward<Args>(args)...); \
}
#endif
@@ -0,0 +1,33 @@
# Copyright 2022 Android Open Source Project
# SPDX-License-Identifier: MIT
files_lib_vulkan_enc = files(
'CommandBufferStagingStream.cpp',
'DescriptorSetVirtualization.cpp',
'HostVisibleMemoryVirtualization.cpp',
'ResourceTracker.cpp',
'Resources.cpp',
'Validation.cpp',
'VkEncoder.cpp',
'VulkanHandleMapping.cpp',
'VulkanStreamGuest.cpp',
'func_table.cpp',
'goldfish_vk_counting_guest.cpp',
'goldfish_vk_counting_guest.h',
'goldfish_vk_deepcopy_guest.cpp',
'goldfish_vk_extension_structs_guest.cpp',
'goldfish_vk_marshaling_guest.cpp',
'goldfish_vk_reserved_marshaling_guest.cpp',
'goldfish_vk_transform_guest.cpp',
)
lib_vulkan_enc = static_library(
'vulkan_enc',
files_lib_vulkan_enc,
cpp_args: cpp_args,
include_directories: [inc_android_emu, inc_host, inc_android_compat,
inc_opengl_codec, inc_render_enc, inc_system,
inc_goldfish_address_space, inc_platform],
link_with: [lib_platform],
dependencies: dependency('libdrm'),
)
@@ -0,0 +1,67 @@
// Manual inline for
// void VkEncoder::vkQueueFlushCommandsGOOGLE( VkQueue queue, VkCommandBuffer commandBuffer, VkDeviceSize dataSize, const void* pData, uint32_t doLock);
// We won't use the lock if this command is used (VulkanQueueSubmitWithCommands is enabled)
(void)doLock;
auto stream = mImpl->stream();
auto pool = mImpl->pool();
VkQueue local_queue;
VkCommandBuffer local_commandBuffer;
VkDeviceSize local_dataSize;
void* local_pData;
local_queue = queue;
local_commandBuffer = commandBuffer;
local_dataSize = dataSize;
// Avoiding deepcopy for pData
local_pData = (void*)pData;
size_t count = 0;
size_t* countPtr = &count;
{
uint64_t cgen_var_1405;
*countPtr += 1 * 8;
uint64_t cgen_var_1406;
*countPtr += 1 * 8;
*countPtr += sizeof(VkDeviceSize);
*countPtr += ((dataSize)) * sizeof(uint8_t);
}
bool queueSubmitWithCommandsEnabled = sFeatureBits & VULKAN_STREAM_FEATURE_QUEUE_SUBMIT_WITH_COMMANDS_BIT;
uint32_t packetSize_vkQueueFlushCommandsGOOGLE = 4 + 4 + (queueSubmitWithCommandsEnabled ? 4 : 0) + count;
healthMonitorAnnotation_packetSize =
std::make_optional(packetSize_vkQueueFlushCommandsGOOGLE);
uint8_t* streamPtr = stream->reserve(packetSize_vkQueueFlushCommandsGOOGLE - local_dataSize);
uint8_t* packetBeginPtr = streamPtr;
uint8_t** streamPtrPtr = &streamPtr;
uint32_t opcode_vkQueueFlushCommandsGOOGLE = OP_vkQueueFlushCommandsGOOGLE;
uint32_t seqno = ResourceTracker::nextSeqno();
healthMonitorAnnotation_seqno = std::make_optional(seqno);
memcpy(streamPtr, &opcode_vkQueueFlushCommandsGOOGLE, sizeof(uint32_t)); streamPtr += sizeof(uint32_t);
memcpy(streamPtr, &packetSize_vkQueueFlushCommandsGOOGLE, sizeof(uint32_t)); streamPtr += sizeof(uint32_t);
memcpy(streamPtr, &seqno, sizeof(uint32_t)); streamPtr += sizeof(uint32_t);
uint64_t cgen_var_1407;
*&cgen_var_1407 = get_host_u64_VkQueue((*&local_queue));
memcpy(*streamPtrPtr, (uint64_t*)&cgen_var_1407, 1 * 8);
*streamPtrPtr += 1 * 8;
uint64_t cgen_var_1408;
*&cgen_var_1408 = get_host_u64_VkCommandBuffer((*&local_commandBuffer));
memcpy(*streamPtrPtr, (uint64_t*)&cgen_var_1408, 1 * 8);
*streamPtrPtr += 1 * 8;
memcpy(*streamPtrPtr, (VkDeviceSize*)&local_dataSize, sizeof(VkDeviceSize));
*streamPtrPtr += sizeof(VkDeviceSize);
if (watchdog) {
size_t watchdogBufSize = std::min<size_t>(
static_cast<size_t>(packetSize_vkQueueFlushCommandsGOOGLE), kWatchdogBufferMax);
healthMonitorAnnotation_packetContents.resize(watchdogBufSize);
memcpy(&healthMonitorAnnotation_packetContents[0], packetBeginPtr, watchdogBufSize);
}
AEMU_SCOPED_TRACE("vkQueueFlush large xfer");
stream->flush();
stream->writeLarge(local_pData, dataSize);
++encodeCount;;
if (0 == encodeCount % POOL_CLEAR_INTERVAL)
{
pool->freeAll();
stream->clearPool();
}
@@ -0,0 +1,222 @@
/*
* Copyright © 2016 Intel Corporation
* Copyright © 2019 The Android Open Source Project
* Copyright © 2019 Google Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef VK_FORMAT_INFO_H
#define VK_FORMAT_INFO_H
#include <stdbool.h>
#ifdef VK_USE_PLATFORM_ANDROID_KHR
#include <system/graphics.h>
#else
/* See system/graphics.h. */
enum {
HAL_PIXEL_FORMAT_YV12 = 842094169,
};
#endif
#include <vulkan/vulkan.h>
#include <vndk/hardware_buffer.h>
namespace gfxstream {
namespace vk {
/* See i915_private_android_types.h in minigbm. */
#define HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL 0x100
// TODO(b/167698976): We should not use OMX_COLOR_FormatYUV420Planar
// but we seem to miss a format translation somewhere.
#define OMX_COLOR_FormatYUV420Planar 0x13
// TODO: update users of this function to query the DRM fourcc
// code using the standard Gralloc4 metadata type and instead
// translate the DRM fourcc code to a Vulkan format as Android
// formats such as AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 could be
// either VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM or
// VK_FORMAT_G8_B8R8_2PLANE_420_UNORM.
static inline VkFormat
vk_format_from_android(unsigned android_format)
{
switch (android_format) {
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
return VK_FORMAT_R8G8B8A8_UNORM;
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
return VK_FORMAT_R8G8B8A8_UNORM;
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
return VK_FORMAT_R8G8B8_UNORM;
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
return VK_FORMAT_R5G6B5_UNORM_PACK16;
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
return VK_FORMAT_R16G16B16A16_SFLOAT;
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
#if __ANDROID_API__ >= 30
case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
#endif
#ifdef VK_USE_PLATFORM_ANDROID_KHR
case HAL_PIXEL_FORMAT_YV12:
case OMX_COLOR_FormatYUV420Planar:
return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
case AHARDWAREBUFFER_FORMAT_BLOB:
#endif
default:
return VK_FORMAT_UNDEFINED;
}
}
static inline unsigned
android_format_from_vk(VkFormat vk_format)
{
switch (vk_format) {
case VK_FORMAT_R8G8B8A8_UNORM:
return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
case VK_FORMAT_R8G8B8_UNORM:
return AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
case VK_FORMAT_R16G16B16A16_SFLOAT:
return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
return HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL;
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
return HAL_PIXEL_FORMAT_YV12;
default:
return AHARDWAREBUFFER_FORMAT_BLOB;
}
}
static inline bool
android_format_is_yuv(unsigned android_format)
{
switch (android_format) {
case AHARDWAREBUFFER_FORMAT_BLOB:
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
case AHARDWAREBUFFER_FORMAT_S8_UINT:
return false;
case HAL_PIXEL_FORMAT_NV12_Y_TILED_INTEL:
case OMX_COLOR_FormatYUV420Planar:
case HAL_PIXEL_FORMAT_YV12:
#if __ANDROID_API__ >= 30
case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
#endif
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
return true;
default:
ALOGE("%s: unhandled format: %d", __FUNCTION__, android_format);
return false;
}
}
static inline VkImageAspectFlags
vk_format_aspects(VkFormat format)
{
switch (format) {
case VK_FORMAT_UNDEFINED:
return 0;
case VK_FORMAT_S8_UINT:
return VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT:
return VK_IMAGE_ASPECT_DEPTH_BIT;
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
return (VK_IMAGE_ASPECT_PLANE_0_BIT |
VK_IMAGE_ASPECT_PLANE_1_BIT |
VK_IMAGE_ASPECT_PLANE_2_BIT);
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
return (VK_IMAGE_ASPECT_PLANE_0_BIT |
VK_IMAGE_ASPECT_PLANE_1_BIT);
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
}
static inline bool
vk_format_is_color(VkFormat format)
{
return vk_format_aspects(format) == VK_IMAGE_ASPECT_COLOR_BIT;
}
static inline bool
vk_format_is_depth_or_stencil(VkFormat format)
{
const VkImageAspectFlags aspects = vk_format_aspects(format);
return aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
}
static inline bool
vk_format_has_depth(VkFormat format)
{
const VkImageAspectFlags aspects = vk_format_aspects(format);
return aspects & VK_IMAGE_ASPECT_DEPTH_BIT;
}
} // namespace vk
} // namespace gfxstream
#endif /* VK_FORMAT_INFO_H */
@@ -0,0 +1,30 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#if VK_HEADER_VERSION < 76
typedef struct VkBaseOutStructure {
VkStructureType sType;
struct VkBaseOutStructure* pNext;
} VkBaseOutStructure;
typedef struct VkBaseInStructure {
VkStructureType sType;
const struct VkBaseInStructure* pNext;
} VkBaseInStructure;
#endif // VK_HEADER_VERSION < 76
@@ -0,0 +1,82 @@
// 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.
#pragma once
#include <vulkan/vulkan.h>
#include "goldfish_vk_private_defs.h"
#include "vulkan_gfxstream.h"
namespace gfxstream {
namespace vk {
template <class T> struct vk_get_vk_struct_id;
#define REGISTER_VK_STRUCT_ID(T, ID) \
template <> struct vk_get_vk_struct_id<T> { static constexpr VkStructureType id = ID; }
#ifdef VK_USE_PLATFORM_ANDROID_KHR
REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferPropertiesANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID);
REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferFormatPropertiesANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID);
REGISTER_VK_STRUCT_ID(VkAndroidHardwareBufferUsageANDROID, VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID);
#endif
REGISTER_VK_STRUCT_ID(VkBufferCreateInfo, VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkImageCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkImageFormatProperties2, VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2);
#ifdef VK_USE_PLATFORM_ANDROID_KHR
REGISTER_VK_STRUCT_ID(VkNativeBufferANDROID, VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID);
REGISTER_VK_STRUCT_ID(VkExternalFormatANDROID, VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID);
#endif
REGISTER_VK_STRUCT_ID(VkExternalMemoryBufferCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkExternalMemoryImageCreateInfo, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkMemoryAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO);
REGISTER_VK_STRUCT_ID(VkMemoryDedicatedAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO);
REGISTER_VK_STRUCT_ID(VkMemoryDedicatedRequirements, VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS);
#ifdef VK_USE_PLATFORM_ANDROID_KHR
REGISTER_VK_STRUCT_ID(VkImportAndroidHardwareBufferInfoANDROID, VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID);
#endif
REGISTER_VK_STRUCT_ID(VkExportMemoryAllocateInfo, VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO);
REGISTER_VK_STRUCT_ID(VkMemoryRequirements2, VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2);
REGISTER_VK_STRUCT_ID(VkSemaphoreCreateInfo, VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkExportSemaphoreCreateInfoKHR, VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR);
REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkImportColorBufferGOOGLE, VK_STRUCTURE_TYPE_IMPORT_COLOR_BUFFER_GOOGLE);
REGISTER_VK_STRUCT_ID(VkImageViewCreateInfo, VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO);
#ifdef VK_USE_PLATFORM_FUCHSIA
REGISTER_VK_STRUCT_ID(VkImportMemoryBufferCollectionFUCHSIA, VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA);
REGISTER_VK_STRUCT_ID(VkImportMemoryZirconHandleInfoFUCHSIA, VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA);
REGISTER_VK_STRUCT_ID(VkBufferCollectionImageCreateInfoFUCHSIA, VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA);
REGISTER_VK_STRUCT_ID(VkBufferCollectionBufferCreateInfoFUCHSIA, VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA);
#endif // VK_USE_PLATFORM_FUCHSIA
REGISTER_VK_STRUCT_ID(VkSamplerCreateInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkSamplerCustomBorderColorCreateInfoEXT, VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
REGISTER_VK_STRUCT_ID(VkSamplerYcbcrConversionInfo, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO);
REGISTER_VK_STRUCT_ID(VkFenceCreateInfo, VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkExportFenceCreateInfo, VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkImportBufferGOOGLE, VK_STRUCTURE_TYPE_IMPORT_BUFFER_GOOGLE);
REGISTER_VK_STRUCT_ID(VkCreateBlobGOOGLE, VK_STRUCTURE_TYPE_CREATE_BLOB_GOOGLE);
REGISTER_VK_STRUCT_ID(VkExternalImageFormatProperties, VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceImageFormatInfo2, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceExternalImageFormatInfo, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO);
REGISTER_VK_STRUCT_ID(VkSemaphoreTypeCreateInfo, VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceFeatures2, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceProperties2, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2);
REGISTER_VK_STRUCT_ID(VkPhysicalDeviceDeviceMemoryReportFeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT);
REGISTER_VK_STRUCT_ID(VkMemoryAllocateFlagsInfo, VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO);
REGISTER_VK_STRUCT_ID(VkMemoryOpaqueCaptureAddressAllocateInfo, VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO);
#undef REGISTER_VK_STRUCT_ID
} // namespace vk
} // namespace gfxstream
+257
View File
@@ -0,0 +1,257 @@
/*
* Copyright © 2017 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef VK_UTIL_H
#define VK_UTIL_H
/* common inlines and macros for vulkan drivers */
#include <vulkan/vulkan.h>
#include <stdlib.h>
#include "vk_struct_id.h"
namespace gfxstream {
namespace vk {
struct vk_struct_common {
VkStructureType sType;
struct vk_struct_common *pNext;
};
struct vk_struct_chain_iterator {
vk_struct_common* value;
};
#define vk_foreach_struct(__iter, __start) \
for (struct vk_struct_common *__iter = (struct vk_struct_common *)(__start); \
__iter; __iter = __iter->pNext)
#define vk_foreach_struct_const(__iter, __start) \
for (const struct vk_struct_common *__iter = (const struct vk_struct_common *)(__start); \
__iter; __iter = __iter->pNext)
/**
* A wrapper for a Vulkan output array. A Vulkan output array is one that
* follows the convention of the parameters to
* vkGetPhysicalDeviceQueueFamilyProperties().
*
* Example Usage:
*
* VkResult
* vkGetPhysicalDeviceQueueFamilyProperties(
* VkPhysicalDevice physicalDevice,
* uint32_t* pQueueFamilyPropertyCount,
* VkQueueFamilyProperties* pQueueFamilyProperties)
* {
* VK_OUTARRAY_MAKE(props, pQueueFamilyProperties,
* pQueueFamilyPropertyCount);
*
* vk_outarray_append(&props, p) {
* p->queueFlags = ...;
* p->queueCount = ...;
* }
*
* vk_outarray_append(&props, p) {
* p->queueFlags = ...;
* p->queueCount = ...;
* }
*
* return vk_outarray_status(&props);
* }
*/
struct __vk_outarray {
/** May be null. */
void *data;
/**
* Capacity, in number of elements. Capacity is unlimited (UINT32_MAX) if
* data is null.
*/
uint32_t cap;
/**
* Count of elements successfully written to the array. Every write is
* considered successful if data is null.
*/
uint32_t *filled_len;
/**
* Count of elements that would have been written to the array if its
* capacity were sufficient. Vulkan functions often return VK_INCOMPLETE
* when `*filled_len < wanted_len`.
*/
uint32_t wanted_len;
};
static inline void
__vk_outarray_init(struct __vk_outarray *a,
void *data, uint32_t * len)
{
a->data = data;
a->cap = *len;
a->filled_len = len;
*a->filled_len = 0;
a->wanted_len = 0;
if (a->data == NULL)
a->cap = UINT32_MAX;
}
static inline VkResult
__vk_outarray_status(const struct __vk_outarray *a)
{
if (*a->filled_len < a->wanted_len)
return VK_INCOMPLETE;
else
return VK_SUCCESS;
}
static inline void *
__vk_outarray_next(struct __vk_outarray *a, size_t elem_size)
{
void *p = NULL;
a->wanted_len += 1;
if (*a->filled_len >= a->cap)
return NULL;
if (a->data != NULL)
p = ((uint8_t*)a->data) + (*a->filled_len) * elem_size;
*a->filled_len += 1;
return p;
}
#define vk_outarray(elem_t) \
struct { \
struct __vk_outarray base; \
elem_t meta[]; \
}
#define vk_outarray_typeof_elem(a) __typeof__((a)->meta[0])
#define vk_outarray_sizeof_elem(a) sizeof((a)->meta[0])
#define vk_outarray_init(a, data, len) \
__vk_outarray_init(&(a)->base, (data), (len))
#define VK_OUTARRAY_MAKE(name, data, len) \
vk_outarray(__typeof__((data)[0])) name; \
vk_outarray_init(&name, (data), (len))
#define vk_outarray_status(a) \
__vk_outarray_status(&(a)->base)
#define vk_outarray_next(a) \
((vk_outarray_typeof_elem(a) *) \
__vk_outarray_next(&(a)->base, vk_outarray_sizeof_elem(a)))
/**
* Append to a Vulkan output array.
*
* This is a block-based macro. For example:
*
* vk_outarray_append(&a, elem) {
* elem->foo = ...;
* elem->bar = ...;
* }
*
* The array `a` has type `vk_outarray(elem_t) *`. It is usually declared with
* VK_OUTARRAY_MAKE(). The variable `elem` is block-scoped and has type
* `elem_t *`.
*
* The macro unconditionally increments the array's `wanted_len`. If the array
* is not full, then the macro also increment its `filled_len` and then
* executes the block. When the block is executed, `elem` is non-null and
* points to the newly appended element.
*/
#define vk_outarray_append(a, elem) \
for (vk_outarray_typeof_elem(a) *elem = vk_outarray_next(a); \
elem != NULL; elem = NULL)
static inline void *
__vk_find_struct(void *start, VkStructureType sType)
{
vk_foreach_struct(s, start) {
if (s->sType == sType)
return s;
}
return NULL;
}
template <class T, class H> T* vk_find_struct(H* head)
{
(void)vk_get_vk_struct_id<H>::id;
return static_cast<T*>(__vk_find_struct(static_cast<void*>(head), vk_get_vk_struct_id<T>::id));
}
template <class T, class H> const T* vk_find_struct(const H* head)
{
(void)vk_get_vk_struct_id<H>::id;
return static_cast<const T*>(__vk_find_struct(const_cast<void*>(static_cast<const void*>(head)),
vk_get_vk_struct_id<T>::id));
}
uint32_t vk_get_driver_version(void);
uint32_t vk_get_version_override(void);
#define VK_EXT_OFFSET (1000000000UL)
#define VK_ENUM_EXTENSION(__enum) \
((__enum) >= VK_EXT_OFFSET ? ((((__enum) - VK_EXT_OFFSET) / 1000UL) + 1) : 0)
#define VK_ENUM_OFFSET(__enum) \
((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum))
template <class T> T vk_make_orphan_copy(const T& vk_struct) {
T copy = vk_struct;
copy.pNext = NULL;
return copy;
}
template <class T> vk_struct_chain_iterator vk_make_chain_iterator(T* vk_struct)
{
(void)vk_get_vk_struct_id<T>::id;
vk_struct_chain_iterator result = { reinterpret_cast<vk_struct_common*>(vk_struct) };
return result;
}
template <class T> void vk_append_struct(vk_struct_chain_iterator* i, T* vk_struct)
{
(void)vk_get_vk_struct_id<T>::id;
vk_struct_common* p = i->value;
if (p->pNext) {
::abort();
}
p->pNext = reinterpret_cast<vk_struct_common *>(vk_struct);
vk_struct->pNext = NULL;
*i = vk_make_chain_iterator(vk_struct);
}
} // namespace vk
} // namespace gfxstream
#endif /* VK_UTIL_H */