1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2022 Imagination Technologies Ltd. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * based in part on v3dv driver which is: 5bf215546Sopenharmony_ci * Copyright © 2019 Raspberry Pi 6bf215546Sopenharmony_ci * 7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 8bf215546Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 9bf215546Sopenharmony_ci * in the Software without restriction, including without limitation the rights 10bf215546Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11bf215546Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 12bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions: 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 15bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 16bf215546Sopenharmony_ci * Software. 17bf215546Sopenharmony_ci * 18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21bf215546Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24bf215546Sopenharmony_ci * SOFTWARE. 25bf215546Sopenharmony_ci */ 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci#include <assert.h> 28bf215546Sopenharmony_ci#include <stdbool.h> 29bf215546Sopenharmony_ci#include <stdint.h> 30bf215546Sopenharmony_ci#include <string.h> 31bf215546Sopenharmony_ci#include <vulkan/vulkan.h> 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "compiler/shader_enums.h" 34bf215546Sopenharmony_ci#include "hwdef/rogue_hw_utils.h" 35bf215546Sopenharmony_ci#include "nir/nir.h" 36bf215546Sopenharmony_ci#include "pvr_bo.h" 37bf215546Sopenharmony_ci#include "pvr_csb.h" 38bf215546Sopenharmony_ci#include "pvr_csb_enum_helpers.h" 39bf215546Sopenharmony_ci#include "pvr_hardcode.h" 40bf215546Sopenharmony_ci#include "pvr_pds.h" 41bf215546Sopenharmony_ci#include "pvr_private.h" 42bf215546Sopenharmony_ci#include "pvr_shader.h" 43bf215546Sopenharmony_ci#include "pvr_types.h" 44bf215546Sopenharmony_ci#include "rogue/rogue.h" 45bf215546Sopenharmony_ci#include "rogue/rogue_build_data.h" 46bf215546Sopenharmony_ci#include "util/log.h" 47bf215546Sopenharmony_ci#include "util/macros.h" 48bf215546Sopenharmony_ci#include "util/ralloc.h" 49bf215546Sopenharmony_ci#include "util/u_math.h" 50bf215546Sopenharmony_ci#include "vk_alloc.h" 51bf215546Sopenharmony_ci#include "vk_log.h" 52bf215546Sopenharmony_ci#include "vk_object.h" 53bf215546Sopenharmony_ci#include "vk_util.h" 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci/***************************************************************************** 56bf215546Sopenharmony_ci PDS functions 57bf215546Sopenharmony_ci*****************************************************************************/ 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci/* If allocator == NULL, the internal one will be used. */ 60bf215546Sopenharmony_cistatic VkResult pvr_pds_coeff_program_create_and_upload( 61bf215546Sopenharmony_ci struct pvr_device *device, 62bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 63bf215546Sopenharmony_ci const uint32_t *fpu_iterators, 64bf215546Sopenharmony_ci uint32_t fpu_iterators_count, 65bf215546Sopenharmony_ci const uint32_t *destinations, 66bf215546Sopenharmony_ci struct pvr_pds_upload *const pds_upload_out) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci struct pvr_pds_coeff_loading_program program = { 69bf215546Sopenharmony_ci .num_fpu_iterators = fpu_iterators_count, 70bf215546Sopenharmony_ci }; 71bf215546Sopenharmony_ci uint32_t staging_buffer_size; 72bf215546Sopenharmony_ci uint32_t *staging_buffer; 73bf215546Sopenharmony_ci VkResult result; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci assert(fpu_iterators_count < PVR_MAXIMUM_ITERATIONS); 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /* Get the size of the program and then allocate that much memory. */ 78bf215546Sopenharmony_ci pvr_pds_coefficient_loading(&program, NULL, PDS_GENERATE_SIZES); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci staging_buffer_size = 81bf215546Sopenharmony_ci (program.code_size + program.data_size) * sizeof(*staging_buffer); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci staging_buffer = vk_alloc2(&device->vk.alloc, 84bf215546Sopenharmony_ci allocator, 85bf215546Sopenharmony_ci staging_buffer_size, 86bf215546Sopenharmony_ci 8, 87bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 88bf215546Sopenharmony_ci if (!staging_buffer) 89bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci /* FIXME: Should we save pointers when we redesign the pds gen api ? */ 92bf215546Sopenharmony_ci typed_memcpy(program.FPU_iterators, 93bf215546Sopenharmony_ci fpu_iterators, 94bf215546Sopenharmony_ci program.num_fpu_iterators); 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci typed_memcpy(program.destination, destinations, program.num_fpu_iterators); 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci /* Generate the program into is the staging_buffer. */ 99bf215546Sopenharmony_ci pvr_pds_coefficient_loading(&program, 100bf215546Sopenharmony_ci staging_buffer, 101bf215546Sopenharmony_ci PDS_GENERATE_CODEDATA_SEGMENTS); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 104bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 105bf215546Sopenharmony_ci &staging_buffer[0], 106bf215546Sopenharmony_ci program.data_size, 107bf215546Sopenharmony_ci 16, 108bf215546Sopenharmony_ci &staging_buffer[program.data_size], 109bf215546Sopenharmony_ci program.code_size, 110bf215546Sopenharmony_ci 16, 111bf215546Sopenharmony_ci 16, 112bf215546Sopenharmony_ci pds_upload_out); 113bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 114bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 115bf215546Sopenharmony_ci return result; 116bf215546Sopenharmony_ci } 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci return VK_SUCCESS; 121bf215546Sopenharmony_ci} 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci/* FIXME: move this elsewhere since it's also called in pvr_pass.c? */ 124bf215546Sopenharmony_ci/* If allocator == NULL, the internal one will be used. */ 125bf215546Sopenharmony_ciVkResult pvr_pds_fragment_program_create_and_upload( 126bf215546Sopenharmony_ci struct pvr_device *device, 127bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 128bf215546Sopenharmony_ci const struct pvr_bo *fragment_shader_bo, 129bf215546Sopenharmony_ci uint32_t fragment_temp_count, 130bf215546Sopenharmony_ci enum rogue_msaa_mode msaa_mode, 131bf215546Sopenharmony_ci bool has_phase_rate_change, 132bf215546Sopenharmony_ci struct pvr_pds_upload *const pds_upload_out) 133bf215546Sopenharmony_ci{ 134bf215546Sopenharmony_ci const enum PVRX(PDSINST_DOUTU_SAMPLE_RATE) 135bf215546Sopenharmony_ci sample_rate = pvr_pdsinst_doutu_sample_rate_from_rogue(msaa_mode); 136bf215546Sopenharmony_ci struct pvr_pds_kickusc_program program = { 0 }; 137bf215546Sopenharmony_ci uint32_t staging_buffer_size; 138bf215546Sopenharmony_ci uint32_t *staging_buffer; 139bf215546Sopenharmony_ci VkResult result; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci /* FIXME: Should it be passing in the USC offset rather than address here? 142bf215546Sopenharmony_ci */ 143bf215546Sopenharmony_ci /* Note this is not strictly required to be done before calculating the 144bf215546Sopenharmony_ci * staging_buffer_size in this particular case. It can also be done after 145bf215546Sopenharmony_ci * allocating the buffer. The size from pvr_pds_kick_usc() is constant. 146bf215546Sopenharmony_ci */ 147bf215546Sopenharmony_ci pvr_pds_setup_doutu(&program.usc_task_control, 148bf215546Sopenharmony_ci fragment_shader_bo->vma->dev_addr.addr, 149bf215546Sopenharmony_ci fragment_temp_count, 150bf215546Sopenharmony_ci sample_rate, 151bf215546Sopenharmony_ci has_phase_rate_change); 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci pvr_pds_kick_usc(&program, NULL, 0, false, PDS_GENERATE_SIZES); 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci staging_buffer_size = 156bf215546Sopenharmony_ci (program.code_size + program.data_size) * sizeof(*staging_buffer); 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci staging_buffer = vk_alloc2(&device->vk.alloc, 159bf215546Sopenharmony_ci allocator, 160bf215546Sopenharmony_ci staging_buffer_size, 161bf215546Sopenharmony_ci 8, 162bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 163bf215546Sopenharmony_ci if (!staging_buffer) 164bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci pvr_pds_kick_usc(&program, 167bf215546Sopenharmony_ci staging_buffer, 168bf215546Sopenharmony_ci 0, 169bf215546Sopenharmony_ci false, 170bf215546Sopenharmony_ci PDS_GENERATE_CODEDATA_SEGMENTS); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 173bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 174bf215546Sopenharmony_ci &staging_buffer[0], 175bf215546Sopenharmony_ci program.data_size, 176bf215546Sopenharmony_ci 16, 177bf215546Sopenharmony_ci &staging_buffer[program.data_size], 178bf215546Sopenharmony_ci program.code_size, 179bf215546Sopenharmony_ci 16, 180bf215546Sopenharmony_ci 16, 181bf215546Sopenharmony_ci pds_upload_out); 182bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 183bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 184bf215546Sopenharmony_ci return result; 185bf215546Sopenharmony_ci } 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci return VK_SUCCESS; 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_cistatic inline size_t pvr_pds_get_max_vertex_program_const_map_size_in_bytes( 193bf215546Sopenharmony_ci const struct pvr_device_info *dev_info, 194bf215546Sopenharmony_ci bool robust_buffer_access) 195bf215546Sopenharmony_ci{ 196bf215546Sopenharmony_ci /* FIXME: Use more local variable to improve formatting. */ 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /* Maximum memory allocation needed for const map entries in 199bf215546Sopenharmony_ci * pvr_pds_generate_vertex_primary_program(). 200bf215546Sopenharmony_ci * When robustBufferAccess is disabled, it must be >= 410. 201bf215546Sopenharmony_ci * When robustBufferAccess is enabled, it must be >= 570. 202bf215546Sopenharmony_ci * 203bf215546Sopenharmony_ci * 1. Size of entry for base instance 204bf215546Sopenharmony_ci * (pvr_const_map_entry_base_instance) 205bf215546Sopenharmony_ci * 206bf215546Sopenharmony_ci * 2. Max. number of vertex inputs (PVR_MAX_VERTEX_INPUT_BINDINGS) * ( 207bf215546Sopenharmony_ci * if (!robustBufferAccess) 208bf215546Sopenharmony_ci * size of vertex attribute entry 209bf215546Sopenharmony_ci * (pvr_const_map_entry_vertex_attribute_address) + 210bf215546Sopenharmony_ci * else 211bf215546Sopenharmony_ci * size of robust vertex attribute entry 212bf215546Sopenharmony_ci * (pvr_const_map_entry_robust_vertex_attribute_address) + 213bf215546Sopenharmony_ci * size of entry for max attribute index 214bf215546Sopenharmony_ci * (pvr_const_map_entry_vertex_attribute_max_index) + 215bf215546Sopenharmony_ci * fi 216bf215546Sopenharmony_ci * size of Unified Store burst entry 217bf215546Sopenharmony_ci * (pvr_const_map_entry_literal32) + 218bf215546Sopenharmony_ci * size of entry for vertex stride 219bf215546Sopenharmony_ci * (pvr_const_map_entry_literal32) + 220bf215546Sopenharmony_ci * size of entries for DDMAD control word 221bf215546Sopenharmony_ci * (num_ddmad_literals * pvr_const_map_entry_literal32)) 222bf215546Sopenharmony_ci * 223bf215546Sopenharmony_ci * 3. Size of entry for DOUTW vertex/instance control word 224bf215546Sopenharmony_ci * (pvr_const_map_entry_literal32) 225bf215546Sopenharmony_ci * 226bf215546Sopenharmony_ci * 4. Size of DOUTU entry (pvr_const_map_entry_doutu_address) 227bf215546Sopenharmony_ci */ 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci const size_t attribute_size = 230bf215546Sopenharmony_ci (!robust_buffer_access) 231bf215546Sopenharmony_ci ? sizeof(struct pvr_const_map_entry_vertex_attribute_address) 232bf215546Sopenharmony_ci : sizeof(struct pvr_const_map_entry_robust_vertex_attribute_address) + 233bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_vertex_attribute_max_index); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci /* If has_pds_ddmadt the DDMAD control word is now a DDMADT control word 236bf215546Sopenharmony_ci * and is increased by one DWORD to contain the data for the DDMADT's 237bf215546Sopenharmony_ci * out-of-bounds check. 238bf215546Sopenharmony_ci */ 239bf215546Sopenharmony_ci const size_t pvr_pds_const_map_vertex_entry_num_ddmad_literals = 240bf215546Sopenharmony_ci 1U + (size_t)PVR_HAS_FEATURE(dev_info, pds_ddmadt); 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci return (sizeof(struct pvr_const_map_entry_base_instance) + 243bf215546Sopenharmony_ci PVR_MAX_VERTEX_INPUT_BINDINGS * 244bf215546Sopenharmony_ci (attribute_size + 245bf215546Sopenharmony_ci (2 + pvr_pds_const_map_vertex_entry_num_ddmad_literals) * 246bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_literal32)) + 247bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_literal32) + 248bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_doutu_address)); 249bf215546Sopenharmony_ci} 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci/* This is a const pointer to an array of pvr_pds_vertex_dma structs. 252bf215546Sopenharmony_ci * The array being pointed to is of PVR_MAX_VERTEX_ATTRIB_DMAS size. 253bf215546Sopenharmony_ci */ 254bf215546Sopenharmony_citypedef struct pvr_pds_vertex_dma ( 255bf215546Sopenharmony_ci *const 256bf215546Sopenharmony_ci pvr_pds_attrib_dma_descriptions_array_ptr)[PVR_MAX_VERTEX_ATTRIB_DMAS]; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci/* dma_descriptions_out_ptr is a pointer to the array used as output. 259bf215546Sopenharmony_ci * The whole array might not be filled so dma_count_out indicates how many 260bf215546Sopenharmony_ci * elements were used. 261bf215546Sopenharmony_ci */ 262bf215546Sopenharmony_cistatic void pvr_pds_vertex_attrib_init_dma_descriptions( 263bf215546Sopenharmony_ci const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, 264bf215546Sopenharmony_ci const struct rogue_vs_build_data *vs_data, 265bf215546Sopenharmony_ci pvr_pds_attrib_dma_descriptions_array_ptr dma_descriptions_out_ptr, 266bf215546Sopenharmony_ci uint32_t *const dma_count_out) 267bf215546Sopenharmony_ci{ 268bf215546Sopenharmony_ci struct pvr_pds_vertex_dma *const dma_descriptions = 269bf215546Sopenharmony_ci *dma_descriptions_out_ptr; 270bf215546Sopenharmony_ci uint32_t dma_count = 0; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (!vertex_input_state) { 273bf215546Sopenharmony_ci *dma_count_out = 0; 274bf215546Sopenharmony_ci return; 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci for (uint32_t i = 0; i < vertex_input_state->vertexAttributeDescriptionCount; 278bf215546Sopenharmony_ci i++) { 279bf215546Sopenharmony_ci const VkVertexInputAttributeDescription *const attrib_desc = 280bf215546Sopenharmony_ci &vertex_input_state->pVertexAttributeDescriptions[i]; 281bf215546Sopenharmony_ci const VkVertexInputBindingDescription *binding_desc = NULL; 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci /* Finding the matching binding description. */ 284bf215546Sopenharmony_ci for (uint32_t j = 0; 285bf215546Sopenharmony_ci j < vertex_input_state->vertexBindingDescriptionCount; 286bf215546Sopenharmony_ci j++) { 287bf215546Sopenharmony_ci const VkVertexInputBindingDescription *const current_binding_desc = 288bf215546Sopenharmony_ci &vertex_input_state->pVertexBindingDescriptions[j]; 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci if (current_binding_desc->binding == attrib_desc->binding) { 291bf215546Sopenharmony_ci binding_desc = current_binding_desc; 292bf215546Sopenharmony_ci break; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci } 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci /* From the Vulkan 1.2.195 spec for 297bf215546Sopenharmony_ci * VkPipelineVertexInputStateCreateInfo: 298bf215546Sopenharmony_ci * 299bf215546Sopenharmony_ci * "For every binding specified by each element of 300bf215546Sopenharmony_ci * pVertexAttributeDescriptions, a 301bf215546Sopenharmony_ci * VkVertexInputBindingDescription must exist in 302bf215546Sopenharmony_ci * pVertexBindingDescriptions with the same value of binding" 303bf215546Sopenharmony_ci * 304bf215546Sopenharmony_ci * So we don't check if we found the matching binding description 305bf215546Sopenharmony_ci * or not. 306bf215546Sopenharmony_ci */ 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci struct pvr_pds_vertex_dma *const dma_desc = &dma_descriptions[dma_count]; 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci size_t location = attrib_desc->location; 311bf215546Sopenharmony_ci assert(location < vs_data->inputs.num_input_vars); 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci dma_desc->offset = attrib_desc->offset; 314bf215546Sopenharmony_ci dma_desc->stride = binding_desc->stride; 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci dma_desc->flags = 0; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci if (binding_desc->inputRate == VK_VERTEX_INPUT_RATE_INSTANCE) 319bf215546Sopenharmony_ci dma_desc->flags |= PVR_PDS_VERTEX_DMA_FLAGS_INSTANCE_RATE; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci dma_desc->size_in_dwords = vs_data->inputs.components[location]; 322bf215546Sopenharmony_ci /* TODO: This will be different when other types are supported. 323bf215546Sopenharmony_ci * Store in vs_data with base and components? 324bf215546Sopenharmony_ci */ 325bf215546Sopenharmony_ci /* TODO: Use attrib_desc->format. */ 326bf215546Sopenharmony_ci dma_desc->component_size_in_bytes = ROGUE_REG_SIZE_BYTES; 327bf215546Sopenharmony_ci dma_desc->destination = vs_data->inputs.base[location]; 328bf215546Sopenharmony_ci dma_desc->binding_index = attrib_desc->binding; 329bf215546Sopenharmony_ci dma_desc->divisor = 1; 330bf215546Sopenharmony_ci dma_desc->robustness_buffer_offset = 0; 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci ++dma_count; 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci *dma_count_out = dma_count; 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_cistatic VkResult pvr_pds_vertex_attrib_program_create_and_upload( 339bf215546Sopenharmony_ci struct pvr_device *const device, 340bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 341bf215546Sopenharmony_ci struct pvr_pds_vertex_primary_program_input *const input, 342bf215546Sopenharmony_ci struct pvr_pds_attrib_program *const program_out) 343bf215546Sopenharmony_ci{ 344bf215546Sopenharmony_ci const size_t const_entries_size_in_bytes = 345bf215546Sopenharmony_ci pvr_pds_get_max_vertex_program_const_map_size_in_bytes( 346bf215546Sopenharmony_ci &device->pdevice->dev_info, 347bf215546Sopenharmony_ci device->features.robustBufferAccess); 348bf215546Sopenharmony_ci struct pvr_pds_upload *const program = &program_out->program; 349bf215546Sopenharmony_ci struct pvr_pds_info *const info = &program_out->info; 350bf215546Sopenharmony_ci struct pvr_const_map_entry *entries_buffer; 351bf215546Sopenharmony_ci ASSERTED uint32_t code_size_in_dwords; 352bf215546Sopenharmony_ci size_t staging_buffer_size; 353bf215546Sopenharmony_ci uint32_t *staging_buffer; 354bf215546Sopenharmony_ci VkResult result; 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci memset(info, 0, sizeof(*info)); 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci entries_buffer = vk_alloc2(&device->vk.alloc, 359bf215546Sopenharmony_ci allocator, 360bf215546Sopenharmony_ci const_entries_size_in_bytes, 361bf215546Sopenharmony_ci 8, 362bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 363bf215546Sopenharmony_ci if (!entries_buffer) 364bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_ci info->entries = entries_buffer; 367bf215546Sopenharmony_ci info->entries_size_in_bytes = const_entries_size_in_bytes; 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci pvr_pds_generate_vertex_primary_program(input, 370bf215546Sopenharmony_ci NULL, 371bf215546Sopenharmony_ci info, 372bf215546Sopenharmony_ci device->features.robustBufferAccess, 373bf215546Sopenharmony_ci &device->pdevice->dev_info); 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_ci code_size_in_dwords = info->code_size_in_dwords; 376bf215546Sopenharmony_ci staging_buffer_size = info->code_size_in_dwords * sizeof(*staging_buffer); 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ci staging_buffer = vk_alloc2(&device->vk.alloc, 379bf215546Sopenharmony_ci allocator, 380bf215546Sopenharmony_ci staging_buffer_size, 381bf215546Sopenharmony_ci 8, 382bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 383bf215546Sopenharmony_ci if (!staging_buffer) { 384bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, entries_buffer); 385bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci /* This also fills in info->entries. */ 389bf215546Sopenharmony_ci pvr_pds_generate_vertex_primary_program(input, 390bf215546Sopenharmony_ci staging_buffer, 391bf215546Sopenharmony_ci info, 392bf215546Sopenharmony_ci device->features.robustBufferAccess, 393bf215546Sopenharmony_ci &device->pdevice->dev_info); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci assert(info->code_size_in_dwords <= code_size_in_dwords); 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci /* FIXME: Add a vk_realloc2() ? */ 398bf215546Sopenharmony_ci entries_buffer = vk_realloc((!allocator) ? &device->vk.alloc : allocator, 399bf215546Sopenharmony_ci entries_buffer, 400bf215546Sopenharmony_ci info->entries_written_size_in_bytes, 401bf215546Sopenharmony_ci 8, 402bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 403bf215546Sopenharmony_ci if (!entries_buffer) { 404bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 405bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci info->entries = entries_buffer; 409bf215546Sopenharmony_ci info->entries_size_in_bytes = info->entries_written_size_in_bytes; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 412bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 413bf215546Sopenharmony_ci NULL, 414bf215546Sopenharmony_ci 0, 415bf215546Sopenharmony_ci 0, 416bf215546Sopenharmony_ci staging_buffer, 417bf215546Sopenharmony_ci info->code_size_in_dwords, 418bf215546Sopenharmony_ci 16, 419bf215546Sopenharmony_ci 16, 420bf215546Sopenharmony_ci program); 421bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 422bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, entries_buffer); 423bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 426bf215546Sopenharmony_ci } 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci return VK_SUCCESS; 431bf215546Sopenharmony_ci} 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_cistatic inline void pvr_pds_vertex_attrib_program_destroy( 434bf215546Sopenharmony_ci struct pvr_device *const device, 435bf215546Sopenharmony_ci const struct VkAllocationCallbacks *const allocator, 436bf215546Sopenharmony_ci struct pvr_pds_attrib_program *const program) 437bf215546Sopenharmony_ci{ 438bf215546Sopenharmony_ci pvr_bo_free(device, program->program.pvr_bo); 439bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, program->info.entries); 440bf215546Sopenharmony_ci} 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci/* This is a const pointer to an array of pvr_pds_attrib_program structs. 443bf215546Sopenharmony_ci * The array being pointed to is of PVR_PDS_VERTEX_ATTRIB_PROGRAM_COUNT size. 444bf215546Sopenharmony_ci */ 445bf215546Sopenharmony_citypedef struct pvr_pds_attrib_program (*const pvr_pds_attrib_programs_array_ptr) 446bf215546Sopenharmony_ci [PVR_PDS_VERTEX_ATTRIB_PROGRAM_COUNT]; 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci/* Generate and uploads a PDS program for DMAing vertex attribs into USC vertex 449bf215546Sopenharmony_ci * inputs. This will bake the code segment and create a template of the data 450bf215546Sopenharmony_ci * segment for the command buffer to fill in. 451bf215546Sopenharmony_ci */ 452bf215546Sopenharmony_ci/* If allocator == NULL, the internal one will be used. 453bf215546Sopenharmony_ci * 454bf215546Sopenharmony_ci * programs_out_ptr is a pointer to the array where the outputs will be placed. 455bf215546Sopenharmony_ci * */ 456bf215546Sopenharmony_cistatic VkResult pvr_pds_vertex_attrib_programs_create_and_upload( 457bf215546Sopenharmony_ci struct pvr_device *device, 458bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 459bf215546Sopenharmony_ci const VkPipelineVertexInputStateCreateInfo *const vertex_input_state, 460bf215546Sopenharmony_ci uint32_t usc_temp_count, 461bf215546Sopenharmony_ci const struct rogue_vs_build_data *vs_data, 462bf215546Sopenharmony_ci pvr_pds_attrib_programs_array_ptr programs_out_ptr) 463bf215546Sopenharmony_ci{ 464bf215546Sopenharmony_ci struct pvr_pds_vertex_dma dma_descriptions[PVR_MAX_VERTEX_ATTRIB_DMAS]; 465bf215546Sopenharmony_ci struct pvr_pds_attrib_program *const programs_out = *programs_out_ptr; 466bf215546Sopenharmony_ci struct pvr_pds_vertex_primary_program_input input = { 467bf215546Sopenharmony_ci .dma_list = dma_descriptions, 468bf215546Sopenharmony_ci }; 469bf215546Sopenharmony_ci VkResult result; 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci pvr_pds_vertex_attrib_init_dma_descriptions(vertex_input_state, 472bf215546Sopenharmony_ci vs_data, 473bf215546Sopenharmony_ci &dma_descriptions, 474bf215546Sopenharmony_ci &input.dma_count); 475bf215546Sopenharmony_ci 476bf215546Sopenharmony_ci pvr_pds_setup_doutu(&input.usc_task_control, 477bf215546Sopenharmony_ci 0, 478bf215546Sopenharmony_ci usc_temp_count, 479bf215546Sopenharmony_ci PVRX(PDSINST_DOUTU_SAMPLE_RATE_INSTANCE), 480bf215546Sopenharmony_ci false); 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci /* TODO: If statements for all the "bRequired"s + ui32ExtraFlags. */ 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci /* Note: programs_out_ptr is a pointer to an array so this is fine. See the 485bf215546Sopenharmony_ci * typedef. 486bf215546Sopenharmony_ci */ 487bf215546Sopenharmony_ci for (uint32_t i = 0; i < ARRAY_SIZE(*programs_out_ptr); i++) { 488bf215546Sopenharmony_ci switch (i) { 489bf215546Sopenharmony_ci case PVR_PDS_VERTEX_ATTRIB_PROGRAM_BASIC: 490bf215546Sopenharmony_ci input.flags = 0; 491bf215546Sopenharmony_ci break; 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci case PVR_PDS_VERTEX_ATTRIB_PROGRAM_BASE_INSTANCE: 494bf215546Sopenharmony_ci input.flags = PVR_PDS_VERTEX_FLAGS_BASE_INSTANCE_VARIANT; 495bf215546Sopenharmony_ci break; 496bf215546Sopenharmony_ci 497bf215546Sopenharmony_ci case PVR_PDS_VERTEX_ATTRIB_PROGRAM_DRAW_INDIRECT: 498bf215546Sopenharmony_ci /* We unset INSTANCE and set INDIRECT. */ 499bf215546Sopenharmony_ci input.flags = PVR_PDS_VERTEX_FLAGS_DRAW_INDIRECT_VARIANT; 500bf215546Sopenharmony_ci break; 501bf215546Sopenharmony_ci 502bf215546Sopenharmony_ci default: 503bf215546Sopenharmony_ci unreachable("Invalid vertex attrib program type."); 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci result = 507bf215546Sopenharmony_ci pvr_pds_vertex_attrib_program_create_and_upload(device, 508bf215546Sopenharmony_ci allocator, 509bf215546Sopenharmony_ci &input, 510bf215546Sopenharmony_ci &programs_out[i]); 511bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 512bf215546Sopenharmony_ci for (uint32_t j = 0; j < i; j++) { 513bf215546Sopenharmony_ci pvr_pds_vertex_attrib_program_destroy(device, 514bf215546Sopenharmony_ci allocator, 515bf215546Sopenharmony_ci &programs_out[j]); 516bf215546Sopenharmony_ci } 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_ci return result; 519bf215546Sopenharmony_ci } 520bf215546Sopenharmony_ci } 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci return VK_SUCCESS; 523bf215546Sopenharmony_ci} 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_cistatic size_t pvr_pds_get_max_descriptor_upload_const_map_size_in_bytes() 526bf215546Sopenharmony_ci{ 527bf215546Sopenharmony_ci /* Maximum memory allocation needed for const map entries in 528bf215546Sopenharmony_ci * pvr_pds_generate_descriptor_upload_program(). 529bf215546Sopenharmony_ci * It must be >= 688 bytes. This size is calculated as the sum of: 530bf215546Sopenharmony_ci * 531bf215546Sopenharmony_ci * 1. Max. number of descriptor sets (8) * ( 532bf215546Sopenharmony_ci * size of descriptor entry 533bf215546Sopenharmony_ci * (pvr_const_map_entry_descriptor_set) + 534bf215546Sopenharmony_ci * size of Common Store burst entry 535bf215546Sopenharmony_ci * (pvr_const_map_entry_literal32)) 536bf215546Sopenharmony_ci * 537bf215546Sopenharmony_ci * 2. Max. number of PDS program buffers (24) * ( 538bf215546Sopenharmony_ci * size of the largest buffer structure 539bf215546Sopenharmony_ci * (pvr_const_map_entry_constant_buffer) + 540bf215546Sopenharmony_ci * size of Common Store burst entry 541bf215546Sopenharmony_ci * (pvr_const_map_entry_literal32) 542bf215546Sopenharmony_ci * 543bf215546Sopenharmony_ci * 3. Size of DOUTU entry (pvr_const_map_entry_doutu_address) 544bf215546Sopenharmony_ci */ 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_ci /* FIXME: PVR_MAX_DESCRIPTOR_SETS is 4 and not 8. The comment above seems to 547bf215546Sopenharmony_ci * say that it should be 8. 548bf215546Sopenharmony_ci * Figure our a define for this or is the comment wrong? 549bf215546Sopenharmony_ci */ 550bf215546Sopenharmony_ci return (8 * (sizeof(struct pvr_const_map_entry_descriptor_set) + 551bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_literal32)) + 552bf215546Sopenharmony_ci PVR_PDS_MAX_BUFFERS * 553bf215546Sopenharmony_ci (sizeof(struct pvr_const_map_entry_constant_buffer) + 554bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_literal32)) + 555bf215546Sopenharmony_ci sizeof(struct pvr_const_map_entry_doutu_address)); 556bf215546Sopenharmony_ci} 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci/* This is a const pointer to an array of PVR_PDS_MAX_BUFFERS pvr_pds_buffer 559bf215546Sopenharmony_ci * structs. 560bf215546Sopenharmony_ci */ 561bf215546Sopenharmony_citypedef struct pvr_pds_buffer ( 562bf215546Sopenharmony_ci *const pvr_pds_descriptor_program_buffer_array_ptr)[PVR_PDS_MAX_BUFFERS]; 563bf215546Sopenharmony_ci 564bf215546Sopenharmony_ci/** 565bf215546Sopenharmony_ci * \brief Setup buffers for the PDS descriptor program. 566bf215546Sopenharmony_ci * 567bf215546Sopenharmony_ci * Sets up buffers required by the PDS gen api based on compiler info. 568bf215546Sopenharmony_ci * 569bf215546Sopenharmony_ci * For compile time static constants that need DMAing it uploads them and 570bf215546Sopenharmony_ci * returns the upload in \r static_consts_pvr_bo_out . 571bf215546Sopenharmony_ci */ 572bf215546Sopenharmony_cistatic VkResult pvr_pds_descriptor_program_setup_buffers( 573bf215546Sopenharmony_ci struct pvr_device *device, 574bf215546Sopenharmony_ci bool robust_buffer_access, 575bf215546Sopenharmony_ci const struct rogue_compile_time_consts_data *compile_time_consts_data, 576bf215546Sopenharmony_ci const struct rogue_ubo_data *ubo_data, 577bf215546Sopenharmony_ci pvr_pds_descriptor_program_buffer_array_ptr buffers_out_ptr, 578bf215546Sopenharmony_ci uint32_t *const buffer_count_out, 579bf215546Sopenharmony_ci struct pvr_bo **const static_consts_pvr_bo_out) 580bf215546Sopenharmony_ci{ 581bf215546Sopenharmony_ci struct pvr_pds_buffer *const buffers = *buffers_out_ptr; 582bf215546Sopenharmony_ci uint32_t buffer_count = 0; 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci for (size_t i = 0; i < ubo_data->num_ubo_entries; i++) { 585bf215546Sopenharmony_ci struct pvr_pds_buffer *current_buffer = &buffers[buffer_count]; 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci /* This is fine since buffers_out_ptr is a pointer to an array. */ 588bf215546Sopenharmony_ci assert(buffer_count < ARRAY_SIZE(*buffers_out_ptr)); 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci current_buffer->type = PVR_BUFFER_TYPE_UBO; 591bf215546Sopenharmony_ci current_buffer->size_in_dwords = ubo_data->size[i]; 592bf215546Sopenharmony_ci current_buffer->destination = ubo_data->dest[i]; 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci current_buffer->buffer_id = buffer_count; 595bf215546Sopenharmony_ci current_buffer->desc_set = ubo_data->desc_set[i]; 596bf215546Sopenharmony_ci current_buffer->binding = ubo_data->binding[i]; 597bf215546Sopenharmony_ci /* TODO: Is this always the case? 598bf215546Sopenharmony_ci * E.g. can multiple UBOs have the same base buffer? 599bf215546Sopenharmony_ci */ 600bf215546Sopenharmony_ci current_buffer->source_offset = 0; 601bf215546Sopenharmony_ci 602bf215546Sopenharmony_ci buffer_count++; 603bf215546Sopenharmony_ci } 604bf215546Sopenharmony_ci 605bf215546Sopenharmony_ci if (compile_time_consts_data->static_consts.num > 0) { 606bf215546Sopenharmony_ci VkResult result; 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci assert(compile_time_consts_data->static_consts.num <= 609bf215546Sopenharmony_ci ARRAY_SIZE(compile_time_consts_data->static_consts.value)); 610bf215546Sopenharmony_ci 611bf215546Sopenharmony_ci /* This is fine since buffers_out_ptr is a pointer to an array. */ 612bf215546Sopenharmony_ci assert(buffer_count < ARRAY_SIZE(*buffers_out_ptr)); 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci /* TODO: Is it possible to have multiple static consts buffer where the 615bf215546Sopenharmony_ci * destination is not adjoining? If so we need to handle that. 616bf215546Sopenharmony_ci * Currently we're only setting up a single buffer. 617bf215546Sopenharmony_ci */ 618bf215546Sopenharmony_ci buffers[buffer_count++] = (struct pvr_pds_buffer){ 619bf215546Sopenharmony_ci .type = PVR_BUFFER_TYPES_COMPILE_TIME, 620bf215546Sopenharmony_ci .size_in_dwords = compile_time_consts_data->static_consts.num, 621bf215546Sopenharmony_ci .destination = compile_time_consts_data->static_consts.dest, 622bf215546Sopenharmony_ci }; 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci result = pvr_gpu_upload(device, 625bf215546Sopenharmony_ci device->heaps.general_heap, 626bf215546Sopenharmony_ci compile_time_consts_data->static_consts.value, 627bf215546Sopenharmony_ci compile_time_consts_data->static_consts.num * 628bf215546Sopenharmony_ci ROGUE_REG_SIZE_BYTES, 629bf215546Sopenharmony_ci ROGUE_REG_SIZE_BYTES, 630bf215546Sopenharmony_ci static_consts_pvr_bo_out); 631bf215546Sopenharmony_ci if (result != VK_SUCCESS) 632bf215546Sopenharmony_ci return result; 633bf215546Sopenharmony_ci } else { 634bf215546Sopenharmony_ci *static_consts_pvr_bo_out = NULL; 635bf215546Sopenharmony_ci } 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci *buffer_count_out = buffer_count; 638bf215546Sopenharmony_ci 639bf215546Sopenharmony_ci return VK_SUCCESS; 640bf215546Sopenharmony_ci} 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_cistatic VkResult pvr_pds_descriptor_program_create_and_upload( 643bf215546Sopenharmony_ci struct pvr_device *const device, 644bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 645bf215546Sopenharmony_ci const struct rogue_compile_time_consts_data *const compile_time_consts_data, 646bf215546Sopenharmony_ci const struct rogue_ubo_data *const ubo_data, 647bf215546Sopenharmony_ci const struct pvr_explicit_constant_usage *const explicit_const_usage, 648bf215546Sopenharmony_ci const struct pvr_pipeline_layout *const layout, 649bf215546Sopenharmony_ci enum pvr_stage_allocation stage, 650bf215546Sopenharmony_ci struct pvr_stage_allocation_descriptor_state *const descriptor_state) 651bf215546Sopenharmony_ci{ 652bf215546Sopenharmony_ci const size_t const_entries_size_in_bytes = 653bf215546Sopenharmony_ci pvr_pds_get_max_descriptor_upload_const_map_size_in_bytes(); 654bf215546Sopenharmony_ci struct pvr_pds_info *const pds_info = &descriptor_state->pds_info; 655bf215546Sopenharmony_ci struct pvr_descriptor_program_input program = { 0 }; 656bf215546Sopenharmony_ci struct pvr_const_map_entry *entries_buffer; 657bf215546Sopenharmony_ci ASSERTED uint32_t code_size_in_dwords; 658bf215546Sopenharmony_ci uint32_t staging_buffer_size; 659bf215546Sopenharmony_ci uint32_t *staging_buffer; 660bf215546Sopenharmony_ci VkResult result; 661bf215546Sopenharmony_ci 662bf215546Sopenharmony_ci assert(stage != PVR_STAGE_ALLOCATION_COUNT); 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_ci *pds_info = (struct pvr_pds_info){ 0 }; 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci result = pvr_pds_descriptor_program_setup_buffers( 667bf215546Sopenharmony_ci device, 668bf215546Sopenharmony_ci device->features.robustBufferAccess, 669bf215546Sopenharmony_ci compile_time_consts_data, 670bf215546Sopenharmony_ci ubo_data, 671bf215546Sopenharmony_ci &program.buffers, 672bf215546Sopenharmony_ci &program.buffer_count, 673bf215546Sopenharmony_ci &descriptor_state->static_consts); 674bf215546Sopenharmony_ci if (result != VK_SUCCESS) 675bf215546Sopenharmony_ci return result; 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci if (layout->per_stage_reg_info[stage].primary_dynamic_size_in_dwords) 678bf215546Sopenharmony_ci assert(!"Unimplemented"); 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_ci for (uint32_t set_num = 0; set_num < layout->set_count; set_num++) { 681bf215546Sopenharmony_ci const struct pvr_descriptor_set_layout_mem_layout *const reg_layout = 682bf215546Sopenharmony_ci &layout->register_layout_in_dwords_per_stage[stage][set_num]; 683bf215546Sopenharmony_ci const uint32_t start_offset = explicit_const_usage->start_offset; 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci /* TODO: Use compiler usage info to optimize this? */ 686bf215546Sopenharmony_ci 687bf215546Sopenharmony_ci /* Only dma primaries if they are actually required. */ 688bf215546Sopenharmony_ci if (reg_layout->primary_size) { 689bf215546Sopenharmony_ci program.descriptor_sets[program.descriptor_set_count++] = 690bf215546Sopenharmony_ci (struct pvr_pds_descriptor_set){ 691bf215546Sopenharmony_ci .descriptor_set = set_num, 692bf215546Sopenharmony_ci .size_in_dwords = reg_layout->primary_size, 693bf215546Sopenharmony_ci .destination = reg_layout->primary_offset + start_offset, 694bf215546Sopenharmony_ci .primary = true, 695bf215546Sopenharmony_ci }; 696bf215546Sopenharmony_ci } 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_ci /* Only dma secondaries if they are actually required. */ 699bf215546Sopenharmony_ci if (!reg_layout->secondary_size) 700bf215546Sopenharmony_ci continue; 701bf215546Sopenharmony_ci 702bf215546Sopenharmony_ci program.descriptor_sets[program.descriptor_set_count++] = 703bf215546Sopenharmony_ci (struct pvr_pds_descriptor_set){ 704bf215546Sopenharmony_ci .descriptor_set = set_num, 705bf215546Sopenharmony_ci .size_in_dwords = reg_layout->secondary_size, 706bf215546Sopenharmony_ci .destination = reg_layout->secondary_offset + start_offset, 707bf215546Sopenharmony_ci }; 708bf215546Sopenharmony_ci } 709bf215546Sopenharmony_ci 710bf215546Sopenharmony_ci entries_buffer = vk_alloc2(&device->vk.alloc, 711bf215546Sopenharmony_ci allocator, 712bf215546Sopenharmony_ci const_entries_size_in_bytes, 713bf215546Sopenharmony_ci 8, 714bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 715bf215546Sopenharmony_ci if (!entries_buffer) { 716bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->static_consts); 717bf215546Sopenharmony_ci 718bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 719bf215546Sopenharmony_ci } 720bf215546Sopenharmony_ci 721bf215546Sopenharmony_ci pds_info->entries = entries_buffer; 722bf215546Sopenharmony_ci pds_info->entries_size_in_bytes = const_entries_size_in_bytes; 723bf215546Sopenharmony_ci 724bf215546Sopenharmony_ci pvr_pds_generate_descriptor_upload_program(&program, NULL, pds_info); 725bf215546Sopenharmony_ci 726bf215546Sopenharmony_ci code_size_in_dwords = pds_info->code_size_in_dwords; 727bf215546Sopenharmony_ci staging_buffer_size = 728bf215546Sopenharmony_ci pds_info->code_size_in_dwords * sizeof(*staging_buffer); 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_ci if (!staging_buffer_size) { 731bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, entries_buffer); 732bf215546Sopenharmony_ci 733bf215546Sopenharmony_ci *descriptor_state = (struct pvr_stage_allocation_descriptor_state){ 0 }; 734bf215546Sopenharmony_ci 735bf215546Sopenharmony_ci return VK_SUCCESS; 736bf215546Sopenharmony_ci } 737bf215546Sopenharmony_ci 738bf215546Sopenharmony_ci staging_buffer = vk_alloc2(&device->vk.alloc, 739bf215546Sopenharmony_ci allocator, 740bf215546Sopenharmony_ci staging_buffer_size, 741bf215546Sopenharmony_ci 8, 742bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 743bf215546Sopenharmony_ci if (!staging_buffer) { 744bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->static_consts); 745bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, entries_buffer); 746bf215546Sopenharmony_ci 747bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 748bf215546Sopenharmony_ci } 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci pvr_pds_generate_descriptor_upload_program(&program, 751bf215546Sopenharmony_ci staging_buffer, 752bf215546Sopenharmony_ci pds_info); 753bf215546Sopenharmony_ci 754bf215546Sopenharmony_ci assert(pds_info->code_size_in_dwords <= code_size_in_dwords); 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci /* FIXME: use vk_realloc2() ? */ 757bf215546Sopenharmony_ci entries_buffer = vk_realloc((!allocator) ? &device->vk.alloc : allocator, 758bf215546Sopenharmony_ci entries_buffer, 759bf215546Sopenharmony_ci pds_info->entries_written_size_in_bytes, 760bf215546Sopenharmony_ci 8, 761bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 762bf215546Sopenharmony_ci if (!entries_buffer) { 763bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->static_consts); 764bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 765bf215546Sopenharmony_ci 766bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 767bf215546Sopenharmony_ci } 768bf215546Sopenharmony_ci 769bf215546Sopenharmony_ci pds_info->entries = entries_buffer; 770bf215546Sopenharmony_ci pds_info->entries_size_in_bytes = pds_info->entries_written_size_in_bytes; 771bf215546Sopenharmony_ci 772bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 773bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 774bf215546Sopenharmony_ci NULL, 775bf215546Sopenharmony_ci 0, 776bf215546Sopenharmony_ci 0, 777bf215546Sopenharmony_ci staging_buffer, 778bf215546Sopenharmony_ci pds_info->code_size_in_dwords, 779bf215546Sopenharmony_ci 16, 780bf215546Sopenharmony_ci 16, 781bf215546Sopenharmony_ci &descriptor_state->pds_code); 782bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 783bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->static_consts); 784bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, entries_buffer); 785bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 786bf215546Sopenharmony_ci 787bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 788bf215546Sopenharmony_ci } 789bf215546Sopenharmony_ci 790bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 791bf215546Sopenharmony_ci 792bf215546Sopenharmony_ci return VK_SUCCESS; 793bf215546Sopenharmony_ci} 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_cistatic void pvr_pds_descriptor_program_destroy( 796bf215546Sopenharmony_ci struct pvr_device *const device, 797bf215546Sopenharmony_ci const struct VkAllocationCallbacks *const allocator, 798bf215546Sopenharmony_ci struct pvr_stage_allocation_descriptor_state *const descriptor_state) 799bf215546Sopenharmony_ci{ 800bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->pds_code.pvr_bo); 801bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, descriptor_state->pds_info.entries); 802bf215546Sopenharmony_ci pvr_bo_free(device, descriptor_state->static_consts); 803bf215546Sopenharmony_ci} 804bf215546Sopenharmony_ci 805bf215546Sopenharmony_cistatic void pvr_pds_compute_program_setup( 806bf215546Sopenharmony_ci const struct pvr_device_info *dev_info, 807bf215546Sopenharmony_ci const uint32_t local_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 808bf215546Sopenharmony_ci const uint32_t work_group_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 809bf215546Sopenharmony_ci uint32_t barrier_coefficient, 810bf215546Sopenharmony_ci bool add_base_workgroup, 811bf215546Sopenharmony_ci uint32_t usc_temps, 812bf215546Sopenharmony_ci pvr_dev_addr_t usc_shader_dev_addr, 813bf215546Sopenharmony_ci struct pvr_pds_compute_shader_program *const program) 814bf215546Sopenharmony_ci{ 815bf215546Sopenharmony_ci *program = (struct pvr_pds_compute_shader_program){ 816bf215546Sopenharmony_ci /* clang-format off */ 817bf215546Sopenharmony_ci .local_input_regs = { 818bf215546Sopenharmony_ci local_input_regs[0], 819bf215546Sopenharmony_ci local_input_regs[1], 820bf215546Sopenharmony_ci local_input_regs[2] 821bf215546Sopenharmony_ci }, 822bf215546Sopenharmony_ci .work_group_input_regs = { 823bf215546Sopenharmony_ci work_group_input_regs[0], 824bf215546Sopenharmony_ci work_group_input_regs[1], 825bf215546Sopenharmony_ci work_group_input_regs[2] 826bf215546Sopenharmony_ci }, 827bf215546Sopenharmony_ci .global_input_regs = { 828bf215546Sopenharmony_ci [0 ... (PVR_WORKGROUP_DIMENSIONS - 1)] = 829bf215546Sopenharmony_ci PVR_PDS_COMPUTE_INPUT_REG_UNUSED 830bf215546Sopenharmony_ci }, 831bf215546Sopenharmony_ci /* clang-format on */ 832bf215546Sopenharmony_ci .barrier_coefficient = barrier_coefficient, 833bf215546Sopenharmony_ci .flattened_work_groups = true, 834bf215546Sopenharmony_ci .clear_pds_barrier = false, 835bf215546Sopenharmony_ci .add_base_workgroup = add_base_workgroup, 836bf215546Sopenharmony_ci .kick_usc = true, 837bf215546Sopenharmony_ci }; 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(program->local_input_regs) == 840bf215546Sopenharmony_ci PVR_WORKGROUP_DIMENSIONS); 841bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(program->work_group_input_regs) == 842bf215546Sopenharmony_ci PVR_WORKGROUP_DIMENSIONS); 843bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(program->global_input_regs) == 844bf215546Sopenharmony_ci PVR_WORKGROUP_DIMENSIONS); 845bf215546Sopenharmony_ci 846bf215546Sopenharmony_ci pvr_pds_setup_doutu(&program->usc_task_control, 847bf215546Sopenharmony_ci usc_shader_dev_addr.addr, 848bf215546Sopenharmony_ci usc_temps, 849bf215546Sopenharmony_ci PVRX(PDSINST_DOUTU_SAMPLE_RATE_INSTANCE), 850bf215546Sopenharmony_ci false); 851bf215546Sopenharmony_ci 852bf215546Sopenharmony_ci pvr_pds_compute_shader(program, NULL, PDS_GENERATE_SIZES, dev_info); 853bf215546Sopenharmony_ci} 854bf215546Sopenharmony_ci 855bf215546Sopenharmony_ci/* FIXME: See if pvr_device_init_compute_pds_program() and this could be merged. 856bf215546Sopenharmony_ci */ 857bf215546Sopenharmony_cistatic VkResult pvr_pds_compute_program_create_and_upload( 858bf215546Sopenharmony_ci struct pvr_device *const device, 859bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 860bf215546Sopenharmony_ci const uint32_t local_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 861bf215546Sopenharmony_ci const uint32_t work_group_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 862bf215546Sopenharmony_ci uint32_t barrier_coefficient, 863bf215546Sopenharmony_ci uint32_t usc_temps, 864bf215546Sopenharmony_ci pvr_dev_addr_t usc_shader_dev_addr, 865bf215546Sopenharmony_ci struct pvr_pds_upload *const pds_upload_out, 866bf215546Sopenharmony_ci struct pvr_pds_info *const pds_info_out) 867bf215546Sopenharmony_ci{ 868bf215546Sopenharmony_ci struct pvr_device_info *dev_info = &device->pdevice->dev_info; 869bf215546Sopenharmony_ci struct pvr_pds_compute_shader_program program; 870bf215546Sopenharmony_ci uint32_t staging_buffer_size; 871bf215546Sopenharmony_ci uint32_t *staging_buffer; 872bf215546Sopenharmony_ci VkResult result; 873bf215546Sopenharmony_ci 874bf215546Sopenharmony_ci pvr_pds_compute_program_setup(dev_info, 875bf215546Sopenharmony_ci local_input_regs, 876bf215546Sopenharmony_ci work_group_input_regs, 877bf215546Sopenharmony_ci barrier_coefficient, 878bf215546Sopenharmony_ci false, 879bf215546Sopenharmony_ci usc_temps, 880bf215546Sopenharmony_ci usc_shader_dev_addr, 881bf215546Sopenharmony_ci &program); 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci /* FIXME: According to pvr_device_init_compute_pds_program() the code size 884bf215546Sopenharmony_ci * is in bytes. Investigate this. 885bf215546Sopenharmony_ci */ 886bf215546Sopenharmony_ci staging_buffer_size = 887bf215546Sopenharmony_ci (program.code_size + program.data_size) * sizeof(*staging_buffer); 888bf215546Sopenharmony_ci 889bf215546Sopenharmony_ci staging_buffer = vk_alloc2(&device->vk.alloc, 890bf215546Sopenharmony_ci allocator, 891bf215546Sopenharmony_ci staging_buffer_size, 892bf215546Sopenharmony_ci 8, 893bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); 894bf215546Sopenharmony_ci if (!staging_buffer) 895bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 896bf215546Sopenharmony_ci 897bf215546Sopenharmony_ci /* FIXME: pvr_pds_compute_shader doesn't implement 898bf215546Sopenharmony_ci * PDS_GENERATE_CODEDATA_SEGMENTS. 899bf215546Sopenharmony_ci */ 900bf215546Sopenharmony_ci pvr_pds_compute_shader(&program, 901bf215546Sopenharmony_ci &staging_buffer[0], 902bf215546Sopenharmony_ci PDS_GENERATE_CODE_SEGMENT, 903bf215546Sopenharmony_ci dev_info); 904bf215546Sopenharmony_ci 905bf215546Sopenharmony_ci pvr_pds_compute_shader(&program, 906bf215546Sopenharmony_ci &staging_buffer[program.code_size], 907bf215546Sopenharmony_ci PDS_GENERATE_DATA_SEGMENT, 908bf215546Sopenharmony_ci dev_info); 909bf215546Sopenharmony_ci 910bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 911bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 912bf215546Sopenharmony_ci &staging_buffer[program.code_size], 913bf215546Sopenharmony_ci program.data_size, 914bf215546Sopenharmony_ci 16, 915bf215546Sopenharmony_ci &staging_buffer[0], 916bf215546Sopenharmony_ci program.code_size, 917bf215546Sopenharmony_ci 16, 918bf215546Sopenharmony_ci 16, 919bf215546Sopenharmony_ci pds_upload_out); 920bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 921bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 922bf215546Sopenharmony_ci return result; 923bf215546Sopenharmony_ci } 924bf215546Sopenharmony_ci 925bf215546Sopenharmony_ci *pds_info_out = (struct pvr_pds_info){ 926bf215546Sopenharmony_ci .temps_required = program.highest_temp, 927bf215546Sopenharmony_ci .code_size_in_dwords = program.code_size, 928bf215546Sopenharmony_ci .data_size_in_dwords = program.data_size, 929bf215546Sopenharmony_ci }; 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, staging_buffer); 932bf215546Sopenharmony_ci 933bf215546Sopenharmony_ci return VK_SUCCESS; 934bf215546Sopenharmony_ci}; 935bf215546Sopenharmony_ci 936bf215546Sopenharmony_cistatic void pvr_pds_compute_program_destroy( 937bf215546Sopenharmony_ci struct pvr_device *const device, 938bf215546Sopenharmony_ci const struct VkAllocationCallbacks *const allocator, 939bf215546Sopenharmony_ci struct pvr_pds_upload *const pds_program, 940bf215546Sopenharmony_ci struct pvr_pds_info *const pds_info) 941bf215546Sopenharmony_ci{ 942bf215546Sopenharmony_ci /* We don't allocate an entries buffer so we don't need to free it */ 943bf215546Sopenharmony_ci pvr_bo_free(device, pds_program->pvr_bo); 944bf215546Sopenharmony_ci} 945bf215546Sopenharmony_ci 946bf215546Sopenharmony_ci/* This only uploads the code segment. The data segment will need to be patched 947bf215546Sopenharmony_ci * with the base workgroup before uploading. 948bf215546Sopenharmony_ci */ 949bf215546Sopenharmony_cistatic VkResult pvr_pds_compute_base_workgroup_variant_program_init( 950bf215546Sopenharmony_ci struct pvr_device *const device, 951bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 952bf215546Sopenharmony_ci const uint32_t local_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 953bf215546Sopenharmony_ci const uint32_t work_group_input_regs[static const PVR_WORKGROUP_DIMENSIONS], 954bf215546Sopenharmony_ci uint32_t barrier_coefficient, 955bf215546Sopenharmony_ci uint32_t usc_temps, 956bf215546Sopenharmony_ci pvr_dev_addr_t usc_shader_dev_addr, 957bf215546Sopenharmony_ci struct pvr_pds_base_workgroup_program *program_out) 958bf215546Sopenharmony_ci{ 959bf215546Sopenharmony_ci struct pvr_device_info *dev_info = &device->pdevice->dev_info; 960bf215546Sopenharmony_ci struct pvr_pds_compute_shader_program program; 961bf215546Sopenharmony_ci uint32_t buffer_size; 962bf215546Sopenharmony_ci uint32_t *buffer; 963bf215546Sopenharmony_ci VkResult result; 964bf215546Sopenharmony_ci 965bf215546Sopenharmony_ci pvr_pds_compute_program_setup(dev_info, 966bf215546Sopenharmony_ci local_input_regs, 967bf215546Sopenharmony_ci work_group_input_regs, 968bf215546Sopenharmony_ci barrier_coefficient, 969bf215546Sopenharmony_ci true, 970bf215546Sopenharmony_ci usc_temps, 971bf215546Sopenharmony_ci usc_shader_dev_addr, 972bf215546Sopenharmony_ci &program); 973bf215546Sopenharmony_ci 974bf215546Sopenharmony_ci /* FIXME: According to pvr_device_init_compute_pds_program() the code size 975bf215546Sopenharmony_ci * is in bytes. Investigate this. 976bf215546Sopenharmony_ci */ 977bf215546Sopenharmony_ci buffer_size = MAX2(program.code_size, program.data_size) * sizeof(*buffer); 978bf215546Sopenharmony_ci 979bf215546Sopenharmony_ci buffer = vk_alloc2(&device->vk.alloc, 980bf215546Sopenharmony_ci allocator, 981bf215546Sopenharmony_ci buffer_size, 982bf215546Sopenharmony_ci 8, 983bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 984bf215546Sopenharmony_ci if (!buffer) 985bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 986bf215546Sopenharmony_ci 987bf215546Sopenharmony_ci pvr_pds_compute_shader(&program, 988bf215546Sopenharmony_ci &buffer[0], 989bf215546Sopenharmony_ci PDS_GENERATE_CODE_SEGMENT, 990bf215546Sopenharmony_ci dev_info); 991bf215546Sopenharmony_ci 992bf215546Sopenharmony_ci /* FIXME: Figure out the define for alignment of 16. */ 993bf215546Sopenharmony_ci result = pvr_gpu_upload_pds(device, 994bf215546Sopenharmony_ci NULL, 995bf215546Sopenharmony_ci 0, 996bf215546Sopenharmony_ci 0, 997bf215546Sopenharmony_ci buffer, 998bf215546Sopenharmony_ci program.code_size, 999bf215546Sopenharmony_ci 16, 1000bf215546Sopenharmony_ci 16, 1001bf215546Sopenharmony_ci &program_out->code_upload); 1002bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1003bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, buffer); 1004bf215546Sopenharmony_ci return result; 1005bf215546Sopenharmony_ci } 1006bf215546Sopenharmony_ci 1007bf215546Sopenharmony_ci pvr_pds_compute_shader(&program, buffer, PDS_GENERATE_DATA_SEGMENT, dev_info); 1008bf215546Sopenharmony_ci 1009bf215546Sopenharmony_ci program_out->data_section = buffer; 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci /* We'll need to patch the base workgroup in the PDS data section before 1012bf215546Sopenharmony_ci * dispatch so we save the offsets at which to patch. We only need to save 1013bf215546Sopenharmony_ci * the offset for the first workgroup id since the workgroup ids are stored 1014bf215546Sopenharmony_ci * contiguously in the data segment. 1015bf215546Sopenharmony_ci */ 1016bf215546Sopenharmony_ci program_out->base_workgroup_data_patching_offset = 1017bf215546Sopenharmony_ci program.base_workgroup_constant_offset_in_dwords[0]; 1018bf215546Sopenharmony_ci 1019bf215546Sopenharmony_ci program_out->info = (struct pvr_pds_info){ 1020bf215546Sopenharmony_ci .temps_required = program.highest_temp, 1021bf215546Sopenharmony_ci .code_size_in_dwords = program.code_size, 1022bf215546Sopenharmony_ci .data_size_in_dwords = program.data_size, 1023bf215546Sopenharmony_ci }; 1024bf215546Sopenharmony_ci 1025bf215546Sopenharmony_ci return VK_SUCCESS; 1026bf215546Sopenharmony_ci} 1027bf215546Sopenharmony_ci 1028bf215546Sopenharmony_cistatic void pvr_pds_compute_base_workgroup_variant_program_finish( 1029bf215546Sopenharmony_ci struct pvr_device *device, 1030bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 1031bf215546Sopenharmony_ci struct pvr_pds_base_workgroup_program *const state) 1032bf215546Sopenharmony_ci{ 1033bf215546Sopenharmony_ci pvr_bo_free(device, state->code_upload.pvr_bo); 1034bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, state->data_section); 1035bf215546Sopenharmony_ci} 1036bf215546Sopenharmony_ci 1037bf215546Sopenharmony_ci/****************************************************************************** 1038bf215546Sopenharmony_ci Generic pipeline functions 1039bf215546Sopenharmony_ci ******************************************************************************/ 1040bf215546Sopenharmony_ci 1041bf215546Sopenharmony_cistatic void pvr_pipeline_init(struct pvr_device *device, 1042bf215546Sopenharmony_ci enum pvr_pipeline_type type, 1043bf215546Sopenharmony_ci struct pvr_pipeline *const pipeline) 1044bf215546Sopenharmony_ci{ 1045bf215546Sopenharmony_ci assert(!pipeline->layout); 1046bf215546Sopenharmony_ci 1047bf215546Sopenharmony_ci vk_object_base_init(&device->vk, &pipeline->base, VK_OBJECT_TYPE_PIPELINE); 1048bf215546Sopenharmony_ci 1049bf215546Sopenharmony_ci pipeline->type = type; 1050bf215546Sopenharmony_ci} 1051bf215546Sopenharmony_ci 1052bf215546Sopenharmony_cistatic void pvr_pipeline_finish(struct pvr_pipeline *pipeline) 1053bf215546Sopenharmony_ci{ 1054bf215546Sopenharmony_ci vk_object_base_finish(&pipeline->base); 1055bf215546Sopenharmony_ci} 1056bf215546Sopenharmony_ci 1057bf215546Sopenharmony_ci/****************************************************************************** 1058bf215546Sopenharmony_ci Compute pipeline functions 1059bf215546Sopenharmony_ci ******************************************************************************/ 1060bf215546Sopenharmony_ci 1061bf215546Sopenharmony_ci/* Compiles and uploads shaders and PDS programs. */ 1062bf215546Sopenharmony_cistatic VkResult pvr_compute_pipeline_compile( 1063bf215546Sopenharmony_ci struct pvr_device *const device, 1064bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1065bf215546Sopenharmony_ci const VkComputePipelineCreateInfo *pCreateInfo, 1066bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 1067bf215546Sopenharmony_ci struct pvr_compute_pipeline *const compute_pipeline) 1068bf215546Sopenharmony_ci{ 1069bf215546Sopenharmony_ci struct rogue_compile_time_consts_data compile_time_consts_data; 1070bf215546Sopenharmony_ci uint32_t work_group_input_regs[PVR_WORKGROUP_DIMENSIONS]; 1071bf215546Sopenharmony_ci struct pvr_explicit_constant_usage explicit_const_usage; 1072bf215546Sopenharmony_ci uint32_t local_input_regs[PVR_WORKGROUP_DIMENSIONS]; 1073bf215546Sopenharmony_ci struct rogue_ubo_data ubo_data; 1074bf215546Sopenharmony_ci uint32_t barrier_coefficient; 1075bf215546Sopenharmony_ci uint32_t usc_temps; 1076bf215546Sopenharmony_ci VkResult result; 1077bf215546Sopenharmony_ci 1078bf215546Sopenharmony_ci if (pvr_hard_code_shader_required(&device->pdevice->dev_info)) { 1079bf215546Sopenharmony_ci struct pvr_hard_code_compute_build_info build_info; 1080bf215546Sopenharmony_ci 1081bf215546Sopenharmony_ci result = pvr_hard_code_compute_pipeline(device, 1082bf215546Sopenharmony_ci &compute_pipeline->state.shader, 1083bf215546Sopenharmony_ci &build_info); 1084bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1085bf215546Sopenharmony_ci return result; 1086bf215546Sopenharmony_ci 1087bf215546Sopenharmony_ci ubo_data = build_info.ubo_data; 1088bf215546Sopenharmony_ci compile_time_consts_data = build_info.compile_time_consts_data; 1089bf215546Sopenharmony_ci 1090bf215546Sopenharmony_ci /* We make sure that the compiler's unused reg value is compatible with 1091bf215546Sopenharmony_ci * the pds api. 1092bf215546Sopenharmony_ci */ 1093bf215546Sopenharmony_ci STATIC_ASSERT(ROGUE_REG_UNUSED == PVR_PDS_COMPUTE_INPUT_REG_UNUSED); 1094bf215546Sopenharmony_ci 1095bf215546Sopenharmony_ci barrier_coefficient = build_info.barrier_reg; 1096bf215546Sopenharmony_ci 1097bf215546Sopenharmony_ci /* TODO: Maybe change the pds api to use pointers so we avoid the copy. */ 1098bf215546Sopenharmony_ci local_input_regs[0] = build_info.local_invocation_regs[0]; 1099bf215546Sopenharmony_ci local_input_regs[1] = build_info.local_invocation_regs[1]; 1100bf215546Sopenharmony_ci /* This is not a mistake. We want to assign element 1 to 2. */ 1101bf215546Sopenharmony_ci local_input_regs[2] = build_info.local_invocation_regs[1]; 1102bf215546Sopenharmony_ci 1103bf215546Sopenharmony_ci STATIC_ASSERT( 1104bf215546Sopenharmony_ci __same_type(work_group_input_regs, build_info.work_group_regs)); 1105bf215546Sopenharmony_ci typed_memcpy(work_group_input_regs, 1106bf215546Sopenharmony_ci build_info.work_group_regs, 1107bf215546Sopenharmony_ci PVR_WORKGROUP_DIMENSIONS); 1108bf215546Sopenharmony_ci 1109bf215546Sopenharmony_ci usc_temps = build_info.usc_temps; 1110bf215546Sopenharmony_ci 1111bf215546Sopenharmony_ci explicit_const_usage = build_info.explicit_conts_usage; 1112bf215546Sopenharmony_ci 1113bf215546Sopenharmony_ci } else { 1114bf215546Sopenharmony_ci /* FIXME: Compile and upload the shader. */ 1115bf215546Sopenharmony_ci /* FIXME: Initialize the shader state and setup build info. */ 1116bf215546Sopenharmony_ci abort(); 1117bf215546Sopenharmony_ci }; 1118bf215546Sopenharmony_ci 1119bf215546Sopenharmony_ci result = pvr_pds_descriptor_program_create_and_upload( 1120bf215546Sopenharmony_ci device, 1121bf215546Sopenharmony_ci allocator, 1122bf215546Sopenharmony_ci &compile_time_consts_data, 1123bf215546Sopenharmony_ci &ubo_data, 1124bf215546Sopenharmony_ci &explicit_const_usage, 1125bf215546Sopenharmony_ci compute_pipeline->base.layout, 1126bf215546Sopenharmony_ci PVR_STAGE_ALLOCATION_COMPUTE, 1127bf215546Sopenharmony_ci &compute_pipeline->state.descriptor); 1128bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1129bf215546Sopenharmony_ci goto err_free_shader; 1130bf215546Sopenharmony_ci 1131bf215546Sopenharmony_ci result = pvr_pds_compute_program_create_and_upload( 1132bf215546Sopenharmony_ci device, 1133bf215546Sopenharmony_ci allocator, 1134bf215546Sopenharmony_ci local_input_regs, 1135bf215546Sopenharmony_ci work_group_input_regs, 1136bf215546Sopenharmony_ci barrier_coefficient, 1137bf215546Sopenharmony_ci usc_temps, 1138bf215546Sopenharmony_ci compute_pipeline->state.shader.bo->vma->dev_addr, 1139bf215546Sopenharmony_ci &compute_pipeline->state.primary_program, 1140bf215546Sopenharmony_ci &compute_pipeline->state.primary_program_info); 1141bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1142bf215546Sopenharmony_ci goto err_free_descriptor_program; 1143bf215546Sopenharmony_ci 1144bf215546Sopenharmony_ci /* If the workgroup ID is required, then we require the base workgroup 1145bf215546Sopenharmony_ci * variant of the PDS compute program as well. 1146bf215546Sopenharmony_ci */ 1147bf215546Sopenharmony_ci compute_pipeline->state.flags.base_workgroup = 1148bf215546Sopenharmony_ci work_group_input_regs[0] != PVR_PDS_COMPUTE_INPUT_REG_UNUSED || 1149bf215546Sopenharmony_ci work_group_input_regs[1] != PVR_PDS_COMPUTE_INPUT_REG_UNUSED || 1150bf215546Sopenharmony_ci work_group_input_regs[2] != PVR_PDS_COMPUTE_INPUT_REG_UNUSED; 1151bf215546Sopenharmony_ci 1152bf215546Sopenharmony_ci if (compute_pipeline->state.flags.base_workgroup) { 1153bf215546Sopenharmony_ci result = pvr_pds_compute_base_workgroup_variant_program_init( 1154bf215546Sopenharmony_ci device, 1155bf215546Sopenharmony_ci allocator, 1156bf215546Sopenharmony_ci local_input_regs, 1157bf215546Sopenharmony_ci work_group_input_regs, 1158bf215546Sopenharmony_ci barrier_coefficient, 1159bf215546Sopenharmony_ci usc_temps, 1160bf215546Sopenharmony_ci compute_pipeline->state.shader.bo->vma->dev_addr, 1161bf215546Sopenharmony_ci &compute_pipeline->state.primary_base_workgroup_variant_program); 1162bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1163bf215546Sopenharmony_ci goto err_destroy_compute_program; 1164bf215546Sopenharmony_ci } 1165bf215546Sopenharmony_ci 1166bf215546Sopenharmony_ci return VK_SUCCESS; 1167bf215546Sopenharmony_ci 1168bf215546Sopenharmony_cierr_destroy_compute_program: 1169bf215546Sopenharmony_ci pvr_pds_compute_program_destroy( 1170bf215546Sopenharmony_ci device, 1171bf215546Sopenharmony_ci allocator, 1172bf215546Sopenharmony_ci &compute_pipeline->state.primary_program, 1173bf215546Sopenharmony_ci &compute_pipeline->state.primary_program_info); 1174bf215546Sopenharmony_ci 1175bf215546Sopenharmony_cierr_free_descriptor_program: 1176bf215546Sopenharmony_ci pvr_bo_free(device, compute_pipeline->state.descriptor.pds_code.pvr_bo); 1177bf215546Sopenharmony_ci 1178bf215546Sopenharmony_cierr_free_shader: 1179bf215546Sopenharmony_ci pvr_bo_free(device, compute_pipeline->state.shader.bo); 1180bf215546Sopenharmony_ci 1181bf215546Sopenharmony_ci return result; 1182bf215546Sopenharmony_ci} 1183bf215546Sopenharmony_ci 1184bf215546Sopenharmony_cistatic VkResult 1185bf215546Sopenharmony_cipvr_compute_pipeline_init(struct pvr_device *device, 1186bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1187bf215546Sopenharmony_ci const VkComputePipelineCreateInfo *pCreateInfo, 1188bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 1189bf215546Sopenharmony_ci struct pvr_compute_pipeline *compute_pipeline) 1190bf215546Sopenharmony_ci{ 1191bf215546Sopenharmony_ci VkResult result; 1192bf215546Sopenharmony_ci 1193bf215546Sopenharmony_ci pvr_pipeline_init(device, 1194bf215546Sopenharmony_ci PVR_PIPELINE_TYPE_COMPUTE, 1195bf215546Sopenharmony_ci &compute_pipeline->base); 1196bf215546Sopenharmony_ci 1197bf215546Sopenharmony_ci compute_pipeline->base.layout = 1198bf215546Sopenharmony_ci pvr_pipeline_layout_from_handle(pCreateInfo->layout); 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci result = pvr_compute_pipeline_compile(device, 1201bf215546Sopenharmony_ci pipeline_cache, 1202bf215546Sopenharmony_ci pCreateInfo, 1203bf215546Sopenharmony_ci allocator, 1204bf215546Sopenharmony_ci compute_pipeline); 1205bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1206bf215546Sopenharmony_ci pvr_pipeline_finish(&compute_pipeline->base); 1207bf215546Sopenharmony_ci return result; 1208bf215546Sopenharmony_ci } 1209bf215546Sopenharmony_ci 1210bf215546Sopenharmony_ci return VK_SUCCESS; 1211bf215546Sopenharmony_ci} 1212bf215546Sopenharmony_ci 1213bf215546Sopenharmony_cistatic VkResult 1214bf215546Sopenharmony_cipvr_compute_pipeline_create(struct pvr_device *device, 1215bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1216bf215546Sopenharmony_ci const VkComputePipelineCreateInfo *pCreateInfo, 1217bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 1218bf215546Sopenharmony_ci VkPipeline *const pipeline_out) 1219bf215546Sopenharmony_ci{ 1220bf215546Sopenharmony_ci struct pvr_compute_pipeline *compute_pipeline; 1221bf215546Sopenharmony_ci VkResult result; 1222bf215546Sopenharmony_ci 1223bf215546Sopenharmony_ci compute_pipeline = vk_zalloc2(&device->vk.alloc, 1224bf215546Sopenharmony_ci allocator, 1225bf215546Sopenharmony_ci sizeof(*compute_pipeline), 1226bf215546Sopenharmony_ci 8, 1227bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 1228bf215546Sopenharmony_ci if (!compute_pipeline) 1229bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1230bf215546Sopenharmony_ci 1231bf215546Sopenharmony_ci /* Compiles and uploads shaders and PDS programs. */ 1232bf215546Sopenharmony_ci result = pvr_compute_pipeline_init(device, 1233bf215546Sopenharmony_ci pipeline_cache, 1234bf215546Sopenharmony_ci pCreateInfo, 1235bf215546Sopenharmony_ci allocator, 1236bf215546Sopenharmony_ci compute_pipeline); 1237bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1238bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, compute_pipeline); 1239bf215546Sopenharmony_ci return result; 1240bf215546Sopenharmony_ci } 1241bf215546Sopenharmony_ci 1242bf215546Sopenharmony_ci *pipeline_out = pvr_pipeline_to_handle(&compute_pipeline->base); 1243bf215546Sopenharmony_ci 1244bf215546Sopenharmony_ci return VK_SUCCESS; 1245bf215546Sopenharmony_ci} 1246bf215546Sopenharmony_ci 1247bf215546Sopenharmony_cistatic void pvr_compute_pipeline_destroy( 1248bf215546Sopenharmony_ci struct pvr_device *const device, 1249bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 1250bf215546Sopenharmony_ci struct pvr_compute_pipeline *const compute_pipeline) 1251bf215546Sopenharmony_ci{ 1252bf215546Sopenharmony_ci if (compute_pipeline->state.flags.base_workgroup) { 1253bf215546Sopenharmony_ci pvr_pds_compute_base_workgroup_variant_program_finish( 1254bf215546Sopenharmony_ci device, 1255bf215546Sopenharmony_ci allocator, 1256bf215546Sopenharmony_ci &compute_pipeline->state.primary_base_workgroup_variant_program); 1257bf215546Sopenharmony_ci } 1258bf215546Sopenharmony_ci 1259bf215546Sopenharmony_ci pvr_pds_compute_program_destroy( 1260bf215546Sopenharmony_ci device, 1261bf215546Sopenharmony_ci allocator, 1262bf215546Sopenharmony_ci &compute_pipeline->state.primary_program, 1263bf215546Sopenharmony_ci &compute_pipeline->state.primary_program_info); 1264bf215546Sopenharmony_ci pvr_pds_descriptor_program_destroy(device, 1265bf215546Sopenharmony_ci allocator, 1266bf215546Sopenharmony_ci &compute_pipeline->state.descriptor); 1267bf215546Sopenharmony_ci pvr_bo_free(device, compute_pipeline->state.shader.bo); 1268bf215546Sopenharmony_ci 1269bf215546Sopenharmony_ci pvr_pipeline_finish(&compute_pipeline->base); 1270bf215546Sopenharmony_ci 1271bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, compute_pipeline); 1272bf215546Sopenharmony_ci} 1273bf215546Sopenharmony_ci 1274bf215546Sopenharmony_ciVkResult 1275bf215546Sopenharmony_cipvr_CreateComputePipelines(VkDevice _device, 1276bf215546Sopenharmony_ci VkPipelineCache pipelineCache, 1277bf215546Sopenharmony_ci uint32_t createInfoCount, 1278bf215546Sopenharmony_ci const VkComputePipelineCreateInfo *pCreateInfos, 1279bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator, 1280bf215546Sopenharmony_ci VkPipeline *pPipelines) 1281bf215546Sopenharmony_ci{ 1282bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_pipeline_cache, pipeline_cache, pipelineCache); 1283bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_device, device, _device); 1284bf215546Sopenharmony_ci VkResult result = VK_SUCCESS; 1285bf215546Sopenharmony_ci 1286bf215546Sopenharmony_ci for (uint32_t i = 0; i < createInfoCount; i++) { 1287bf215546Sopenharmony_ci const VkResult local_result = 1288bf215546Sopenharmony_ci pvr_compute_pipeline_create(device, 1289bf215546Sopenharmony_ci pipeline_cache, 1290bf215546Sopenharmony_ci &pCreateInfos[i], 1291bf215546Sopenharmony_ci pAllocator, 1292bf215546Sopenharmony_ci &pPipelines[i]); 1293bf215546Sopenharmony_ci if (local_result != VK_SUCCESS) { 1294bf215546Sopenharmony_ci result = local_result; 1295bf215546Sopenharmony_ci pPipelines[i] = VK_NULL_HANDLE; 1296bf215546Sopenharmony_ci } 1297bf215546Sopenharmony_ci } 1298bf215546Sopenharmony_ci 1299bf215546Sopenharmony_ci return result; 1300bf215546Sopenharmony_ci} 1301bf215546Sopenharmony_ci 1302bf215546Sopenharmony_ci/****************************************************************************** 1303bf215546Sopenharmony_ci Graphics pipeline functions 1304bf215546Sopenharmony_ci ******************************************************************************/ 1305bf215546Sopenharmony_ci 1306bf215546Sopenharmony_cistatic inline uint32_t pvr_dynamic_state_bit_from_vk(VkDynamicState state) 1307bf215546Sopenharmony_ci{ 1308bf215546Sopenharmony_ci switch (state) { 1309bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_VIEWPORT: 1310bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_VIEWPORT; 1311bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_SCISSOR: 1312bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_SCISSOR; 1313bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_LINE_WIDTH: 1314bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_LINE_WIDTH; 1315bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_DEPTH_BIAS: 1316bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_DEPTH_BIAS; 1317bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_BLEND_CONSTANTS: 1318bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_BLEND_CONSTANTS; 1319bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: 1320bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_STENCIL_COMPARE_MASK; 1321bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK: 1322bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_STENCIL_WRITE_MASK; 1323bf215546Sopenharmony_ci case VK_DYNAMIC_STATE_STENCIL_REFERENCE: 1324bf215546Sopenharmony_ci return PVR_DYNAMIC_STATE_BIT_STENCIL_REFERENCE; 1325bf215546Sopenharmony_ci default: 1326bf215546Sopenharmony_ci unreachable("Unsupported state."); 1327bf215546Sopenharmony_ci } 1328bf215546Sopenharmony_ci} 1329bf215546Sopenharmony_ci 1330bf215546Sopenharmony_cistatic void 1331bf215546Sopenharmony_cipvr_graphics_pipeline_destroy(struct pvr_device *const device, 1332bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 1333bf215546Sopenharmony_ci struct pvr_graphics_pipeline *const gfx_pipeline) 1334bf215546Sopenharmony_ci{ 1335bf215546Sopenharmony_ci const uint32_t num_vertex_attrib_programs = 1336bf215546Sopenharmony_ci ARRAY_SIZE(gfx_pipeline->vertex_shader_state.pds_attrib_programs); 1337bf215546Sopenharmony_ci 1338bf215546Sopenharmony_ci pvr_pds_descriptor_program_destroy( 1339bf215546Sopenharmony_ci device, 1340bf215546Sopenharmony_ci allocator, 1341bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state.descriptor_state); 1342bf215546Sopenharmony_ci 1343bf215546Sopenharmony_ci pvr_pds_descriptor_program_destroy( 1344bf215546Sopenharmony_ci device, 1345bf215546Sopenharmony_ci allocator, 1346bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.descriptor_state); 1347bf215546Sopenharmony_ci 1348bf215546Sopenharmony_ci for (uint32_t i = 0; i < num_vertex_attrib_programs; i++) { 1349bf215546Sopenharmony_ci struct pvr_pds_attrib_program *const attrib_program = 1350bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.pds_attrib_programs[i]; 1351bf215546Sopenharmony_ci 1352bf215546Sopenharmony_ci pvr_pds_vertex_attrib_program_destroy(device, allocator, attrib_program); 1353bf215546Sopenharmony_ci } 1354bf215546Sopenharmony_ci 1355bf215546Sopenharmony_ci pvr_bo_free(device, 1356bf215546Sopenharmony_ci gfx_pipeline->fragment_shader_state.pds_fragment_program.pvr_bo); 1357bf215546Sopenharmony_ci pvr_bo_free(device, 1358bf215546Sopenharmony_ci gfx_pipeline->fragment_shader_state.pds_coeff_program.pvr_bo); 1359bf215546Sopenharmony_ci 1360bf215546Sopenharmony_ci pvr_bo_free(device, gfx_pipeline->fragment_shader_state.bo); 1361bf215546Sopenharmony_ci pvr_bo_free(device, gfx_pipeline->vertex_shader_state.bo); 1362bf215546Sopenharmony_ci 1363bf215546Sopenharmony_ci pvr_pipeline_finish(&gfx_pipeline->base); 1364bf215546Sopenharmony_ci 1365bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, gfx_pipeline); 1366bf215546Sopenharmony_ci} 1367bf215546Sopenharmony_ci 1368bf215546Sopenharmony_cistatic void 1369bf215546Sopenharmony_cipvr_vertex_state_init(struct pvr_graphics_pipeline *gfx_pipeline, 1370bf215546Sopenharmony_ci const struct rogue_common_build_data *common_data, 1371bf215546Sopenharmony_ci const struct rogue_vs_build_data *vs_data) 1372bf215546Sopenharmony_ci{ 1373bf215546Sopenharmony_ci struct pvr_vertex_shader_state *vertex_state = 1374bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state; 1375bf215546Sopenharmony_ci 1376bf215546Sopenharmony_ci /* TODO: Hard coding these for now. These should be populated based on the 1377bf215546Sopenharmony_ci * information returned by the compiler. 1378bf215546Sopenharmony_ci */ 1379bf215546Sopenharmony_ci vertex_state->stage_state.const_shared_reg_count = common_data->shareds; 1380bf215546Sopenharmony_ci vertex_state->stage_state.const_shared_reg_offset = 0; 1381bf215546Sopenharmony_ci vertex_state->stage_state.temps_count = common_data->temps; 1382bf215546Sopenharmony_ci vertex_state->stage_state.coefficient_size = common_data->coeffs; 1383bf215546Sopenharmony_ci vertex_state->stage_state.uses_atomic_ops = false; 1384bf215546Sopenharmony_ci vertex_state->stage_state.uses_texture_rw = false; 1385bf215546Sopenharmony_ci vertex_state->stage_state.uses_barrier = false; 1386bf215546Sopenharmony_ci vertex_state->stage_state.has_side_effects = false; 1387bf215546Sopenharmony_ci vertex_state->stage_state.empty_program = false; 1388bf215546Sopenharmony_ci 1389bf215546Sopenharmony_ci vertex_state->vertex_input_size = vs_data->num_vertex_input_regs; 1390bf215546Sopenharmony_ci vertex_state->vertex_output_size = 1391bf215546Sopenharmony_ci vs_data->num_vertex_outputs * ROGUE_REG_SIZE_BYTES; 1392bf215546Sopenharmony_ci vertex_state->user_clip_planes_mask = 0; 1393bf215546Sopenharmony_ci vertex_state->entry_offset = 0; 1394bf215546Sopenharmony_ci 1395bf215546Sopenharmony_ci /* TODO: The number of varyings should be checked against the fragment 1396bf215546Sopenharmony_ci * shader inputs and assigned in the place where that happens. 1397bf215546Sopenharmony_ci * There will also be an opportunity to cull unused fs inputs/vs outputs. 1398bf215546Sopenharmony_ci */ 1399bf215546Sopenharmony_ci pvr_csb_pack (&gfx_pipeline->vertex_shader_state.varying[0], 1400bf215546Sopenharmony_ci TA_STATE_VARYING0, 1401bf215546Sopenharmony_ci varying0) { 1402bf215546Sopenharmony_ci varying0.f32_linear = vs_data->num_varyings; 1403bf215546Sopenharmony_ci varying0.f32_flat = 0; 1404bf215546Sopenharmony_ci varying0.f32_npc = 0; 1405bf215546Sopenharmony_ci } 1406bf215546Sopenharmony_ci 1407bf215546Sopenharmony_ci pvr_csb_pack (&gfx_pipeline->vertex_shader_state.varying[1], 1408bf215546Sopenharmony_ci TA_STATE_VARYING1, 1409bf215546Sopenharmony_ci varying1) { 1410bf215546Sopenharmony_ci varying1.f16_linear = 0; 1411bf215546Sopenharmony_ci varying1.f16_flat = 0; 1412bf215546Sopenharmony_ci varying1.f16_npc = 0; 1413bf215546Sopenharmony_ci } 1414bf215546Sopenharmony_ci} 1415bf215546Sopenharmony_ci 1416bf215546Sopenharmony_cistatic void 1417bf215546Sopenharmony_cipvr_fragment_state_init(struct pvr_graphics_pipeline *gfx_pipeline, 1418bf215546Sopenharmony_ci const struct rogue_common_build_data *common_data) 1419bf215546Sopenharmony_ci{ 1420bf215546Sopenharmony_ci struct pvr_fragment_shader_state *fragment_state = 1421bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state; 1422bf215546Sopenharmony_ci 1423bf215546Sopenharmony_ci /* TODO: Hard coding these for now. These should be populated based on the 1424bf215546Sopenharmony_ci * information returned by the compiler. 1425bf215546Sopenharmony_ci */ 1426bf215546Sopenharmony_ci fragment_state->stage_state.const_shared_reg_count = 0; 1427bf215546Sopenharmony_ci fragment_state->stage_state.const_shared_reg_offset = 0; 1428bf215546Sopenharmony_ci fragment_state->stage_state.temps_count = common_data->temps; 1429bf215546Sopenharmony_ci fragment_state->stage_state.coefficient_size = common_data->coeffs; 1430bf215546Sopenharmony_ci fragment_state->stage_state.uses_atomic_ops = false; 1431bf215546Sopenharmony_ci fragment_state->stage_state.uses_texture_rw = false; 1432bf215546Sopenharmony_ci fragment_state->stage_state.uses_barrier = false; 1433bf215546Sopenharmony_ci fragment_state->stage_state.has_side_effects = false; 1434bf215546Sopenharmony_ci fragment_state->stage_state.empty_program = false; 1435bf215546Sopenharmony_ci 1436bf215546Sopenharmony_ci fragment_state->pass_type = 0; 1437bf215546Sopenharmony_ci fragment_state->entry_offset = 0; 1438bf215546Sopenharmony_ci} 1439bf215546Sopenharmony_ci 1440bf215546Sopenharmony_ci/* Compiles and uploads shaders and PDS programs. */ 1441bf215546Sopenharmony_cistatic VkResult 1442bf215546Sopenharmony_cipvr_graphics_pipeline_compile(struct pvr_device *const device, 1443bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1444bf215546Sopenharmony_ci const VkGraphicsPipelineCreateInfo *pCreateInfo, 1445bf215546Sopenharmony_ci const VkAllocationCallbacks *const allocator, 1446bf215546Sopenharmony_ci struct pvr_graphics_pipeline *const gfx_pipeline) 1447bf215546Sopenharmony_ci{ 1448bf215546Sopenharmony_ci /* FIXME: Remove this hard coding. */ 1449bf215546Sopenharmony_ci struct pvr_explicit_constant_usage vert_explicit_const_usage = { 1450bf215546Sopenharmony_ci .start_offset = 16, 1451bf215546Sopenharmony_ci }; 1452bf215546Sopenharmony_ci struct pvr_explicit_constant_usage frag_explicit_const_usage = { 1453bf215546Sopenharmony_ci .start_offset = 0, 1454bf215546Sopenharmony_ci }; 1455bf215546Sopenharmony_ci static uint32_t hard_code_pipeline_n = 0; 1456bf215546Sopenharmony_ci 1457bf215546Sopenharmony_ci const VkPipelineVertexInputStateCreateInfo *const vertex_input_state = 1458bf215546Sopenharmony_ci pCreateInfo->pVertexInputState; 1459bf215546Sopenharmony_ci const uint32_t cache_line_size = 1460bf215546Sopenharmony_ci rogue_get_slc_cache_line_size(&device->pdevice->dev_info); 1461bf215546Sopenharmony_ci struct rogue_compiler *compiler = device->pdevice->compiler; 1462bf215546Sopenharmony_ci struct rogue_build_ctx *ctx; 1463bf215546Sopenharmony_ci VkResult result; 1464bf215546Sopenharmony_ci 1465bf215546Sopenharmony_ci /* Setup shared build context. */ 1466bf215546Sopenharmony_ci ctx = rogue_create_build_context(compiler); 1467bf215546Sopenharmony_ci if (!ctx) 1468bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1469bf215546Sopenharmony_ci 1470bf215546Sopenharmony_ci /* NIR middle-end translation. */ 1471bf215546Sopenharmony_ci for (gl_shader_stage stage = MESA_SHADER_FRAGMENT; stage > MESA_SHADER_NONE; 1472bf215546Sopenharmony_ci stage--) { 1473bf215546Sopenharmony_ci const VkPipelineShaderStageCreateInfo *create_info; 1474bf215546Sopenharmony_ci size_t stage_index = gfx_pipeline->stage_indices[stage]; 1475bf215546Sopenharmony_ci 1476bf215546Sopenharmony_ci if (pvr_hard_code_shader_required(&device->pdevice->dev_info)) { 1477bf215546Sopenharmony_ci if (pvr_hard_code_graphics_get_flags(&device->pdevice->dev_info) & 1478bf215546Sopenharmony_ci BITFIELD_BIT(stage)) { 1479bf215546Sopenharmony_ci continue; 1480bf215546Sopenharmony_ci } 1481bf215546Sopenharmony_ci } 1482bf215546Sopenharmony_ci 1483bf215546Sopenharmony_ci /* Skip unused/inactive stages. */ 1484bf215546Sopenharmony_ci if (stage_index == ~0) 1485bf215546Sopenharmony_ci continue; 1486bf215546Sopenharmony_ci 1487bf215546Sopenharmony_ci create_info = &pCreateInfo->pStages[stage_index]; 1488bf215546Sopenharmony_ci 1489bf215546Sopenharmony_ci /* SPIR-V to NIR. */ 1490bf215546Sopenharmony_ci ctx->nir[stage] = pvr_spirv_to_nir(ctx, stage, create_info); 1491bf215546Sopenharmony_ci if (!ctx->nir[stage]) { 1492bf215546Sopenharmony_ci ralloc_free(ctx); 1493bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1494bf215546Sopenharmony_ci } 1495bf215546Sopenharmony_ci } 1496bf215546Sopenharmony_ci 1497bf215546Sopenharmony_ci /* Pre-back-end analysis and optimization, driver data extraction. */ 1498bf215546Sopenharmony_ci /* TODO: Analyze and cull unused I/O between stages. */ 1499bf215546Sopenharmony_ci /* TODO: Allocate UBOs between stages; 1500bf215546Sopenharmony_ci * pipeline->layout->set_{count,layout}. 1501bf215546Sopenharmony_ci */ 1502bf215546Sopenharmony_ci 1503bf215546Sopenharmony_ci /* Back-end translation. */ 1504bf215546Sopenharmony_ci for (gl_shader_stage stage = MESA_SHADER_FRAGMENT; stage > MESA_SHADER_NONE; 1505bf215546Sopenharmony_ci stage--) { 1506bf215546Sopenharmony_ci if (pvr_hard_code_shader_required(&device->pdevice->dev_info) && 1507bf215546Sopenharmony_ci pvr_hard_code_graphics_get_flags(&device->pdevice->dev_info) & 1508bf215546Sopenharmony_ci BITFIELD_BIT(stage)) { 1509bf215546Sopenharmony_ci const struct pvr_device_info *const dev_info = 1510bf215546Sopenharmony_ci &device->pdevice->dev_info; 1511bf215546Sopenharmony_ci struct pvr_explicit_constant_usage *explicit_const_usage; 1512bf215546Sopenharmony_ci 1513bf215546Sopenharmony_ci switch (stage) { 1514bf215546Sopenharmony_ci case MESA_SHADER_VERTEX: 1515bf215546Sopenharmony_ci explicit_const_usage = &vert_explicit_const_usage; 1516bf215546Sopenharmony_ci break; 1517bf215546Sopenharmony_ci 1518bf215546Sopenharmony_ci case MESA_SHADER_FRAGMENT: 1519bf215546Sopenharmony_ci explicit_const_usage = &frag_explicit_const_usage; 1520bf215546Sopenharmony_ci break; 1521bf215546Sopenharmony_ci 1522bf215546Sopenharmony_ci default: 1523bf215546Sopenharmony_ci unreachable("Unsupported stage."); 1524bf215546Sopenharmony_ci } 1525bf215546Sopenharmony_ci 1526bf215546Sopenharmony_ci pvr_hard_code_graphics_shader(dev_info, 1527bf215546Sopenharmony_ci hard_code_pipeline_n, 1528bf215546Sopenharmony_ci stage, 1529bf215546Sopenharmony_ci &ctx->binary[stage]); 1530bf215546Sopenharmony_ci 1531bf215546Sopenharmony_ci pvr_hard_code_graphics_get_build_info(dev_info, 1532bf215546Sopenharmony_ci hard_code_pipeline_n, 1533bf215546Sopenharmony_ci stage, 1534bf215546Sopenharmony_ci &ctx->common_data[stage], 1535bf215546Sopenharmony_ci &ctx->stage_data, 1536bf215546Sopenharmony_ci explicit_const_usage); 1537bf215546Sopenharmony_ci 1538bf215546Sopenharmony_ci continue; 1539bf215546Sopenharmony_ci } 1540bf215546Sopenharmony_ci 1541bf215546Sopenharmony_ci if (!ctx->nir[stage]) 1542bf215546Sopenharmony_ci continue; 1543bf215546Sopenharmony_ci 1544bf215546Sopenharmony_ci ctx->rogue[stage] = pvr_nir_to_rogue(ctx, ctx->nir[stage]); 1545bf215546Sopenharmony_ci if (!ctx->rogue[stage]) { 1546bf215546Sopenharmony_ci ralloc_free(ctx); 1547bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1548bf215546Sopenharmony_ci } 1549bf215546Sopenharmony_ci 1550bf215546Sopenharmony_ci ctx->binary[stage] = pvr_rogue_to_binary(ctx, ctx->rogue[stage]); 1551bf215546Sopenharmony_ci if (!ctx->binary[stage]) { 1552bf215546Sopenharmony_ci ralloc_free(ctx); 1553bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1554bf215546Sopenharmony_ci } 1555bf215546Sopenharmony_ci } 1556bf215546Sopenharmony_ci 1557bf215546Sopenharmony_ci if (pvr_hard_code_shader_required(&device->pdevice->dev_info) && 1558bf215546Sopenharmony_ci pvr_hard_code_graphics_get_flags(&device->pdevice->dev_info) & 1559bf215546Sopenharmony_ci BITFIELD_BIT(MESA_SHADER_VERTEX)) { 1560bf215546Sopenharmony_ci pvr_hard_code_graphics_vertex_state(&device->pdevice->dev_info, 1561bf215546Sopenharmony_ci hard_code_pipeline_n, 1562bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state); 1563bf215546Sopenharmony_ci } else { 1564bf215546Sopenharmony_ci pvr_vertex_state_init(gfx_pipeline, 1565bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_VERTEX], 1566bf215546Sopenharmony_ci &ctx->stage_data.vs); 1567bf215546Sopenharmony_ci } 1568bf215546Sopenharmony_ci 1569bf215546Sopenharmony_ci result = pvr_gpu_upload_usc(device, 1570bf215546Sopenharmony_ci ctx->binary[MESA_SHADER_VERTEX]->data, 1571bf215546Sopenharmony_ci ctx->binary[MESA_SHADER_VERTEX]->size, 1572bf215546Sopenharmony_ci cache_line_size, 1573bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.bo); 1574bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1575bf215546Sopenharmony_ci goto err_free_build_context; 1576bf215546Sopenharmony_ci 1577bf215546Sopenharmony_ci if (pvr_hard_code_shader_required(&device->pdevice->dev_info) && 1578bf215546Sopenharmony_ci pvr_hard_code_graphics_get_flags(&device->pdevice->dev_info) & 1579bf215546Sopenharmony_ci BITFIELD_BIT(MESA_SHADER_FRAGMENT)) { 1580bf215546Sopenharmony_ci pvr_hard_code_graphics_fragment_state( 1581bf215546Sopenharmony_ci &device->pdevice->dev_info, 1582bf215546Sopenharmony_ci hard_code_pipeline_n, 1583bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state); 1584bf215546Sopenharmony_ci } else { 1585bf215546Sopenharmony_ci pvr_fragment_state_init(gfx_pipeline, 1586bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_FRAGMENT]); 1587bf215546Sopenharmony_ci } 1588bf215546Sopenharmony_ci 1589bf215546Sopenharmony_ci result = pvr_gpu_upload_usc(device, 1590bf215546Sopenharmony_ci ctx->binary[MESA_SHADER_FRAGMENT]->data, 1591bf215546Sopenharmony_ci ctx->binary[MESA_SHADER_FRAGMENT]->size, 1592bf215546Sopenharmony_ci cache_line_size, 1593bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state.bo); 1594bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1595bf215546Sopenharmony_ci goto err_free_vertex_bo; 1596bf215546Sopenharmony_ci 1597bf215546Sopenharmony_ci /* TODO: powervr has an optimization where it attempts to recompile shaders. 1598bf215546Sopenharmony_ci * See PipelineCompileNoISPFeedbackFragmentStage. Unimplemented since in our 1599bf215546Sopenharmony_ci * case the optimization doesn't happen. 1600bf215546Sopenharmony_ci */ 1601bf215546Sopenharmony_ci 1602bf215546Sopenharmony_ci /* TODO: The programs we use are hard coded for now, but these should be 1603bf215546Sopenharmony_ci * selected dynamically. 1604bf215546Sopenharmony_ci */ 1605bf215546Sopenharmony_ci 1606bf215546Sopenharmony_ci result = pvr_pds_coeff_program_create_and_upload( 1607bf215546Sopenharmony_ci device, 1608bf215546Sopenharmony_ci allocator, 1609bf215546Sopenharmony_ci ctx->stage_data.fs.iterator_args.fpu_iterators, 1610bf215546Sopenharmony_ci ctx->stage_data.fs.iterator_args.num_fpu_iterators, 1611bf215546Sopenharmony_ci ctx->stage_data.fs.iterator_args.destination, 1612bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state.pds_coeff_program); 1613bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1614bf215546Sopenharmony_ci goto err_free_fragment_bo; 1615bf215546Sopenharmony_ci 1616bf215546Sopenharmony_ci result = pvr_pds_fragment_program_create_and_upload( 1617bf215546Sopenharmony_ci device, 1618bf215546Sopenharmony_ci allocator, 1619bf215546Sopenharmony_ci gfx_pipeline->fragment_shader_state.bo, 1620bf215546Sopenharmony_ci ctx->common_data[MESA_SHADER_FRAGMENT].temps, 1621bf215546Sopenharmony_ci ctx->stage_data.fs.msaa_mode, 1622bf215546Sopenharmony_ci ctx->stage_data.fs.phas, 1623bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state.pds_fragment_program); 1624bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1625bf215546Sopenharmony_ci goto err_free_coeff_program; 1626bf215546Sopenharmony_ci 1627bf215546Sopenharmony_ci result = pvr_pds_vertex_attrib_programs_create_and_upload( 1628bf215546Sopenharmony_ci device, 1629bf215546Sopenharmony_ci allocator, 1630bf215546Sopenharmony_ci vertex_input_state, 1631bf215546Sopenharmony_ci ctx->common_data[MESA_SHADER_VERTEX].temps, 1632bf215546Sopenharmony_ci &ctx->stage_data.vs, 1633bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.pds_attrib_programs); 1634bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1635bf215546Sopenharmony_ci goto err_free_frag_program; 1636bf215546Sopenharmony_ci 1637bf215546Sopenharmony_ci result = pvr_pds_descriptor_program_create_and_upload( 1638bf215546Sopenharmony_ci device, 1639bf215546Sopenharmony_ci allocator, 1640bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_VERTEX].compile_time_consts_data, 1641bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_VERTEX].ubo_data, 1642bf215546Sopenharmony_ci &vert_explicit_const_usage, 1643bf215546Sopenharmony_ci gfx_pipeline->base.layout, 1644bf215546Sopenharmony_ci PVR_STAGE_ALLOCATION_VERTEX_GEOMETRY, 1645bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.descriptor_state); 1646bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1647bf215546Sopenharmony_ci goto err_free_vertex_attrib_program; 1648bf215546Sopenharmony_ci 1649bf215546Sopenharmony_ci /* FIXME: When the temp_buffer_total_size is non-zero we need to allocate a 1650bf215546Sopenharmony_ci * scratch buffer for both vertex and fragment stage. 1651bf215546Sopenharmony_ci * Figure out the best place to do this. 1652bf215546Sopenharmony_ci */ 1653bf215546Sopenharmony_ci /* assert(pvr_pds_descriptor_program_variables.temp_buff_total_size == 0); */ 1654bf215546Sopenharmony_ci /* TODO: Implement spilling with the above. */ 1655bf215546Sopenharmony_ci 1656bf215546Sopenharmony_ci /* TODO: Call pvr_pds_program_program_create_and_upload in a loop. */ 1657bf215546Sopenharmony_ci /* FIXME: For now we pass in the same explicit_const_usage since it contains 1658bf215546Sopenharmony_ci * all invalid entries. Fix this by hooking it up to the compiler. 1659bf215546Sopenharmony_ci */ 1660bf215546Sopenharmony_ci result = pvr_pds_descriptor_program_create_and_upload( 1661bf215546Sopenharmony_ci device, 1662bf215546Sopenharmony_ci allocator, 1663bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_FRAGMENT].compile_time_consts_data, 1664bf215546Sopenharmony_ci &ctx->common_data[MESA_SHADER_FRAGMENT].ubo_data, 1665bf215546Sopenharmony_ci &frag_explicit_const_usage, 1666bf215546Sopenharmony_ci gfx_pipeline->base.layout, 1667bf215546Sopenharmony_ci PVR_STAGE_ALLOCATION_FRAGMENT, 1668bf215546Sopenharmony_ci &gfx_pipeline->fragment_shader_state.descriptor_state); 1669bf215546Sopenharmony_ci if (result != VK_SUCCESS) 1670bf215546Sopenharmony_ci goto err_free_vertex_descriptor_program; 1671bf215546Sopenharmony_ci 1672bf215546Sopenharmony_ci ralloc_free(ctx); 1673bf215546Sopenharmony_ci 1674bf215546Sopenharmony_ci hard_code_pipeline_n++; 1675bf215546Sopenharmony_ci 1676bf215546Sopenharmony_ci return VK_SUCCESS; 1677bf215546Sopenharmony_ci 1678bf215546Sopenharmony_cierr_free_vertex_descriptor_program: 1679bf215546Sopenharmony_ci pvr_pds_descriptor_program_destroy( 1680bf215546Sopenharmony_ci device, 1681bf215546Sopenharmony_ci allocator, 1682bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.descriptor_state); 1683bf215546Sopenharmony_cierr_free_vertex_attrib_program: 1684bf215546Sopenharmony_ci for (uint32_t i = 0; 1685bf215546Sopenharmony_ci i < ARRAY_SIZE(gfx_pipeline->vertex_shader_state.pds_attrib_programs); 1686bf215546Sopenharmony_ci i++) { 1687bf215546Sopenharmony_ci struct pvr_pds_attrib_program *const attrib_program = 1688bf215546Sopenharmony_ci &gfx_pipeline->vertex_shader_state.pds_attrib_programs[i]; 1689bf215546Sopenharmony_ci 1690bf215546Sopenharmony_ci pvr_pds_vertex_attrib_program_destroy(device, allocator, attrib_program); 1691bf215546Sopenharmony_ci } 1692bf215546Sopenharmony_cierr_free_frag_program: 1693bf215546Sopenharmony_ci pvr_bo_free(device, 1694bf215546Sopenharmony_ci gfx_pipeline->fragment_shader_state.pds_fragment_program.pvr_bo); 1695bf215546Sopenharmony_cierr_free_coeff_program: 1696bf215546Sopenharmony_ci pvr_bo_free(device, 1697bf215546Sopenharmony_ci gfx_pipeline->fragment_shader_state.pds_coeff_program.pvr_bo); 1698bf215546Sopenharmony_cierr_free_fragment_bo: 1699bf215546Sopenharmony_ci pvr_bo_free(device, gfx_pipeline->fragment_shader_state.bo); 1700bf215546Sopenharmony_cierr_free_vertex_bo: 1701bf215546Sopenharmony_ci pvr_bo_free(device, gfx_pipeline->vertex_shader_state.bo); 1702bf215546Sopenharmony_cierr_free_build_context: 1703bf215546Sopenharmony_ci ralloc_free(ctx); 1704bf215546Sopenharmony_ci return result; 1705bf215546Sopenharmony_ci} 1706bf215546Sopenharmony_ci 1707bf215546Sopenharmony_cistatic void pvr_graphics_pipeline_init_depth_and_stencil_state( 1708bf215546Sopenharmony_ci struct pvr_graphics_pipeline *gfx_pipeline, 1709bf215546Sopenharmony_ci const VkPipelineDepthStencilStateCreateInfo *depth_stencil_state) 1710bf215546Sopenharmony_ci{ 1711bf215546Sopenharmony_ci const VkStencilOpState *front; 1712bf215546Sopenharmony_ci const VkStencilOpState *back; 1713bf215546Sopenharmony_ci 1714bf215546Sopenharmony_ci if (!depth_stencil_state) 1715bf215546Sopenharmony_ci return; 1716bf215546Sopenharmony_ci 1717bf215546Sopenharmony_ci front = &depth_stencil_state->front; 1718bf215546Sopenharmony_ci back = &depth_stencil_state->back; 1719bf215546Sopenharmony_ci 1720bf215546Sopenharmony_ci if (depth_stencil_state->depthTestEnable) { 1721bf215546Sopenharmony_ci gfx_pipeline->depth_compare_op = depth_stencil_state->depthCompareOp; 1722bf215546Sopenharmony_ci gfx_pipeline->depth_write_disable = 1723bf215546Sopenharmony_ci !depth_stencil_state->depthWriteEnable; 1724bf215546Sopenharmony_ci } else { 1725bf215546Sopenharmony_ci gfx_pipeline->depth_compare_op = VK_COMPARE_OP_ALWAYS; 1726bf215546Sopenharmony_ci gfx_pipeline->depth_write_disable = true; 1727bf215546Sopenharmony_ci } 1728bf215546Sopenharmony_ci 1729bf215546Sopenharmony_ci if (depth_stencil_state->stencilTestEnable) { 1730bf215546Sopenharmony_ci gfx_pipeline->stencil_front.compare_op = front->compareOp; 1731bf215546Sopenharmony_ci gfx_pipeline->stencil_front.fail_op = front->failOp; 1732bf215546Sopenharmony_ci gfx_pipeline->stencil_front.depth_fail_op = front->depthFailOp; 1733bf215546Sopenharmony_ci gfx_pipeline->stencil_front.pass_op = front->passOp; 1734bf215546Sopenharmony_ci 1735bf215546Sopenharmony_ci gfx_pipeline->stencil_back.compare_op = back->compareOp; 1736bf215546Sopenharmony_ci gfx_pipeline->stencil_back.fail_op = back->failOp; 1737bf215546Sopenharmony_ci gfx_pipeline->stencil_back.depth_fail_op = back->depthFailOp; 1738bf215546Sopenharmony_ci gfx_pipeline->stencil_back.pass_op = back->passOp; 1739bf215546Sopenharmony_ci } else { 1740bf215546Sopenharmony_ci gfx_pipeline->stencil_front.compare_op = VK_COMPARE_OP_ALWAYS; 1741bf215546Sopenharmony_ci gfx_pipeline->stencil_front.fail_op = VK_STENCIL_OP_KEEP; 1742bf215546Sopenharmony_ci gfx_pipeline->stencil_front.depth_fail_op = VK_STENCIL_OP_KEEP; 1743bf215546Sopenharmony_ci gfx_pipeline->stencil_front.pass_op = VK_STENCIL_OP_KEEP; 1744bf215546Sopenharmony_ci 1745bf215546Sopenharmony_ci gfx_pipeline->stencil_back = gfx_pipeline->stencil_front; 1746bf215546Sopenharmony_ci } 1747bf215546Sopenharmony_ci} 1748bf215546Sopenharmony_ci 1749bf215546Sopenharmony_cistatic void pvr_graphics_pipeline_init_dynamic_state( 1750bf215546Sopenharmony_ci struct pvr_graphics_pipeline *gfx_pipeline, 1751bf215546Sopenharmony_ci const VkPipelineDynamicStateCreateInfo *dynamic_state, 1752bf215546Sopenharmony_ci const VkPipelineViewportStateCreateInfo *viewport_state, 1753bf215546Sopenharmony_ci const VkPipelineDepthStencilStateCreateInfo *depth_stencil_state, 1754bf215546Sopenharmony_ci const VkPipelineColorBlendStateCreateInfo *color_blend_state, 1755bf215546Sopenharmony_ci const VkPipelineRasterizationStateCreateInfo *rasterization_state) 1756bf215546Sopenharmony_ci{ 1757bf215546Sopenharmony_ci struct pvr_dynamic_state *const internal_dynamic_state = 1758bf215546Sopenharmony_ci &gfx_pipeline->dynamic_state; 1759bf215546Sopenharmony_ci uint32_t dynamic_states = 0; 1760bf215546Sopenharmony_ci 1761bf215546Sopenharmony_ci if (dynamic_state) { 1762bf215546Sopenharmony_ci for (uint32_t i = 0; i < dynamic_state->dynamicStateCount; i++) { 1763bf215546Sopenharmony_ci dynamic_states |= 1764bf215546Sopenharmony_ci pvr_dynamic_state_bit_from_vk(dynamic_state->pDynamicStates[i]); 1765bf215546Sopenharmony_ci } 1766bf215546Sopenharmony_ci } 1767bf215546Sopenharmony_ci 1768bf215546Sopenharmony_ci /* TODO: Verify this. 1769bf215546Sopenharmony_ci * We don't zero out the pipeline's state if they are dynamic since they 1770bf215546Sopenharmony_ci * should be set later on in the command buffer. 1771bf215546Sopenharmony_ci */ 1772bf215546Sopenharmony_ci 1773bf215546Sopenharmony_ci /* TODO: Handle rasterizerDiscardEnable. */ 1774bf215546Sopenharmony_ci 1775bf215546Sopenharmony_ci if (rasterization_state) { 1776bf215546Sopenharmony_ci if (!(dynamic_states & PVR_DYNAMIC_STATE_BIT_LINE_WIDTH)) 1777bf215546Sopenharmony_ci internal_dynamic_state->line_width = rasterization_state->lineWidth; 1778bf215546Sopenharmony_ci 1779bf215546Sopenharmony_ci /* TODO: Do we need the depthBiasEnable check? */ 1780bf215546Sopenharmony_ci if (!(dynamic_states & PVR_DYNAMIC_STATE_BIT_DEPTH_BIAS)) { 1781bf215546Sopenharmony_ci internal_dynamic_state->depth_bias.constant_factor = 1782bf215546Sopenharmony_ci rasterization_state->depthBiasConstantFactor; 1783bf215546Sopenharmony_ci internal_dynamic_state->depth_bias.clamp = 1784bf215546Sopenharmony_ci rasterization_state->depthBiasClamp; 1785bf215546Sopenharmony_ci internal_dynamic_state->depth_bias.slope_factor = 1786bf215546Sopenharmony_ci rasterization_state->depthBiasSlopeFactor; 1787bf215546Sopenharmony_ci } 1788bf215546Sopenharmony_ci } 1789bf215546Sopenharmony_ci 1790bf215546Sopenharmony_ci /* TODO: handle viewport state flags. */ 1791bf215546Sopenharmony_ci 1792bf215546Sopenharmony_ci /* TODO: handle static viewport state. */ 1793bf215546Sopenharmony_ci /* We assume the viewport state to by dynamic for now. */ 1794bf215546Sopenharmony_ci 1795bf215546Sopenharmony_ci /* TODO: handle static scissor state. */ 1796bf215546Sopenharmony_ci /* We assume the scissor state to by dynamic for now. */ 1797bf215546Sopenharmony_ci 1798bf215546Sopenharmony_ci if (depth_stencil_state) { 1799bf215546Sopenharmony_ci const VkStencilOpState *const front = &depth_stencil_state->front; 1800bf215546Sopenharmony_ci const VkStencilOpState *const back = &depth_stencil_state->back; 1801bf215546Sopenharmony_ci 1802bf215546Sopenharmony_ci /* VkPhysicalDeviceFeatures->depthBounds is false. */ 1803bf215546Sopenharmony_ci assert(depth_stencil_state->depthBoundsTestEnable == VK_FALSE); 1804bf215546Sopenharmony_ci 1805bf215546Sopenharmony_ci if (!(dynamic_states & PVR_DYNAMIC_STATE_BIT_STENCIL_COMPARE_MASK)) { 1806bf215546Sopenharmony_ci internal_dynamic_state->compare_mask.front = front->compareMask; 1807bf215546Sopenharmony_ci internal_dynamic_state->compare_mask.back = back->compareMask; 1808bf215546Sopenharmony_ci } 1809bf215546Sopenharmony_ci 1810bf215546Sopenharmony_ci if (!(dynamic_states & PVR_DYNAMIC_STATE_BIT_STENCIL_WRITE_MASK)) { 1811bf215546Sopenharmony_ci internal_dynamic_state->write_mask.front = front->writeMask; 1812bf215546Sopenharmony_ci internal_dynamic_state->write_mask.back = back->writeMask; 1813bf215546Sopenharmony_ci } 1814bf215546Sopenharmony_ci 1815bf215546Sopenharmony_ci if (!(dynamic_states & PVR_DYNAMIC_STATE_BIT_STENCIL_REFERENCE)) { 1816bf215546Sopenharmony_ci internal_dynamic_state->reference.front = front->reference; 1817bf215546Sopenharmony_ci internal_dynamic_state->reference.back = back->reference; 1818bf215546Sopenharmony_ci } 1819bf215546Sopenharmony_ci } 1820bf215546Sopenharmony_ci 1821bf215546Sopenharmony_ci if (color_blend_state && 1822bf215546Sopenharmony_ci !(dynamic_states & PVR_DYNAMIC_STATE_BIT_BLEND_CONSTANTS)) { 1823bf215546Sopenharmony_ci STATIC_ASSERT(__same_type(internal_dynamic_state->blend_constants, 1824bf215546Sopenharmony_ci color_blend_state->blendConstants)); 1825bf215546Sopenharmony_ci 1826bf215546Sopenharmony_ci typed_memcpy(internal_dynamic_state->blend_constants, 1827bf215546Sopenharmony_ci color_blend_state->blendConstants, 1828bf215546Sopenharmony_ci ARRAY_SIZE(internal_dynamic_state->blend_constants)); 1829bf215546Sopenharmony_ci } 1830bf215546Sopenharmony_ci 1831bf215546Sopenharmony_ci /* TODO: handle STATIC_STATE_DEPTH_BOUNDS ? */ 1832bf215546Sopenharmony_ci 1833bf215546Sopenharmony_ci internal_dynamic_state->mask = dynamic_states; 1834bf215546Sopenharmony_ci} 1835bf215546Sopenharmony_ci 1836bf215546Sopenharmony_cistatic VkResult 1837bf215546Sopenharmony_cipvr_graphics_pipeline_init(struct pvr_device *device, 1838bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1839bf215546Sopenharmony_ci const VkGraphicsPipelineCreateInfo *pCreateInfo, 1840bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 1841bf215546Sopenharmony_ci struct pvr_graphics_pipeline *gfx_pipeline) 1842bf215546Sopenharmony_ci{ 1843bf215546Sopenharmony_ci /* If rasterization is not enabled, various CreateInfo structs must be 1844bf215546Sopenharmony_ci * ignored. 1845bf215546Sopenharmony_ci */ 1846bf215546Sopenharmony_ci const bool raster_discard_enabled = 1847bf215546Sopenharmony_ci pCreateInfo->pRasterizationState->rasterizerDiscardEnable; 1848bf215546Sopenharmony_ci const VkPipelineViewportStateCreateInfo *vs_info = 1849bf215546Sopenharmony_ci !raster_discard_enabled ? pCreateInfo->pViewportState : NULL; 1850bf215546Sopenharmony_ci const VkPipelineDepthStencilStateCreateInfo *dss_info = 1851bf215546Sopenharmony_ci !raster_discard_enabled ? pCreateInfo->pDepthStencilState : NULL; 1852bf215546Sopenharmony_ci const VkPipelineRasterizationStateCreateInfo *rs_info = 1853bf215546Sopenharmony_ci !raster_discard_enabled ? pCreateInfo->pRasterizationState : NULL; 1854bf215546Sopenharmony_ci const VkPipelineColorBlendStateCreateInfo *cbs_info = 1855bf215546Sopenharmony_ci !raster_discard_enabled ? pCreateInfo->pColorBlendState : NULL; 1856bf215546Sopenharmony_ci const VkPipelineMultisampleStateCreateInfo *ms_info = 1857bf215546Sopenharmony_ci !raster_discard_enabled ? pCreateInfo->pMultisampleState : NULL; 1858bf215546Sopenharmony_ci VkResult result; 1859bf215546Sopenharmony_ci 1860bf215546Sopenharmony_ci pvr_pipeline_init(device, PVR_PIPELINE_TYPE_GRAPHICS, &gfx_pipeline->base); 1861bf215546Sopenharmony_ci 1862bf215546Sopenharmony_ci pvr_finishme("ignoring pCreateInfo flags."); 1863bf215546Sopenharmony_ci pvr_finishme("ignoring pipeline cache."); 1864bf215546Sopenharmony_ci 1865bf215546Sopenharmony_ci gfx_pipeline->raster_state.discard_enable = raster_discard_enabled; 1866bf215546Sopenharmony_ci gfx_pipeline->raster_state.cull_mode = 1867bf215546Sopenharmony_ci pCreateInfo->pRasterizationState->cullMode; 1868bf215546Sopenharmony_ci gfx_pipeline->raster_state.front_face = 1869bf215546Sopenharmony_ci pCreateInfo->pRasterizationState->frontFace; 1870bf215546Sopenharmony_ci gfx_pipeline->raster_state.depth_bias_enable = 1871bf215546Sopenharmony_ci pCreateInfo->pRasterizationState->depthBiasEnable; 1872bf215546Sopenharmony_ci gfx_pipeline->raster_state.depth_clamp_enable = 1873bf215546Sopenharmony_ci pCreateInfo->pRasterizationState->depthClampEnable; 1874bf215546Sopenharmony_ci 1875bf215546Sopenharmony_ci /* FIXME: Handle depthClampEnable. */ 1876bf215546Sopenharmony_ci 1877bf215546Sopenharmony_ci pvr_graphics_pipeline_init_depth_and_stencil_state(gfx_pipeline, dss_info); 1878bf215546Sopenharmony_ci pvr_graphics_pipeline_init_dynamic_state(gfx_pipeline, 1879bf215546Sopenharmony_ci pCreateInfo->pDynamicState, 1880bf215546Sopenharmony_ci vs_info, 1881bf215546Sopenharmony_ci dss_info, 1882bf215546Sopenharmony_ci cbs_info, 1883bf215546Sopenharmony_ci rs_info); 1884bf215546Sopenharmony_ci 1885bf215546Sopenharmony_ci if (pCreateInfo->pInputAssemblyState) { 1886bf215546Sopenharmony_ci gfx_pipeline->input_asm_state.topology = 1887bf215546Sopenharmony_ci pCreateInfo->pInputAssemblyState->topology; 1888bf215546Sopenharmony_ci gfx_pipeline->input_asm_state.primitive_restart = 1889bf215546Sopenharmony_ci pCreateInfo->pInputAssemblyState->primitiveRestartEnable; 1890bf215546Sopenharmony_ci } 1891bf215546Sopenharmony_ci 1892bf215546Sopenharmony_ci memset(gfx_pipeline->stage_indices, ~0, sizeof(gfx_pipeline->stage_indices)); 1893bf215546Sopenharmony_ci 1894bf215546Sopenharmony_ci for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) { 1895bf215546Sopenharmony_ci VkShaderStageFlagBits vk_stage = pCreateInfo->pStages[i].stage; 1896bf215546Sopenharmony_ci gl_shader_stage gl_stage = vk_to_mesa_shader_stage(vk_stage); 1897bf215546Sopenharmony_ci /* From the Vulkan 1.2.192 spec for VkPipelineShaderStageCreateInfo: 1898bf215546Sopenharmony_ci * 1899bf215546Sopenharmony_ci * "stage must not be VK_SHADER_STAGE_ALL_GRAPHICS, 1900bf215546Sopenharmony_ci * or VK_SHADER_STAGE_ALL." 1901bf215546Sopenharmony_ci * 1902bf215546Sopenharmony_ci * So we don't handle that. 1903bf215546Sopenharmony_ci * 1904bf215546Sopenharmony_ci * We also don't handle VK_SHADER_STAGE_TESSELLATION_* and 1905bf215546Sopenharmony_ci * VK_SHADER_STAGE_GEOMETRY_BIT stages as 'tessellationShader' and 1906bf215546Sopenharmony_ci * 'geometryShader' are set to false in the VkPhysicalDeviceFeatures 1907bf215546Sopenharmony_ci * structure returned by the driver. 1908bf215546Sopenharmony_ci */ 1909bf215546Sopenharmony_ci switch (pCreateInfo->pStages[i].stage) { 1910bf215546Sopenharmony_ci case VK_SHADER_STAGE_VERTEX_BIT: 1911bf215546Sopenharmony_ci case VK_SHADER_STAGE_FRAGMENT_BIT: 1912bf215546Sopenharmony_ci gfx_pipeline->stage_indices[gl_stage] = i; 1913bf215546Sopenharmony_ci break; 1914bf215546Sopenharmony_ci default: 1915bf215546Sopenharmony_ci unreachable("Unsupported stage."); 1916bf215546Sopenharmony_ci } 1917bf215546Sopenharmony_ci } 1918bf215546Sopenharmony_ci 1919bf215546Sopenharmony_ci gfx_pipeline->base.layout = 1920bf215546Sopenharmony_ci pvr_pipeline_layout_from_handle(pCreateInfo->layout); 1921bf215546Sopenharmony_ci 1922bf215546Sopenharmony_ci if (ms_info) { 1923bf215546Sopenharmony_ci gfx_pipeline->rasterization_samples = ms_info->rasterizationSamples; 1924bf215546Sopenharmony_ci gfx_pipeline->sample_mask = 1925bf215546Sopenharmony_ci (ms_info->pSampleMask) ? ms_info->pSampleMask[0] : 0xFFFFFFFF; 1926bf215546Sopenharmony_ci } else { 1927bf215546Sopenharmony_ci gfx_pipeline->rasterization_samples = VK_SAMPLE_COUNT_1_BIT; 1928bf215546Sopenharmony_ci gfx_pipeline->sample_mask = 0xFFFFFFFF; 1929bf215546Sopenharmony_ci } 1930bf215546Sopenharmony_ci 1931bf215546Sopenharmony_ci /* Compiles and uploads shaders and PDS programs. */ 1932bf215546Sopenharmony_ci result = pvr_graphics_pipeline_compile(device, 1933bf215546Sopenharmony_ci pipeline_cache, 1934bf215546Sopenharmony_ci pCreateInfo, 1935bf215546Sopenharmony_ci allocator, 1936bf215546Sopenharmony_ci gfx_pipeline); 1937bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1938bf215546Sopenharmony_ci pvr_pipeline_finish(&gfx_pipeline->base); 1939bf215546Sopenharmony_ci return result; 1940bf215546Sopenharmony_ci } 1941bf215546Sopenharmony_ci 1942bf215546Sopenharmony_ci return VK_SUCCESS; 1943bf215546Sopenharmony_ci} 1944bf215546Sopenharmony_ci 1945bf215546Sopenharmony_ci/* If allocator == NULL, the internal one will be used. */ 1946bf215546Sopenharmony_cistatic VkResult 1947bf215546Sopenharmony_cipvr_graphics_pipeline_create(struct pvr_device *device, 1948bf215546Sopenharmony_ci struct pvr_pipeline_cache *pipeline_cache, 1949bf215546Sopenharmony_ci const VkGraphicsPipelineCreateInfo *pCreateInfo, 1950bf215546Sopenharmony_ci const VkAllocationCallbacks *allocator, 1951bf215546Sopenharmony_ci VkPipeline *const pipeline_out) 1952bf215546Sopenharmony_ci{ 1953bf215546Sopenharmony_ci struct pvr_graphics_pipeline *gfx_pipeline; 1954bf215546Sopenharmony_ci VkResult result; 1955bf215546Sopenharmony_ci 1956bf215546Sopenharmony_ci gfx_pipeline = vk_zalloc2(&device->vk.alloc, 1957bf215546Sopenharmony_ci allocator, 1958bf215546Sopenharmony_ci sizeof(*gfx_pipeline), 1959bf215546Sopenharmony_ci 8, 1960bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 1961bf215546Sopenharmony_ci if (!gfx_pipeline) 1962bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 1963bf215546Sopenharmony_ci 1964bf215546Sopenharmony_ci /* Compiles and uploads shaders and PDS programs too. */ 1965bf215546Sopenharmony_ci result = pvr_graphics_pipeline_init(device, 1966bf215546Sopenharmony_ci pipeline_cache, 1967bf215546Sopenharmony_ci pCreateInfo, 1968bf215546Sopenharmony_ci allocator, 1969bf215546Sopenharmony_ci gfx_pipeline); 1970bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 1971bf215546Sopenharmony_ci vk_free2(&device->vk.alloc, allocator, gfx_pipeline); 1972bf215546Sopenharmony_ci return result; 1973bf215546Sopenharmony_ci } 1974bf215546Sopenharmony_ci 1975bf215546Sopenharmony_ci *pipeline_out = pvr_pipeline_to_handle(&gfx_pipeline->base); 1976bf215546Sopenharmony_ci 1977bf215546Sopenharmony_ci return VK_SUCCESS; 1978bf215546Sopenharmony_ci} 1979bf215546Sopenharmony_ci 1980bf215546Sopenharmony_ciVkResult 1981bf215546Sopenharmony_cipvr_CreateGraphicsPipelines(VkDevice _device, 1982bf215546Sopenharmony_ci VkPipelineCache pipelineCache, 1983bf215546Sopenharmony_ci uint32_t createInfoCount, 1984bf215546Sopenharmony_ci const VkGraphicsPipelineCreateInfo *pCreateInfos, 1985bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator, 1986bf215546Sopenharmony_ci VkPipeline *pPipelines) 1987bf215546Sopenharmony_ci{ 1988bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_pipeline_cache, pipeline_cache, pipelineCache); 1989bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_device, device, _device); 1990bf215546Sopenharmony_ci VkResult result = VK_SUCCESS; 1991bf215546Sopenharmony_ci 1992bf215546Sopenharmony_ci for (uint32_t i = 0; i < createInfoCount; i++) { 1993bf215546Sopenharmony_ci const VkResult local_result = 1994bf215546Sopenharmony_ci pvr_graphics_pipeline_create(device, 1995bf215546Sopenharmony_ci pipeline_cache, 1996bf215546Sopenharmony_ci &pCreateInfos[i], 1997bf215546Sopenharmony_ci pAllocator, 1998bf215546Sopenharmony_ci &pPipelines[i]); 1999bf215546Sopenharmony_ci if (local_result != VK_SUCCESS) { 2000bf215546Sopenharmony_ci result = local_result; 2001bf215546Sopenharmony_ci pPipelines[i] = VK_NULL_HANDLE; 2002bf215546Sopenharmony_ci } 2003bf215546Sopenharmony_ci } 2004bf215546Sopenharmony_ci 2005bf215546Sopenharmony_ci return result; 2006bf215546Sopenharmony_ci} 2007bf215546Sopenharmony_ci 2008bf215546Sopenharmony_ci/***************************************************************************** 2009bf215546Sopenharmony_ci Other functions 2010bf215546Sopenharmony_ci*****************************************************************************/ 2011bf215546Sopenharmony_ci 2012bf215546Sopenharmony_civoid pvr_DestroyPipeline(VkDevice _device, 2013bf215546Sopenharmony_ci VkPipeline _pipeline, 2014bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator) 2015bf215546Sopenharmony_ci{ 2016bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_pipeline, pipeline, _pipeline); 2017bf215546Sopenharmony_ci PVR_FROM_HANDLE(pvr_device, device, _device); 2018bf215546Sopenharmony_ci 2019bf215546Sopenharmony_ci if (!pipeline) 2020bf215546Sopenharmony_ci return; 2021bf215546Sopenharmony_ci 2022bf215546Sopenharmony_ci switch (pipeline->type) { 2023bf215546Sopenharmony_ci case PVR_PIPELINE_TYPE_GRAPHICS: { 2024bf215546Sopenharmony_ci struct pvr_graphics_pipeline *const gfx_pipeline = 2025bf215546Sopenharmony_ci to_pvr_graphics_pipeline(pipeline); 2026bf215546Sopenharmony_ci 2027bf215546Sopenharmony_ci pvr_graphics_pipeline_destroy(device, pAllocator, gfx_pipeline); 2028bf215546Sopenharmony_ci break; 2029bf215546Sopenharmony_ci } 2030bf215546Sopenharmony_ci 2031bf215546Sopenharmony_ci case PVR_PIPELINE_TYPE_COMPUTE: { 2032bf215546Sopenharmony_ci struct pvr_compute_pipeline *const compute_pipeline = 2033bf215546Sopenharmony_ci to_pvr_compute_pipeline(pipeline); 2034bf215546Sopenharmony_ci 2035bf215546Sopenharmony_ci pvr_compute_pipeline_destroy(device, pAllocator, compute_pipeline); 2036bf215546Sopenharmony_ci break; 2037bf215546Sopenharmony_ci } 2038bf215546Sopenharmony_ci 2039bf215546Sopenharmony_ci default: 2040bf215546Sopenharmony_ci unreachable("Unknown pipeline type."); 2041bf215546Sopenharmony_ci } 2042bf215546Sopenharmony_ci} 2043