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