// 初始 Skia 封装的后端渲染 vulkan 上下文
if (!grVkBackendContext) {
grVkBackendContext = new GrVkBackendContext();
}
// 创建 vulkan 应用信息
VkApplicationInfo appCreateInfo = {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = nullptr,
.pApplicationName = "silk_vulkan",
.applicationVersion = VK_MAKE_VERSION(1, 0, 0),
.pEngineName = "silk_vulkan_en",
.engineVersion = VK_MAKE_VERSION(1, 0, 0),
.apiVersion = VK_MAKE_VERSION(1, 0, 0),
};
// 创建 Vulkan 实例
uint32_t instanceExtCount = 2;
uint32_t deviceExtCount = 1;
const char *instanceExt[instanceExtCount];
const char *deviceExt[deviceExtCount];
// 扩展实例支持 android surface,以下都为必选参数
instanceExt[0] = "VK_KHR_surface";
instanceExt[1] = "VK_KHR_android_surface";
// 逻辑设备要支持交换链
deviceExt[0] = "VK_KHR_swapchain";
// 调用 Vulkan 函数创建
VkInstanceCreateInfo instanceCreateInfo{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = nullptr,
.pApplicationInfo = &appCreateInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = instanceExtCount,
.ppEnabledExtensionNames = instanceExt,
};
VkResult result = vkCreateInstance(
&instanceCreateInfo, nullptr, &grVkBackendContext->fInstance);
if (result != VK_SUCCESS) {
return false;
}
// 获取支持的物理设备列表,同一函数调两次,vulkan 用法套路,先取数量再取实际值
uint32_t gpuCount = 0;
result = vkEnumeratePhysicalDevices(
grVkBackendContext->fInstance, &gpuCount, nullptr);
if (result != VK_SUCCESS) {
return false;
}
VkPhysicalDevice vkGpus[gpuCount];
result = vkEnumeratePhysicalDevices(
grVkBackendContext->fInstance, &gpuCount, vkGpus);
if (result != VK_SUCCESS) {
return false;
}
// 取本机第一个 GPU 物理设备
grVkBackendContext->fPhysicalDevice = vkGpus[0];
VkPhysicalDeviceProperties gpuProperties;
vkGetPhysicalDeviceProperties(
grVkBackendContext->fPhysicalDevice, &gpuProperties);
// 获取物理设备支持的队列族类型,比如用于图形的,用于计算的
uint32_t queueFamilyCount;
vkGetPhysicalDeviceQueueFamilyProperties(
grVkBackendContext->fPhysicalDevice, &queueFamilyCount, nullptr);
if (queueFamilyCount <= 0) {
return false;
}
VkQueueFamilyProperties queueFamilyProperties[queueFamilyCount];
vkGetPhysicalDeviceQueueFamilyProperties(
grVkBackendContext->fPhysicalDevice,
&queueFamilyCount,
queueFamilyProperties);
// 我们只关心图形队列族,只需找到图形队列族用于绘制
uint32_t queueFamilyIndex;
for (queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount;
queueFamilyIndex++) {
if (queueFamilyProperties[queueFamilyIndex].queueFlags &
VK_QUEUE_GRAPHICS_BIT) {
break;
}
}
if (queueFamilyIndex >= queueFamilyCount) {
return false;
}
grVkBackendContext->fGraphicsQueueIndex = queueFamilyIndex;
// 队列优先级 0-1 ,高优先级
float priorities[] = {
1.0f,
};
VkDeviceQueueCreateInfo queueCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.queueFamilyIndex = queueFamilyIndex,
.queueCount = 1,
.pQueuePriorities = priorities,
};
VkDeviceCreateInfo deviceCreateInfo{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = nullptr,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queueCreateInfo,
.enabledLayerCount = 0,
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = deviceExtCount,
.ppEnabledExtensionNames = deviceExt,
.pEnabledFeatures = nullptr,
};
// 创建与物理设备对应的逻辑设备
result = vkCreateDevice(
grVkBackendContext->fPhysicalDevice,
&deviceCreateInfo,
nullptr,
&grVkBackendContext->fDevice);
if (result != VK_SUCCESS) {
return false;
}
// 初始逻辑设备的队列
vkGetDeviceQueue(
grVkBackendContext->fDevice,
queueFamilyIndex,
0,
&grVkBackendContext->fQueue);
// 加载 Vulkan 函数指针(skia 必备,会通过这个来回调各种 vulkan api)
// function<void (*(const char *, VkInstance_T *, VkDevice_T *))()>
// void (*)()
GrVkGetProc getProc =
[](const char *name, VkInstance_T *instance, VkDevice_T *device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, name);
}
return vkGetInstanceProcAddr(instance, name);
};
grVkBackendContext->fGetProc = getProc;
GrVkExtensions *grVkExtensions = new GrVkExtensions();
grVkExtensions->init(
grVkBackendContext->fGetProc,
grVkBackendContext->fInstance,
grVkBackendContext->fPhysicalDevice,
instanceExtCount,
instanceExt,
deviceExtCount,
deviceExt);
grVkBackendContext->fVkExtensions = grVkExtensions;
// 启用任务拆分,尽可能的利用多线程优化渲染性能
GrContextOptions options;
persistentCacheVulkan = new PersistentCacheVulkan();
options.fReduceOpsTaskSplitting = GrContextOptions::Enable::kYes;
options.fDisableCoverageCountingPaths = true;
options.fDisableDistanceFieldPaths = true;
options.fMaxCachedVulkanSecondaryCommandBuffers = 100;
options.fReducedShaderVariations = true;
options.fPersistentCache = persistentCacheVulkan;
// 生成 Skia 所需的 gpu 上下文
grDirectContext = GrDirectContext::MakeVulkan(*grVkBackendContext, options);
if (!grDirectContext) {
return false;
}
// 创建 vulkan surface 和 android 关联
VkAndroidSurfaceCreateInfoKHR androidSurfaceCreateInfo{
.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR,
.pNext = nullptr,
.flags = 0,
.window = nativeWindow};
result = vkCreateAndroidSurfaceKHR(
grVkBackendContext->fInstance,
&androidSurfaceCreateInfo,
nullptr,
&vkSurfaceKHR);
if (result != VK_SUCCESS) {
return false;
}
// 获取 vulkan 所能支持的 surface 能力及属性
VkSurfaceCapabilitiesKHR surfaceCapabilities;
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
grVkBackendContext->fPhysicalDevice, vkSurfaceKHR, &surfaceCapabilities);
if (result != VK_SUCCESS) {
return false;
}
// 获取 vulkan 所能支持的 format 列表
uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(
grVkBackendContext->fPhysicalDevice, vkSurfaceKHR, &formatCount, nullptr);
VkSurfaceFormatKHR formats[formatCount];
vkGetPhysicalDeviceSurfaceFormatsKHR(
grVkBackendContext->fPhysicalDevice, vkSurfaceKHR, &formatCount, formats);
// 找到支持 RGBA 的格式
uint32_t chosenFormat;
for (chosenFormat = 0; chosenFormat < formatCount; chosenFormat++) {
if (formats[chosenFormat].format == VK_FORMAT_R8G8B8A8_UNORM)
break;
}
if (chosenFormat >= formatCount) {
return false;
}
// 需要支持透明从窗口系统继承,而不是自己设置,交换链需要用到该属性
if (surfaceCapabilities.supportedCompositeAlpha !=
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
return false;
}
// 创建交换链(类似Android中为了解决jank问题,引入的三缓冲机制)
VkSwapchainCreateInfoKHR swapchainCreateInfo{
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = nullptr,
.surface = vkSurfaceKHR,
.minImageCount = surfaceCapabilities.minImageCount,
.imageFormat = formats[chosenFormat].format,
.imageColorSpace = formats[chosenFormat].colorSpace,
.imageExtent = surfaceCapabilities.currentExtent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 1,
.pQueueFamilyIndices = &queueFamilyIndex,
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
.presentMode = VK_PRESENT_MODE_MAILBOX_KHR,
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE,
};
result = vkCreateSwapchainKHR(
grVkBackendContext->fDevice,
&swapchainCreateInfo,
nullptr,
&vkSwapchainKHR);
if (result != VK_SUCCESS) {
return false;
}
// 获取交换链所有的图像列表
uint32_t swapchainLength;
result = vkGetSwapchainImagesKHR(
grVkBackendContext->fDevice, vkSwapchainKHR, &swapchainLength, nullptr);
if (result != VK_SUCCESS) {
return false;
}
VkImage displayImages[swapchainLength];
result = vkGetSwapchainImagesKHR(
grVkBackendContext->fDevice,
vkSwapchainKHR,
&swapchainLength,
displayImages);
if (result != VK_SUCCESS) {
return false;
}
// 组装 Skia 的 image 数据(参考了flutter配置)
GrVkImageInfo grVkImageInfo;
grVkImageInfo.fImage = displayImages[0];
grVkImageInfo.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
grVkImageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
grVkImageInfo.fFormat = VK_FORMAT_R8G8B8A8_UNORM;
grVkImageInfo.fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
grVkImageInfo.fSampleCount = 1;
grVkImageInfo.fLevelCount = 1;
// 组装 Skia 的后端渲染 target
GrBackendRenderTarget grBackendRenderTarget(mWidth, mHeight, grVkImageInfo);
SkSurfaceProps skSurfaceProps(0, kUnknown_SkPixelGeometry);
// 生成 Skia 所需的 sksurface
skSurface = SkSurface::MakeFromBackendRenderTarget(
grDirectContext.get(),
grBackendRenderTarget,
kTopLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType,
SkColorSpace::MakeSRGB(),
&skSurfaceProps);
if (!skSurface) {
return false;
}
// 获取交换链中下一次可展示的image索引
uint32_t nextIndex;
result = vkAcquireNextImageKHR(
grVkBackendContext->fDevice,
vkSwapchainKHR,
UINT64_MAX,
VK_NULL_HANDLE,
VK_NULL_HANDLE,
&nextIndex);
if (result != VK_SUCCESS) {
return false;
}
VkPipelineStageFlags waitStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.pNext = nullptr,
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.pWaitDstStageMask = &waitStageMask,
.commandBufferCount = 0,
.pCommandBuffers = nullptr,
.signalSemaphoreCount = 0,
.pSignalSemaphores = nullptr};
result = vkQueueSubmit(grVkBackendContext->fQueue, 0, &submit_info, nullptr);
if (result != VK_SUCCESS) {
return false;
}
// 将 image 提交并显示
VkPresentInfoKHR presentInfo{
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pNext = nullptr,
.waitSemaphoreCount = 0,
.pWaitSemaphores = nullptr,
.swapchainCount = 1,
.pSwapchains = &vkSwapchainKHR,
.pImageIndices = &nextIndex,
.pResults = &result,
};
vkQueuePresentKHR(grVkBackendContext->fQueue, &presentInfo);
评论