1 /*
2  * Copyright 2019 Google LLC
3  * SPDX-License-Identifier: MIT
4  *
5  * based in part on anv and radv which are:
6  * Copyright © 2015 Intel Corporation
7  * Copyright © 2016 Red Hat.
8  * Copyright © 2016 Bas Nieuwenhuizen
9  */
10 
11 #include "vn_pipeline.h"
12 
13 #include "venus-protocol/vn_protocol_driver_pipeline.h"
14 #include "venus-protocol/vn_protocol_driver_pipeline_cache.h"
15 #include "venus-protocol/vn_protocol_driver_pipeline_layout.h"
16 #include "venus-protocol/vn_protocol_driver_shader_module.h"
17 
18 #include "vn_device.h"
19 #include "vn_physical_device.h"
20 
21 /* shader module commands */
22 
23 VkResult
vn_CreateShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule)24 vn_CreateShaderModule(VkDevice device,
25                       const VkShaderModuleCreateInfo *pCreateInfo,
26                       const VkAllocationCallbacks *pAllocator,
27                       VkShaderModule *pShaderModule)
28 {
29    struct vn_device *dev = vn_device_from_handle(device);
30    const VkAllocationCallbacks *alloc =
31       pAllocator ? pAllocator : &dev->base.base.alloc;
32 
33    struct vn_shader_module *mod =
34       vk_zalloc(alloc, sizeof(*mod), VN_DEFAULT_ALIGN,
35                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
36    if (!mod)
37       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
38 
39    vn_object_base_init(&mod->base, VK_OBJECT_TYPE_SHADER_MODULE, &dev->base);
40 
41    VkShaderModule mod_handle = vn_shader_module_to_handle(mod);
42    vn_async_vkCreateShaderModule(dev->instance, device, pCreateInfo, NULL,
43                                  &mod_handle);
44 
45    *pShaderModule = mod_handle;
46 
47    return VK_SUCCESS;
48 }
49 
50 void
vn_DestroyShaderModule(VkDevice device,VkShaderModule shaderModule,const VkAllocationCallbacks * pAllocator)51 vn_DestroyShaderModule(VkDevice device,
52                        VkShaderModule shaderModule,
53                        const VkAllocationCallbacks *pAllocator)
54 {
55    struct vn_device *dev = vn_device_from_handle(device);
56    struct vn_shader_module *mod = vn_shader_module_from_handle(shaderModule);
57    const VkAllocationCallbacks *alloc =
58       pAllocator ? pAllocator : &dev->base.base.alloc;
59 
60    if (!mod)
61       return;
62 
63    vn_async_vkDestroyShaderModule(dev->instance, device, shaderModule, NULL);
64 
65    vn_object_base_fini(&mod->base);
66    vk_free(alloc, mod);
67 }
68 
69 /* pipeline layout commands */
70 
71 VkResult
vn_CreatePipelineLayout(VkDevice device,const VkPipelineLayoutCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineLayout * pPipelineLayout)72 vn_CreatePipelineLayout(VkDevice device,
73                         const VkPipelineLayoutCreateInfo *pCreateInfo,
74                         const VkAllocationCallbacks *pAllocator,
75                         VkPipelineLayout *pPipelineLayout)
76 {
77    struct vn_device *dev = vn_device_from_handle(device);
78    const VkAllocationCallbacks *alloc =
79       pAllocator ? pAllocator : &dev->base.base.alloc;
80 
81    struct vn_pipeline_layout *layout =
82       vk_zalloc(alloc, sizeof(*layout), VN_DEFAULT_ALIGN,
83                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
84    if (!layout)
85       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
86 
87    vn_object_base_init(&layout->base, VK_OBJECT_TYPE_PIPELINE_LAYOUT,
88                        &dev->base);
89 
90    VkPipelineLayout layout_handle = vn_pipeline_layout_to_handle(layout);
91    vn_async_vkCreatePipelineLayout(dev->instance, device, pCreateInfo, NULL,
92                                    &layout_handle);
93 
94    *pPipelineLayout = layout_handle;
95 
96    return VK_SUCCESS;
97 }
98 
99 void
vn_DestroyPipelineLayout(VkDevice device,VkPipelineLayout pipelineLayout,const VkAllocationCallbacks * pAllocator)100 vn_DestroyPipelineLayout(VkDevice device,
101                          VkPipelineLayout pipelineLayout,
102                          const VkAllocationCallbacks *pAllocator)
103 {
104    struct vn_device *dev = vn_device_from_handle(device);
105    struct vn_pipeline_layout *layout =
106       vn_pipeline_layout_from_handle(pipelineLayout);
107    const VkAllocationCallbacks *alloc =
108       pAllocator ? pAllocator : &dev->base.base.alloc;
109 
110    if (!layout)
111       return;
112 
113    vn_async_vkDestroyPipelineLayout(dev->instance, device, pipelineLayout,
114                                     NULL);
115 
116    vn_object_base_fini(&layout->base);
117    vk_free(alloc, layout);
118 }
119 
120 /* pipeline cache commands */
121 
122 VkResult
vn_CreatePipelineCache(VkDevice device,const VkPipelineCacheCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineCache * pPipelineCache)123 vn_CreatePipelineCache(VkDevice device,
124                        const VkPipelineCacheCreateInfo *pCreateInfo,
125                        const VkAllocationCallbacks *pAllocator,
126                        VkPipelineCache *pPipelineCache)
127 {
128    struct vn_device *dev = vn_device_from_handle(device);
129    const VkAllocationCallbacks *alloc =
130       pAllocator ? pAllocator : &dev->base.base.alloc;
131 
132    struct vn_pipeline_cache *cache =
133       vk_zalloc(alloc, sizeof(*cache), VN_DEFAULT_ALIGN,
134                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
135    if (!cache)
136       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
137 
138    vn_object_base_init(&cache->base, VK_OBJECT_TYPE_PIPELINE_CACHE,
139                        &dev->base);
140 
141    VkPipelineCacheCreateInfo local_create_info;
142    if (pCreateInfo->initialDataSize) {
143       const struct vk_pipeline_cache_header *header =
144          pCreateInfo->pInitialData;
145 
146       local_create_info = *pCreateInfo;
147       local_create_info.initialDataSize -= header->header_size;
148       local_create_info.pInitialData += header->header_size;
149       pCreateInfo = &local_create_info;
150    }
151 
152    VkPipelineCache cache_handle = vn_pipeline_cache_to_handle(cache);
153    vn_async_vkCreatePipelineCache(dev->instance, device, pCreateInfo, NULL,
154                                   &cache_handle);
155 
156    *pPipelineCache = cache_handle;
157 
158    return VK_SUCCESS;
159 }
160 
161 void
vn_DestroyPipelineCache(VkDevice device,VkPipelineCache pipelineCache,const VkAllocationCallbacks * pAllocator)162 vn_DestroyPipelineCache(VkDevice device,
163                         VkPipelineCache pipelineCache,
164                         const VkAllocationCallbacks *pAllocator)
165 {
166    struct vn_device *dev = vn_device_from_handle(device);
167    struct vn_pipeline_cache *cache =
168       vn_pipeline_cache_from_handle(pipelineCache);
169    const VkAllocationCallbacks *alloc =
170       pAllocator ? pAllocator : &dev->base.base.alloc;
171 
172    if (!cache)
173       return;
174 
175    vn_async_vkDestroyPipelineCache(dev->instance, device, pipelineCache,
176                                    NULL);
177 
178    vn_object_base_fini(&cache->base);
179    vk_free(alloc, cache);
180 }
181 
182 VkResult
vn_GetPipelineCacheData(VkDevice device,VkPipelineCache pipelineCache,size_t * pDataSize,void * pData)183 vn_GetPipelineCacheData(VkDevice device,
184                         VkPipelineCache pipelineCache,
185                         size_t *pDataSize,
186                         void *pData)
187 {
188    struct vn_device *dev = vn_device_from_handle(device);
189    struct vn_physical_device *physical_dev = dev->physical_device;
190 
191    struct vk_pipeline_cache_header *header = pData;
192    VkResult result;
193    if (!pData) {
194       result = vn_call_vkGetPipelineCacheData(dev->instance, device,
195                                               pipelineCache, pDataSize, NULL);
196       if (result != VK_SUCCESS)
197          return vn_error(dev->instance, result);
198 
199       *pDataSize += sizeof(*header);
200       return VK_SUCCESS;
201    }
202 
203    if (*pDataSize <= sizeof(*header)) {
204       *pDataSize = 0;
205       return VK_INCOMPLETE;
206    }
207 
208    const VkPhysicalDeviceProperties *props =
209       &physical_dev->properties.properties;
210    header->header_size = sizeof(*header);
211    header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
212    header->vendor_id = props->vendorID;
213    header->device_id = props->deviceID;
214    memcpy(header->uuid, props->pipelineCacheUUID, VK_UUID_SIZE);
215 
216    *pDataSize -= header->header_size;
217    result =
218       vn_call_vkGetPipelineCacheData(dev->instance, device, pipelineCache,
219                                      pDataSize, pData + header->header_size);
220    if (result < VK_SUCCESS)
221       return vn_error(dev->instance, result);
222 
223    *pDataSize += header->header_size;
224 
225    return result;
226 }
227 
228 VkResult
vn_MergePipelineCaches(VkDevice device,VkPipelineCache dstCache,uint32_t srcCacheCount,const VkPipelineCache * pSrcCaches)229 vn_MergePipelineCaches(VkDevice device,
230                        VkPipelineCache dstCache,
231                        uint32_t srcCacheCount,
232                        const VkPipelineCache *pSrcCaches)
233 {
234    struct vn_device *dev = vn_device_from_handle(device);
235 
236    vn_async_vkMergePipelineCaches(dev->instance, device, dstCache,
237                                   srcCacheCount, pSrcCaches);
238 
239    return VK_SUCCESS;
240 }
241 
242 /* pipeline commands */
243 
244 static const VkGraphicsPipelineCreateInfo *
vn_fix_graphics_pipeline_create_info(struct vn_device * dev,uint32_t create_info_count,const VkGraphicsPipelineCreateInfo * create_infos,const VkAllocationCallbacks * alloc,VkGraphicsPipelineCreateInfo ** out)245 vn_fix_graphics_pipeline_create_info(
246    struct vn_device *dev,
247    uint32_t create_info_count,
248    const VkGraphicsPipelineCreateInfo *create_infos,
249    const VkAllocationCallbacks *alloc,
250    VkGraphicsPipelineCreateInfo **out)
251 {
252    VkGraphicsPipelineCreateInfo *infos = NULL;
253    bool has_ignored_state = false;
254 
255    for (uint32_t i = 0; i < create_info_count; i++) {
256       if (create_infos[i].pRasterizationState->rasterizerDiscardEnable ==
257           VK_FALSE)
258          continue;
259 
260       if (create_infos[i].pViewportState ||
261           create_infos[i].pMultisampleState ||
262           create_infos[i].pDepthStencilState ||
263           create_infos[i].pColorBlendState) {
264          has_ignored_state = true;
265          break;
266       }
267    }
268 
269    if (!has_ignored_state)
270       return create_infos;
271 
272    infos = vk_alloc(alloc, sizeof(*infos) * create_info_count,
273                     VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
274    if (!infos)
275       return NULL;
276 
277    memcpy(infos, create_infos, sizeof(*infos) * create_info_count);
278 
279    for (uint32_t i = 0; i < create_info_count; i++) {
280       if (infos[i].pRasterizationState->rasterizerDiscardEnable == VK_FALSE)
281          continue;
282 
283       infos[i].pViewportState = NULL;
284       infos[i].pMultisampleState = NULL;
285       infos[i].pDepthStencilState = NULL;
286       infos[i].pColorBlendState = NULL;
287    }
288 
289    *out = infos;
290    return infos;
291 }
292 
293 VkResult
vn_CreateGraphicsPipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t createInfoCount,const VkGraphicsPipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines)294 vn_CreateGraphicsPipelines(VkDevice device,
295                            VkPipelineCache pipelineCache,
296                            uint32_t createInfoCount,
297                            const VkGraphicsPipelineCreateInfo *pCreateInfos,
298                            const VkAllocationCallbacks *pAllocator,
299                            VkPipeline *pPipelines)
300 {
301    struct vn_device *dev = vn_device_from_handle(device);
302    const VkAllocationCallbacks *alloc =
303       pAllocator ? pAllocator : &dev->base.base.alloc;
304    VkGraphicsPipelineCreateInfo *local_infos = NULL;
305 
306    pCreateInfos = vn_fix_graphics_pipeline_create_info(
307       dev, createInfoCount, pCreateInfos, alloc, &local_infos);
308    if (!pCreateInfos)
309       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
310 
311    for (uint32_t i = 0; i < createInfoCount; i++) {
312       struct vn_pipeline *pipeline =
313          vk_zalloc(alloc, sizeof(*pipeline), VN_DEFAULT_ALIGN,
314                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
315       if (!pipeline) {
316          for (uint32_t j = 0; j < i; j++)
317             vk_free(alloc, vn_pipeline_from_handle(pPipelines[j]));
318 
319          if (local_infos)
320             vk_free(alloc, local_infos);
321 
322          memset(pPipelines, 0, sizeof(*pPipelines) * createInfoCount);
323          return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
324       }
325 
326       vn_object_base_init(&pipeline->base, VK_OBJECT_TYPE_PIPELINE,
327                           &dev->base);
328 
329       VkPipeline pipeline_handle = vn_pipeline_to_handle(pipeline);
330       pPipelines[i] = pipeline_handle;
331    }
332 
333    vn_async_vkCreateGraphicsPipelines(dev->instance, device, pipelineCache,
334                                       createInfoCount, pCreateInfos, NULL,
335                                       pPipelines);
336 
337    if (local_infos)
338       vk_free(alloc, local_infos);
339 
340    return VK_SUCCESS;
341 }
342 
343 VkResult
vn_CreateComputePipelines(VkDevice device,VkPipelineCache pipelineCache,uint32_t createInfoCount,const VkComputePipelineCreateInfo * pCreateInfos,const VkAllocationCallbacks * pAllocator,VkPipeline * pPipelines)344 vn_CreateComputePipelines(VkDevice device,
345                           VkPipelineCache pipelineCache,
346                           uint32_t createInfoCount,
347                           const VkComputePipelineCreateInfo *pCreateInfos,
348                           const VkAllocationCallbacks *pAllocator,
349                           VkPipeline *pPipelines)
350 {
351    struct vn_device *dev = vn_device_from_handle(device);
352    const VkAllocationCallbacks *alloc =
353       pAllocator ? pAllocator : &dev->base.base.alloc;
354 
355    for (uint32_t i = 0; i < createInfoCount; i++) {
356       struct vn_pipeline *pipeline =
357          vk_zalloc(alloc, sizeof(*pipeline), VN_DEFAULT_ALIGN,
358                    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
359       if (!pipeline) {
360          for (uint32_t j = 0; j < i; j++)
361             vk_free(alloc, vn_pipeline_from_handle(pPipelines[j]));
362          memset(pPipelines, 0, sizeof(*pPipelines) * createInfoCount);
363          return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
364       }
365 
366       vn_object_base_init(&pipeline->base, VK_OBJECT_TYPE_PIPELINE,
367                           &dev->base);
368 
369       VkPipeline pipeline_handle = vn_pipeline_to_handle(pipeline);
370       pPipelines[i] = pipeline_handle;
371    }
372 
373    vn_async_vkCreateComputePipelines(dev->instance, device, pipelineCache,
374                                      createInfoCount, pCreateInfos, NULL,
375                                      pPipelines);
376 
377    return VK_SUCCESS;
378 }
379 
380 void
vn_DestroyPipeline(VkDevice device,VkPipeline _pipeline,const VkAllocationCallbacks * pAllocator)381 vn_DestroyPipeline(VkDevice device,
382                    VkPipeline _pipeline,
383                    const VkAllocationCallbacks *pAllocator)
384 {
385    struct vn_device *dev = vn_device_from_handle(device);
386    struct vn_pipeline *pipeline = vn_pipeline_from_handle(_pipeline);
387    const VkAllocationCallbacks *alloc =
388       pAllocator ? pAllocator : &dev->base.base.alloc;
389 
390    if (!pipeline)
391       return;
392 
393    vn_async_vkDestroyPipeline(dev->instance, device, _pipeline, NULL);
394 
395    vn_object_base_fini(&pipeline->base);
396    vk_free(alloc, pipeline);
397 }
398