mirror of https://gitlab.freedesktop.org/mesa/mesa
790 lines
27 KiB
C
790 lines
27 KiB
C
/*
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* based in part on anv and radv which are:
|
|
* Copyright © 2015 Intel Corporation
|
|
* Copyright © 2016 Red Hat.
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
*/
|
|
|
|
#include "vn_pipeline.h"
|
|
|
|
#include "venus-protocol/vn_protocol_driver_pipeline.h"
|
|
#include "venus-protocol/vn_protocol_driver_pipeline_cache.h"
|
|
#include "venus-protocol/vn_protocol_driver_pipeline_layout.h"
|
|
#include "venus-protocol/vn_protocol_driver_shader_module.h"
|
|
|
|
#include "vn_device.h"
|
|
#include "vn_physical_device.h"
|
|
#include "vn_render_pass.h"
|
|
|
|
/* shader module commands */
|
|
|
|
VkResult
|
|
vn_CreateShaderModule(VkDevice device,
|
|
const VkShaderModuleCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkShaderModule *pShaderModule)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
struct vn_shader_module *mod =
|
|
vk_zalloc(alloc, sizeof(*mod), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!mod)
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
vn_object_base_init(&mod->base, VK_OBJECT_TYPE_SHADER_MODULE, &dev->base);
|
|
|
|
VkShaderModule mod_handle = vn_shader_module_to_handle(mod);
|
|
vn_async_vkCreateShaderModule(dev->instance, device, pCreateInfo, NULL,
|
|
&mod_handle);
|
|
|
|
*pShaderModule = mod_handle;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_DestroyShaderModule(VkDevice device,
|
|
VkShaderModule shaderModule,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_shader_module *mod = vn_shader_module_from_handle(shaderModule);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
if (!mod)
|
|
return;
|
|
|
|
vn_async_vkDestroyShaderModule(dev->instance, device, shaderModule, NULL);
|
|
|
|
vn_object_base_fini(&mod->base);
|
|
vk_free(alloc, mod);
|
|
}
|
|
|
|
/* pipeline layout commands */
|
|
|
|
VkResult
|
|
vn_CreatePipelineLayout(VkDevice device,
|
|
const VkPipelineLayoutCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkPipelineLayout *pPipelineLayout)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
struct vn_pipeline_layout *layout =
|
|
vk_zalloc(alloc, sizeof(*layout), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!layout)
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
vn_object_base_init(&layout->base, VK_OBJECT_TYPE_PIPELINE_LAYOUT,
|
|
&dev->base);
|
|
|
|
VkPipelineLayout layout_handle = vn_pipeline_layout_to_handle(layout);
|
|
vn_async_vkCreatePipelineLayout(dev->instance, device, pCreateInfo, NULL,
|
|
&layout_handle);
|
|
|
|
*pPipelineLayout = layout_handle;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_DestroyPipelineLayout(VkDevice device,
|
|
VkPipelineLayout pipelineLayout,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_pipeline_layout *layout =
|
|
vn_pipeline_layout_from_handle(pipelineLayout);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
if (!layout)
|
|
return;
|
|
|
|
vn_async_vkDestroyPipelineLayout(dev->instance, device, pipelineLayout,
|
|
NULL);
|
|
|
|
vn_object_base_fini(&layout->base);
|
|
vk_free(alloc, layout);
|
|
}
|
|
|
|
/* pipeline cache commands */
|
|
|
|
VkResult
|
|
vn_CreatePipelineCache(VkDevice device,
|
|
const VkPipelineCacheCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkPipelineCache *pPipelineCache)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
struct vn_pipeline_cache *cache =
|
|
vk_zalloc(alloc, sizeof(*cache), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (!cache)
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
vn_object_base_init(&cache->base, VK_OBJECT_TYPE_PIPELINE_CACHE,
|
|
&dev->base);
|
|
|
|
VkPipelineCacheCreateInfo local_create_info;
|
|
if (pCreateInfo->initialDataSize) {
|
|
const struct vk_pipeline_cache_header *header =
|
|
pCreateInfo->pInitialData;
|
|
|
|
local_create_info = *pCreateInfo;
|
|
local_create_info.initialDataSize -= header->header_size;
|
|
local_create_info.pInitialData += header->header_size;
|
|
pCreateInfo = &local_create_info;
|
|
}
|
|
|
|
VkPipelineCache cache_handle = vn_pipeline_cache_to_handle(cache);
|
|
vn_async_vkCreatePipelineCache(dev->instance, device, pCreateInfo, NULL,
|
|
&cache_handle);
|
|
|
|
*pPipelineCache = cache_handle;
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
vn_DestroyPipelineCache(VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_pipeline_cache *cache =
|
|
vn_pipeline_cache_from_handle(pipelineCache);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
if (!cache)
|
|
return;
|
|
|
|
vn_async_vkDestroyPipelineCache(dev->instance, device, pipelineCache,
|
|
NULL);
|
|
|
|
vn_object_base_fini(&cache->base);
|
|
vk_free(alloc, cache);
|
|
}
|
|
|
|
VkResult
|
|
vn_GetPipelineCacheData(VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
size_t *pDataSize,
|
|
void *pData)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_physical_device *physical_dev = dev->physical_device;
|
|
|
|
struct vk_pipeline_cache_header *header = pData;
|
|
VkResult result;
|
|
if (!pData) {
|
|
result = vn_call_vkGetPipelineCacheData(dev->instance, device,
|
|
pipelineCache, pDataSize, NULL);
|
|
if (result != VK_SUCCESS)
|
|
return vn_error(dev->instance, result);
|
|
|
|
*pDataSize += sizeof(*header);
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
if (*pDataSize <= sizeof(*header)) {
|
|
*pDataSize = 0;
|
|
return VK_INCOMPLETE;
|
|
}
|
|
|
|
const VkPhysicalDeviceProperties *props =
|
|
&physical_dev->properties.vulkan_1_0;
|
|
header->header_size = sizeof(*header);
|
|
header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
|
|
header->vendor_id = props->vendorID;
|
|
header->device_id = props->deviceID;
|
|
memcpy(header->uuid, props->pipelineCacheUUID, VK_UUID_SIZE);
|
|
|
|
*pDataSize -= header->header_size;
|
|
result =
|
|
vn_call_vkGetPipelineCacheData(dev->instance, device, pipelineCache,
|
|
pDataSize, pData + header->header_size);
|
|
if (result < VK_SUCCESS)
|
|
return vn_error(dev->instance, result);
|
|
|
|
*pDataSize += header->header_size;
|
|
|
|
return result;
|
|
}
|
|
|
|
VkResult
|
|
vn_MergePipelineCaches(VkDevice device,
|
|
VkPipelineCache dstCache,
|
|
uint32_t srcCacheCount,
|
|
const VkPipelineCache *pSrcCaches)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
|
|
vn_async_vkMergePipelineCaches(dev->instance, device, dstCache,
|
|
srcCacheCount, pSrcCaches);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
/* pipeline commands */
|
|
|
|
static bool
|
|
vn_create_pipeline_handles(struct vn_device *dev,
|
|
uint32_t pipeline_count,
|
|
VkPipeline *pipeline_handles,
|
|
const VkAllocationCallbacks *alloc)
|
|
{
|
|
for (uint32_t i = 0; i < pipeline_count; i++) {
|
|
struct vn_pipeline *pipeline =
|
|
vk_zalloc(alloc, sizeof(*pipeline), VN_DEFAULT_ALIGN,
|
|
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
|
|
if (!pipeline) {
|
|
for (uint32_t j = 0; j < i; j++) {
|
|
pipeline = vn_pipeline_from_handle(pipeline_handles[j]);
|
|
vn_object_base_fini(&pipeline->base);
|
|
vk_free(alloc, pipeline);
|
|
}
|
|
|
|
memset(pipeline_handles, 0,
|
|
pipeline_count * sizeof(pipeline_handles[0]));
|
|
return false;
|
|
}
|
|
|
|
vn_object_base_init(&pipeline->base, VK_OBJECT_TYPE_PIPELINE,
|
|
&dev->base);
|
|
pipeline_handles[i] = vn_pipeline_to_handle(pipeline);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/** For vkCreate*Pipelines. */
|
|
static void
|
|
vn_destroy_failed_pipelines(struct vn_device *dev,
|
|
uint32_t create_info_count,
|
|
VkPipeline *pipelines,
|
|
const VkAllocationCallbacks *alloc)
|
|
{
|
|
for (uint32_t i = 0; i < create_info_count; i++) {
|
|
struct vn_pipeline *pipeline = vn_pipeline_from_handle(pipelines[i]);
|
|
|
|
if (pipeline->base.id == 0) {
|
|
vn_object_base_fini(&pipeline->base);
|
|
vk_free(alloc, pipeline);
|
|
pipelines[i] = VK_NULL_HANDLE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define VN_PIPELINE_CREATE_SYNC_MASK \
|
|
(VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT | \
|
|
VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT)
|
|
|
|
/** Fixes for a single VkGraphicsPipelineCreateInfo. */
|
|
struct vn_graphics_pipeline_create_info_fix {
|
|
bool ignore_tessellation_state;
|
|
bool ignore_viewport_state;
|
|
bool ignore_viewports;
|
|
bool ignore_scissors;
|
|
bool ignore_multisample_state;
|
|
bool ignore_depth_stencil_state;
|
|
bool ignore_color_blend_state;
|
|
bool ignore_base_pipeline_handle;
|
|
};
|
|
|
|
/** Temporary storage for fixes in vkCreateGraphicsPipelines. */
|
|
struct vn_create_graphics_pipelines_fixes {
|
|
VkGraphicsPipelineCreateInfo *create_infos;
|
|
VkPipelineViewportStateCreateInfo *viewport_state_create_infos;
|
|
};
|
|
|
|
static struct vn_create_graphics_pipelines_fixes *
|
|
vn_alloc_create_graphics_pipelines_fixes(const VkAllocationCallbacks *alloc,
|
|
uint32_t info_count)
|
|
{
|
|
struct vn_create_graphics_pipelines_fixes *fixes;
|
|
VkGraphicsPipelineCreateInfo *create_infos;
|
|
VkPipelineViewportStateCreateInfo *viewport_state_create_infos;
|
|
|
|
VK_MULTIALLOC(ma);
|
|
vk_multialloc_add(&ma, &fixes, __typeof__(*fixes), 1);
|
|
vk_multialloc_add(&ma, &create_infos, __typeof__(*create_infos),
|
|
info_count);
|
|
vk_multialloc_add(&ma, &viewport_state_create_infos,
|
|
__typeof__(*viewport_state_create_infos), info_count);
|
|
|
|
if (!vk_multialloc_zalloc(&ma, alloc, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND))
|
|
return NULL;
|
|
|
|
fixes->create_infos = create_infos;
|
|
fixes->viewport_state_create_infos = viewport_state_create_infos;
|
|
|
|
return fixes;
|
|
}
|
|
|
|
static const VkGraphicsPipelineCreateInfo *
|
|
vn_fix_graphics_pipeline_create_info(
|
|
struct vn_device *dev,
|
|
uint32_t info_count,
|
|
const VkGraphicsPipelineCreateInfo *create_infos,
|
|
const VkAllocationCallbacks *alloc,
|
|
struct vn_create_graphics_pipelines_fixes **out_fixes)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
|
|
/* Defer allocation until we need a fix. */
|
|
struct vn_create_graphics_pipelines_fixes *fixes = NULL;
|
|
|
|
for (uint32_t i = 0; i < info_count; i++) {
|
|
struct vn_graphics_pipeline_create_info_fix fix = { 0 };
|
|
bool any_fix = false;
|
|
|
|
const VkGraphicsPipelineCreateInfo *info = &create_infos[i];
|
|
const VkPipelineRenderingCreateInfo *rendering_info =
|
|
vk_find_struct_const(info, PIPELINE_RENDERING_CREATE_INFO);
|
|
|
|
VkShaderStageFlags stages = 0;
|
|
for (uint32_t j = 0; j < info->stageCount; j++) {
|
|
stages |= info->pStages[j].stage;
|
|
}
|
|
|
|
/* VkDynamicState */
|
|
struct {
|
|
bool rasterizer_discard_enable;
|
|
bool viewport;
|
|
bool viewport_with_count;
|
|
bool scissor;
|
|
bool scissor_with_count;
|
|
} has_dynamic_state = { 0 };
|
|
|
|
if (info->pDynamicState) {
|
|
for (uint32_t j = 0; j < info->pDynamicState->dynamicStateCount;
|
|
j++) {
|
|
switch (info->pDynamicState->pDynamicStates[j]) {
|
|
case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE:
|
|
has_dynamic_state.rasterizer_discard_enable = true;
|
|
break;
|
|
case VK_DYNAMIC_STATE_VIEWPORT:
|
|
has_dynamic_state.viewport = true;
|
|
break;
|
|
case VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT:
|
|
has_dynamic_state.viewport_with_count = true;
|
|
break;
|
|
case VK_DYNAMIC_STATE_SCISSOR:
|
|
has_dynamic_state.scissor = true;
|
|
break;
|
|
case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT:
|
|
has_dynamic_state.scissor_with_count = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
const struct vn_render_pass *pass =
|
|
vn_render_pass_from_handle(info->renderPass);
|
|
|
|
const struct vn_subpass *subpass = NULL;
|
|
if (pass)
|
|
subpass = &pass->subpasses[info->subpass];
|
|
|
|
/* TODO: Ignore VkPipelineRenderingCreateInfo when not using dynamic
|
|
* rendering. This requires either a deep rewrite of
|
|
* VkGraphicsPipelineCreateInfo::pNext or a fix in the generated
|
|
* protocol code.
|
|
*
|
|
* The Vulkan spec (1.3.223) says about VkPipelineRenderingCreateInfo:
|
|
* If a graphics pipeline is created with a valid VkRenderPass,
|
|
* parameters of this structure are ignored.
|
|
*/
|
|
const bool has_dynamic_rendering = !pass && rendering_info;
|
|
|
|
/* For each pipeline state category, we define a bool.
|
|
*
|
|
* The Vulkan spec (1.3.223) says:
|
|
* The state required for a graphics pipeline is divided into vertex
|
|
* input state, pre-rasterization shader state, fragment shader
|
|
* state, and fragment output state.
|
|
*
|
|
* Without VK_EXT_graphics_pipeline_library, most states are
|
|
* unconditionally included in the pipeline. Despite that, we still
|
|
* reference the state bools in the ignore rules because (a) it makes
|
|
* the ignore condition easier to validate against the text of the
|
|
* relevant VUs; and (b) it makes it easier to enable
|
|
* VK_EXT_graphics_pipeline_library because we won't need to carefully
|
|
* revisit the text of each VU to untangle the missing pipeline state
|
|
* bools.
|
|
*/
|
|
|
|
/* VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT
|
|
*
|
|
* The Vulkan spec (1.3.223) says:
|
|
* If the pre-rasterization shader state includes a vertex shader,
|
|
* then vertex input state is included in a complete graphics pipeline.
|
|
*
|
|
* We support no extension yet that allows the vertex stage to be
|
|
* omitted, such as VK_EXT_vertex_input_dynamic_state or
|
|
* VK_EXT_graphics_pipeline_library.
|
|
*/
|
|
const bool UNUSED has_vertex_input_state = true;
|
|
|
|
/* VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT */
|
|
const bool has_pre_raster_state = true;
|
|
|
|
/* The spec does not assign a name to this state. We define it just to
|
|
* deduplicate code.
|
|
*
|
|
* The Vulkan spec (1.3.223) says:
|
|
* If the value of [...]rasterizerDiscardEnable in the
|
|
* pre-rasterization shader state is VK_FALSE or the
|
|
* VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE dynamic state is
|
|
* enabled fragment shader state and fragment output interface state
|
|
* is included in a complete graphics pipeline.
|
|
*/
|
|
const bool has_raster_state =
|
|
has_dynamic_state.rasterizer_discard_enable ||
|
|
(info->pRasterizationState &&
|
|
info->pRasterizationState->rasterizerDiscardEnable == VK_FALSE);
|
|
|
|
/* VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT */
|
|
const bool has_fragment_shader_state = has_raster_state;
|
|
|
|
/* VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT */
|
|
const bool has_fragment_output_state = has_raster_state;
|
|
|
|
/* Ignore pTessellationState?
|
|
* VUID-VkGraphicsPipelineCreateInfo-pStages-00731
|
|
*/
|
|
if (info->pTessellationState &&
|
|
(!(stages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) ||
|
|
!(stages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))) {
|
|
fix.ignore_tessellation_state = true;
|
|
any_fix = true;
|
|
}
|
|
|
|
/* Ignore pViewportState?
|
|
* VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00750
|
|
* VUID-VkGraphicsPipelineCreateInfo-pViewportState-04892
|
|
*/
|
|
if (info->pViewportState &&
|
|
!(has_pre_raster_state && has_raster_state)) {
|
|
fix.ignore_viewport_state = true;
|
|
any_fix = true;
|
|
}
|
|
|
|
/* Ignore pViewports?
|
|
* VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04130
|
|
*
|
|
* Even if pViewportState is non-null, we must not dereference it if it
|
|
* is ignored.
|
|
*/
|
|
if (!fix.ignore_viewport_state && info->pViewportState &&
|
|
info->pViewportState->pViewports) {
|
|
const bool has_dynamic_viewport =
|
|
has_pre_raster_state && (has_dynamic_state.viewport ||
|
|
has_dynamic_state.viewport_with_count);
|
|
|
|
if (has_dynamic_viewport) {
|
|
fix.ignore_viewports = true;
|
|
any_fix = true;
|
|
}
|
|
}
|
|
|
|
/* Ignore pScissors?
|
|
* VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04131
|
|
*
|
|
* Even if pViewportState is non-null, we must not dereference it if it
|
|
* is ignored.
|
|
*/
|
|
if (!fix.ignore_viewport_state && info->pViewportState &&
|
|
info->pViewportState->pScissors) {
|
|
const bool has_dynamic_scissor =
|
|
has_pre_raster_state && (has_dynamic_state.scissor ||
|
|
has_dynamic_state.scissor_with_count);
|
|
if (has_dynamic_scissor) {
|
|
fix.ignore_scissors = true;
|
|
any_fix = true;
|
|
}
|
|
}
|
|
|
|
/* Ignore pMultisampleState?
|
|
* VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00751
|
|
*/
|
|
if (info->pMultisampleState && !has_fragment_output_state) {
|
|
fix.ignore_multisample_state = true;
|
|
any_fix = true;
|
|
}
|
|
|
|
/* Ignore pDepthStencilState? */
|
|
if (info->pDepthStencilState) {
|
|
const bool has_static_attachment =
|
|
subpass && subpass->has_depth_stencil_attachment;
|
|
|
|
/* VUID-VkGraphicsPipelineCreateInfo-renderPass-06043 */
|
|
bool require_state =
|
|
has_fragment_shader_state && has_static_attachment;
|
|
|
|
if (!require_state) {
|
|
const bool has_dynamic_attachment =
|
|
has_dynamic_rendering &&
|
|
(rendering_info->depthAttachmentFormat !=
|
|
VK_FORMAT_UNDEFINED ||
|
|
rendering_info->stencilAttachmentFormat !=
|
|
VK_FORMAT_UNDEFINED);
|
|
|
|
/* VUID-VkGraphicsPipelineCreateInfo-renderPass-06053 */
|
|
require_state = has_fragment_shader_state &&
|
|
has_fragment_output_state &&
|
|
has_dynamic_attachment;
|
|
}
|
|
|
|
fix.ignore_depth_stencil_state = !require_state;
|
|
any_fix |= fix.ignore_depth_stencil_state;
|
|
}
|
|
|
|
/* Ignore pColorBlendState? */
|
|
if (info->pColorBlendState) {
|
|
const bool has_static_attachment =
|
|
subpass && subpass->has_color_attachment;
|
|
|
|
/* VUID-VkGraphicsPipelineCreateInfo-renderPass-06044 */
|
|
bool require_state =
|
|
has_fragment_output_state && has_static_attachment;
|
|
|
|
if (!require_state) {
|
|
const bool has_dynamic_attachment =
|
|
has_dynamic_rendering && rendering_info->colorAttachmentCount;
|
|
|
|
/* VUID-VkGraphicsPipelineCreateInfo-renderPass-06054 */
|
|
require_state =
|
|
has_fragment_output_state && has_dynamic_attachment;
|
|
}
|
|
|
|
fix.ignore_color_blend_state = !require_state;
|
|
any_fix |= fix.ignore_color_blend_state;
|
|
}
|
|
|
|
/* Ignore basePipelineHandle?
|
|
* VUID-VkGraphicsPipelineCreateInfo-flags-00722
|
|
*/
|
|
if (!(info->flags & VK_PIPELINE_CREATE_DERIVATIVE_BIT) ||
|
|
info->basePipelineIndex != -1) {
|
|
fix.ignore_base_pipeline_handle = true;
|
|
any_fix = true;
|
|
}
|
|
|
|
if (!any_fix)
|
|
continue;
|
|
|
|
if (!fixes) {
|
|
fixes = vn_alloc_create_graphics_pipelines_fixes(alloc, info_count);
|
|
|
|
if (!fixes)
|
|
return NULL;
|
|
|
|
memcpy(fixes->create_infos, create_infos,
|
|
info_count * sizeof(create_infos[0]));
|
|
}
|
|
|
|
if (fix.ignore_tessellation_state)
|
|
fixes->create_infos[i].pTessellationState = NULL;
|
|
|
|
if (fix.ignore_viewport_state)
|
|
fixes->create_infos[i].pViewportState = NULL;
|
|
|
|
if (fixes->create_infos[i].pViewportState) {
|
|
if (fix.ignore_viewports || fix.ignore_scissors) {
|
|
fixes->viewport_state_create_infos[i] = *info->pViewportState;
|
|
fixes->create_infos[i].pViewportState =
|
|
&fixes->viewport_state_create_infos[i];
|
|
}
|
|
|
|
if (fix.ignore_viewports)
|
|
fixes->viewport_state_create_infos[i].pViewports = NULL;
|
|
|
|
if (fix.ignore_scissors)
|
|
fixes->viewport_state_create_infos[i].pScissors = NULL;
|
|
}
|
|
|
|
if (fix.ignore_multisample_state)
|
|
fixes->create_infos[i].pMultisampleState = NULL;
|
|
|
|
if (fix.ignore_depth_stencil_state)
|
|
fixes->create_infos[i].pDepthStencilState = NULL;
|
|
|
|
if (fix.ignore_color_blend_state)
|
|
fixes->create_infos[i].pColorBlendState = NULL;
|
|
|
|
if (fix.ignore_base_pipeline_handle)
|
|
fixes->create_infos[i].basePipelineHandle = VK_NULL_HANDLE;
|
|
}
|
|
|
|
if (!fixes)
|
|
return create_infos;
|
|
|
|
*out_fixes = fixes;
|
|
return fixes->create_infos;
|
|
}
|
|
|
|
/**
|
|
* We invalidate each VkPipelineCreationFeedback. This is a legal but useless
|
|
* implementation.
|
|
*
|
|
* We invalidate because the venus protocol (as of 2022-08-25) does not know
|
|
* that the VkPipelineCreationFeedback structs in the
|
|
* VkGraphicsPipelineCreateInfo pNext are output parameters. Before
|
|
* VK_EXT_pipeline_creation_feedback, the pNext chain was input-only.
|
|
*/
|
|
static void
|
|
vn_invalidate_pipeline_creation_feedback(const VkBaseInStructure *chain)
|
|
{
|
|
const VkPipelineCreationFeedbackCreateInfo *feedback_info =
|
|
vk_find_struct_const(chain, PIPELINE_CREATION_FEEDBACK_CREATE_INFO);
|
|
|
|
if (!feedback_info)
|
|
return;
|
|
|
|
feedback_info->pPipelineCreationFeedback->flags &=
|
|
~VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT;
|
|
|
|
for (uint32_t i = 0; i < feedback_info->pipelineStageCreationFeedbackCount;
|
|
i++) {
|
|
feedback_info->pPipelineStageCreationFeedbacks[i].flags &=
|
|
~VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT;
|
|
}
|
|
}
|
|
|
|
VkResult
|
|
vn_CreateGraphicsPipelines(VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
uint32_t createInfoCount,
|
|
const VkGraphicsPipelineCreateInfo *pCreateInfos,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkPipeline *pPipelines)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
struct vn_create_graphics_pipelines_fixes *fixes = NULL;
|
|
bool want_sync = false;
|
|
VkResult result;
|
|
|
|
pCreateInfos = vn_fix_graphics_pipeline_create_info(
|
|
dev, createInfoCount, pCreateInfos, alloc, &fixes);
|
|
if (!pCreateInfos)
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
if (!vn_create_pipeline_handles(dev, createInfoCount, pPipelines, alloc)) {
|
|
vk_free(alloc, fixes);
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < createInfoCount; i++) {
|
|
if ((pCreateInfos[i].flags & VN_PIPELINE_CREATE_SYNC_MASK))
|
|
want_sync = true;
|
|
|
|
vn_invalidate_pipeline_creation_feedback(
|
|
(const VkBaseInStructure *)pCreateInfos[i].pNext);
|
|
}
|
|
|
|
if (want_sync) {
|
|
result = vn_call_vkCreateGraphicsPipelines(
|
|
dev->instance, device, pipelineCache, createInfoCount, pCreateInfos,
|
|
NULL, pPipelines);
|
|
if (result != VK_SUCCESS)
|
|
vn_destroy_failed_pipelines(dev, createInfoCount, pPipelines, alloc);
|
|
} else {
|
|
vn_async_vkCreateGraphicsPipelines(dev->instance, device, pipelineCache,
|
|
createInfoCount, pCreateInfos, NULL,
|
|
pPipelines);
|
|
result = VK_SUCCESS;
|
|
}
|
|
|
|
vk_free(alloc, fixes);
|
|
|
|
return vn_result(dev->instance, result);
|
|
}
|
|
|
|
VkResult
|
|
vn_CreateComputePipelines(VkDevice device,
|
|
VkPipelineCache pipelineCache,
|
|
uint32_t createInfoCount,
|
|
const VkComputePipelineCreateInfo *pCreateInfos,
|
|
const VkAllocationCallbacks *pAllocator,
|
|
VkPipeline *pPipelines)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
bool want_sync = false;
|
|
VkResult result;
|
|
|
|
if (!vn_create_pipeline_handles(dev, createInfoCount, pPipelines, alloc))
|
|
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
for (uint32_t i = 0; i < createInfoCount; i++) {
|
|
if ((pCreateInfos[i].flags & VN_PIPELINE_CREATE_SYNC_MASK))
|
|
want_sync = true;
|
|
|
|
vn_invalidate_pipeline_creation_feedback(
|
|
(const VkBaseInStructure *)pCreateInfos[i].pNext);
|
|
}
|
|
|
|
if (want_sync) {
|
|
result = vn_call_vkCreateComputePipelines(
|
|
dev->instance, device, pipelineCache, createInfoCount, pCreateInfos,
|
|
NULL, pPipelines);
|
|
if (result != VK_SUCCESS)
|
|
vn_destroy_failed_pipelines(dev, createInfoCount, pPipelines, alloc);
|
|
} else {
|
|
vn_call_vkCreateComputePipelines(dev->instance, device, pipelineCache,
|
|
createInfoCount, pCreateInfos, NULL,
|
|
pPipelines);
|
|
result = VK_SUCCESS;
|
|
}
|
|
|
|
return vn_result(dev->instance, result);
|
|
}
|
|
|
|
void
|
|
vn_DestroyPipeline(VkDevice device,
|
|
VkPipeline _pipeline,
|
|
const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VN_TRACE_FUNC();
|
|
struct vn_device *dev = vn_device_from_handle(device);
|
|
struct vn_pipeline *pipeline = vn_pipeline_from_handle(_pipeline);
|
|
const VkAllocationCallbacks *alloc =
|
|
pAllocator ? pAllocator : &dev->base.base.alloc;
|
|
|
|
if (!pipeline)
|
|
return;
|
|
|
|
vn_async_vkDestroyPipeline(dev->instance, device, _pipeline, NULL);
|
|
|
|
vn_object_base_fini(&pipeline->base);
|
|
vk_free(alloc, pipeline);
|
|
}
|