1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2022 Imagination Technologies Ltd.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
5bf215546Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
6bf215546Sopenharmony_ci * in the Software without restriction, including without limitation the rights
7bf215546Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8bf215546Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
9bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18bf215546Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include <stdbool.h>
25bf215546Sopenharmony_ci#include <stdint.h>
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "hwdef/rogue_hw_utils.h"
28bf215546Sopenharmony_ci#include "pvr_bo.h"
29bf215546Sopenharmony_ci#include "pvr_device_info.h"
30bf215546Sopenharmony_ci#include "pvr_formats.h"
31bf215546Sopenharmony_ci#include "pvr_hw_pass.h"
32bf215546Sopenharmony_ci#include "pvr_pds.h"
33bf215546Sopenharmony_ci#include "pvr_private.h"
34bf215546Sopenharmony_ci#include "pvr_usc_fragment_shader.h"
35bf215546Sopenharmony_ci#include "rogue/rogue.h"
36bf215546Sopenharmony_ci#include "vk_alloc.h"
37bf215546Sopenharmony_ci#include "vk_format.h"
38bf215546Sopenharmony_ci#include "vk_log.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci/*****************************************************************************
41bf215546Sopenharmony_ci  PDS pre-baked program generation parameters and variables.
42bf215546Sopenharmony_ci*****************************************************************************/
43bf215546Sopenharmony_ci/* These would normally be produced by the compiler or other code. We're using
44bf215546Sopenharmony_ci * them for now just to speed up things. All of these should eventually be
45bf215546Sopenharmony_ci * removed.
46bf215546Sopenharmony_ci */
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistatic const struct {
49bf215546Sopenharmony_ci   /* Indicates the amount of temporaries for the shader. */
50bf215546Sopenharmony_ci   uint32_t temp_count;
51bf215546Sopenharmony_ci   enum rogue_msaa_mode msaa_mode;
52bf215546Sopenharmony_ci   /* Indicates the presence of PHAS instruction. */
53bf215546Sopenharmony_ci   bool has_phase_rate_change;
54bf215546Sopenharmony_ci} pvr_pds_fragment_program_params = {
55bf215546Sopenharmony_ci   .temp_count = 0,
56bf215546Sopenharmony_ci   .msaa_mode = ROGUE_MSAA_MODE_PIXEL,
57bf215546Sopenharmony_ci   .has_phase_rate_change = false,
58bf215546Sopenharmony_ci};
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic inline bool pvr_subpass_has_msaa_input_attachment(
61bf215546Sopenharmony_ci   struct pvr_render_subpass *subpass,
62bf215546Sopenharmony_ci   const VkRenderPassCreateInfo2 *pCreateInfo)
63bf215546Sopenharmony_ci{
64bf215546Sopenharmony_ci   for (uint32_t i = 0; i < subpass->input_count; i++) {
65bf215546Sopenharmony_ci      const uint32_t attachment = subpass->input_attachments[i];
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci      if (pCreateInfo->pAttachments[attachment].samples > 1)
68bf215546Sopenharmony_ci         return true;
69bf215546Sopenharmony_ci   }
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   return false;
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic inline size_t
75bf215546Sopenharmony_cipvr_num_subpass_attachments(const VkSubpassDescription2 *desc)
76bf215546Sopenharmony_ci{
77bf215546Sopenharmony_ci   return desc->inputAttachmentCount + desc->colorAttachmentCount +
78bf215546Sopenharmony_ci          (desc->pResolveAttachments ? desc->colorAttachmentCount : 0) +
79bf215546Sopenharmony_ci          (desc->pDepthStencilAttachment != NULL);
80bf215546Sopenharmony_ci}
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_cistatic bool pvr_is_subpass_initops_flush_needed(
83bf215546Sopenharmony_ci   const struct pvr_render_pass *pass,
84bf215546Sopenharmony_ci   const struct pvr_renderpass_hwsetup_render *hw_render)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci   struct pvr_render_subpass *subpass = &pass->subpasses[0];
87bf215546Sopenharmony_ci   uint32_t render_loadop_mask = 0;
88bf215546Sopenharmony_ci   uint32_t color_attachment_mask;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci   for (uint32_t i = 0; i < hw_render->color_init_count; i++) {
91bf215546Sopenharmony_ci      if (hw_render->color_init[i].op != RENDERPASS_SURFACE_INITOP_NOP)
92bf215546Sopenharmony_ci         render_loadop_mask |= (1 << hw_render->color_init[i].driver_id);
93bf215546Sopenharmony_ci   }
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   /* If there are no load ops then there's nothing to flush. */
96bf215546Sopenharmony_ci   if (render_loadop_mask == 0)
97bf215546Sopenharmony_ci      return false;
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   /* If the first subpass has any input attachments, they need to be
100bf215546Sopenharmony_ci    * initialized with the result of the load op. Since the input attachment
101bf215546Sopenharmony_ci    * may be read from fragments with an opaque pass type, the load ops must be
102bf215546Sopenharmony_ci    * flushed or else they would be obscured and eliminated by HSR.
103bf215546Sopenharmony_ci    */
104bf215546Sopenharmony_ci   if (subpass->input_count != 0)
105bf215546Sopenharmony_ci      return true;
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   color_attachment_mask = 0;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   for (uint32_t i = 0; i < subpass->color_count; i++) {
110bf215546Sopenharmony_ci      const int32_t color_idx = subpass->color_attachments[i];
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci      if (color_idx != -1)
113bf215546Sopenharmony_ci         color_attachment_mask |= (1 << pass->attachments[color_idx].index);
114bf215546Sopenharmony_ci   }
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   /* If the first subpass does not write to all attachments which have a load
117bf215546Sopenharmony_ci    * op then the load ops need to be flushed to ensure they don't get obscured
118bf215546Sopenharmony_ci    * and removed by HSR.
119bf215546Sopenharmony_ci    */
120bf215546Sopenharmony_ci   return (render_loadop_mask & color_attachment_mask) != render_loadop_mask;
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_cistatic void
124bf215546Sopenharmony_cipvr_init_subpass_userpass_spawn(struct pvr_renderpass_hwsetup *hw_setup,
125bf215546Sopenharmony_ci                                struct pvr_render_pass *pass,
126bf215546Sopenharmony_ci                                struct pvr_render_subpass *subpasses)
127bf215546Sopenharmony_ci{
128bf215546Sopenharmony_ci   uint32_t subpass_idx = 0;
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   for (uint32_t i = 0; i < hw_setup->render_count; i++) {
131bf215546Sopenharmony_ci      struct pvr_renderpass_hwsetup_render *hw_render = &hw_setup->renders[i];
132bf215546Sopenharmony_ci      uint32_t initial_userpass_spawn =
133bf215546Sopenharmony_ci         (uint32_t)pvr_is_subpass_initops_flush_needed(pass, hw_render);
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci      for (uint32_t j = 0; j < hw_render->subpass_count; j++) {
136bf215546Sopenharmony_ci         subpasses[subpass_idx].userpass_spawn = (j + initial_userpass_spawn);
137bf215546Sopenharmony_ci         subpass_idx++;
138bf215546Sopenharmony_ci      }
139bf215546Sopenharmony_ci   }
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   assert(subpass_idx == pass->subpass_count);
142bf215546Sopenharmony_ci}
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_cistatic inline bool pvr_has_output_register_writes(
145bf215546Sopenharmony_ci   const struct pvr_renderpass_hwsetup_render *hw_render)
146bf215546Sopenharmony_ci{
147bf215546Sopenharmony_ci   for (uint32_t i = 0; i < hw_render->init_setup.render_targets_count; i++) {
148bf215546Sopenharmony_ci      struct usc_mrt_resource *mrt_resource =
149bf215546Sopenharmony_ci         &hw_render->init_setup.mrt_resources[i];
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci      if (mrt_resource->type == USC_MRT_RESOURCE_TYPE_OUTPUT_REGISTER)
152bf215546Sopenharmony_ci         return true;
153bf215546Sopenharmony_ci   }
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   return false;
156bf215546Sopenharmony_ci}
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ciVkResult pvr_pds_unitex_state_program_create_and_upload(
159bf215546Sopenharmony_ci   struct pvr_device *device,
160bf215546Sopenharmony_ci   const VkAllocationCallbacks *allocator,
161bf215546Sopenharmony_ci   uint32_t texture_kicks,
162bf215546Sopenharmony_ci   uint32_t uniform_kicks,
163bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
164bf215546Sopenharmony_ci{
165bf215546Sopenharmony_ci   struct pvr_pds_pixel_shader_sa_program program = {
166bf215546Sopenharmony_ci      .num_texture_dma_kicks = texture_kicks,
167bf215546Sopenharmony_ci      .num_uniform_dma_kicks = uniform_kicks,
168bf215546Sopenharmony_ci   };
169bf215546Sopenharmony_ci   uint32_t staging_buffer_size;
170bf215546Sopenharmony_ci   uint32_t *staging_buffer;
171bf215546Sopenharmony_ci   VkResult result;
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   pvr_pds_set_sizes_pixel_shader_uniform_texture_code(&program);
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   staging_buffer_size = program.code_size * sizeof(*staging_buffer);
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   staging_buffer = vk_alloc2(&device->vk.alloc,
178bf215546Sopenharmony_ci                              allocator,
179bf215546Sopenharmony_ci                              staging_buffer_size,
180bf215546Sopenharmony_ci                              8U,
181bf215546Sopenharmony_ci                              VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
182bf215546Sopenharmony_ci   if (!staging_buffer)
183bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   pvr_pds_generate_pixel_shader_sa_code_segment(&program, staging_buffer);
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   /* FIXME: Figure out the define for alignment of 16. */
188bf215546Sopenharmony_ci   result = pvr_gpu_upload_pds(device,
189bf215546Sopenharmony_ci                               NULL,
190bf215546Sopenharmony_ci                               0U,
191bf215546Sopenharmony_ci                               0U,
192bf215546Sopenharmony_ci                               staging_buffer,
193bf215546Sopenharmony_ci                               program.code_size,
194bf215546Sopenharmony_ci                               16U,
195bf215546Sopenharmony_ci                               16U,
196bf215546Sopenharmony_ci                               pds_upload_out);
197bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
198bf215546Sopenharmony_ci      vk_free2(&device->vk.alloc, allocator, staging_buffer);
199bf215546Sopenharmony_ci      return result;
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, allocator, staging_buffer);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   return VK_SUCCESS;
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_cistatic VkResult
208bf215546Sopenharmony_cipvr_load_op_create(struct pvr_device *device,
209bf215546Sopenharmony_ci                   const VkAllocationCallbacks *allocator,
210bf215546Sopenharmony_ci                   struct pvr_renderpass_hwsetup_render *hw_render,
211bf215546Sopenharmony_ci                   struct pvr_load_op **const load_op_out)
212bf215546Sopenharmony_ci{
213bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
214bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
215bf215546Sopenharmony_ci   struct pvr_load_op *load_op;
216bf215546Sopenharmony_ci   VkResult result;
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   load_op = vk_zalloc2(&device->vk.alloc,
219bf215546Sopenharmony_ci                        allocator,
220bf215546Sopenharmony_ci                        sizeof(*load_op),
221bf215546Sopenharmony_ci                        8,
222bf215546Sopenharmony_ci                        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
223bf215546Sopenharmony_ci   if (!load_op)
224bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   for (uint32_t i = 0; i < hw_render->color_init_count; i++) {
227bf215546Sopenharmony_ci      struct pvr_renderpass_colorinit *color_init = &hw_render->color_init[i];
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci      if (color_init->op == RENDERPASS_SURFACE_INITOP_CLEAR)
230bf215546Sopenharmony_ci         load_op->clear_mask |= 1U << i;
231bf215546Sopenharmony_ci      else if (color_init->op == RENDERPASS_SURFACE_INITOP_LOAD)
232bf215546Sopenharmony_ci         pvr_finishme("Missing 'load' load op");
233bf215546Sopenharmony_ci   }
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   result = pvr_gpu_upload_usc(device,
236bf215546Sopenharmony_ci                               pvr_usc_fragment_shader,
237bf215546Sopenharmony_ci                               sizeof(pvr_usc_fragment_shader),
238bf215546Sopenharmony_ci                               cache_line_size,
239bf215546Sopenharmony_ci                               &load_op->usc_frag_prog_bo);
240bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
241bf215546Sopenharmony_ci      goto err_free_load_op;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   result = pvr_pds_fragment_program_create_and_upload(
244bf215546Sopenharmony_ci      device,
245bf215546Sopenharmony_ci      allocator,
246bf215546Sopenharmony_ci      load_op->usc_frag_prog_bo,
247bf215546Sopenharmony_ci      pvr_pds_fragment_program_params.temp_count,
248bf215546Sopenharmony_ci      pvr_pds_fragment_program_params.msaa_mode,
249bf215546Sopenharmony_ci      pvr_pds_fragment_program_params.has_phase_rate_change,
250bf215546Sopenharmony_ci      &load_op->pds_frag_prog);
251bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
252bf215546Sopenharmony_ci      goto err_free_usc_frag_prog_bo;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   result = pvr_pds_unitex_state_program_create_and_upload(
255bf215546Sopenharmony_ci      device,
256bf215546Sopenharmony_ci      allocator,
257bf215546Sopenharmony_ci      1U,
258bf215546Sopenharmony_ci      0U,
259bf215546Sopenharmony_ci      &load_op->pds_tex_state_prog);
260bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
261bf215546Sopenharmony_ci      goto err_free_pds_frag_prog;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   load_op->is_hw_object = true;
264bf215546Sopenharmony_ci   /* FIXME: These should be based on the USC and PDS programs, but are hard
265bf215546Sopenharmony_ci    * coded for now.
266bf215546Sopenharmony_ci    */
267bf215546Sopenharmony_ci   load_op->const_shareds_count = 1;
268bf215546Sopenharmony_ci   load_op->shareds_dest_offset = 0;
269bf215546Sopenharmony_ci   load_op->shareds_count = 1;
270bf215546Sopenharmony_ci   load_op->temps_count = 1;
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci   *load_op_out = load_op;
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   return VK_SUCCESS;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_cierr_free_pds_frag_prog:
277bf215546Sopenharmony_ci   pvr_bo_free(device, load_op->pds_frag_prog.pvr_bo);
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_cierr_free_usc_frag_prog_bo:
280bf215546Sopenharmony_ci   pvr_bo_free(device, load_op->usc_frag_prog_bo);
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_cierr_free_load_op:
283bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, allocator, load_op);
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   return result;
286bf215546Sopenharmony_ci}
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_cistatic void pvr_load_op_destroy(struct pvr_device *device,
289bf215546Sopenharmony_ci                                const VkAllocationCallbacks *allocator,
290bf215546Sopenharmony_ci                                struct pvr_load_op *load_op)
291bf215546Sopenharmony_ci{
292bf215546Sopenharmony_ci   pvr_bo_free(device, load_op->pds_tex_state_prog.pvr_bo);
293bf215546Sopenharmony_ci   pvr_bo_free(device, load_op->pds_frag_prog.pvr_bo);
294bf215546Sopenharmony_ci   pvr_bo_free(device, load_op->usc_frag_prog_bo);
295bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, allocator, load_op);
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci#define PVR_SPM_LOAD_IN_BUFFERS_COUNT(dev_info)              \
299bf215546Sopenharmony_ci   ({                                                        \
300bf215546Sopenharmony_ci      int __ret = 7U;                                        \
301bf215546Sopenharmony_ci      if (PVR_HAS_FEATURE(dev_info, eight_output_registers)) \
302bf215546Sopenharmony_ci         __ret = 3U;                                         \
303bf215546Sopenharmony_ci      __ret;                                                 \
304bf215546Sopenharmony_ci   })
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ciVkResult pvr_CreateRenderPass2(VkDevice _device,
307bf215546Sopenharmony_ci                               const VkRenderPassCreateInfo2 *pCreateInfo,
308bf215546Sopenharmony_ci                               const VkAllocationCallbacks *pAllocator,
309bf215546Sopenharmony_ci                               VkRenderPass *pRenderPass)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci   struct pvr_render_pass_attachment *attachments;
312bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_device, device, _device);
313bf215546Sopenharmony_ci   struct pvr_render_subpass *subpasses;
314bf215546Sopenharmony_ci   size_t subpass_attachment_count;
315bf215546Sopenharmony_ci   uint32_t *subpass_attachments;
316bf215546Sopenharmony_ci   struct pvr_render_pass *pass;
317bf215546Sopenharmony_ci   uint32_t *dep_list;
318bf215546Sopenharmony_ci   bool *flush_on_dep;
319bf215546Sopenharmony_ci   VkResult result;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   VK_MULTIALLOC(ma);
322bf215546Sopenharmony_ci   vk_multialloc_add(&ma, &pass, __typeof__(*pass), 1);
323bf215546Sopenharmony_ci   vk_multialloc_add(&ma,
324bf215546Sopenharmony_ci                     &attachments,
325bf215546Sopenharmony_ci                     __typeof__(*attachments),
326bf215546Sopenharmony_ci                     pCreateInfo->attachmentCount);
327bf215546Sopenharmony_ci   vk_multialloc_add(&ma,
328bf215546Sopenharmony_ci                     &subpasses,
329bf215546Sopenharmony_ci                     __typeof__(*subpasses),
330bf215546Sopenharmony_ci                     pCreateInfo->subpassCount);
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   subpass_attachment_count = 0;
333bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
334bf215546Sopenharmony_ci      subpass_attachment_count +=
335bf215546Sopenharmony_ci         pvr_num_subpass_attachments(&pCreateInfo->pSubpasses[i]);
336bf215546Sopenharmony_ci   }
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   vk_multialloc_add(&ma,
339bf215546Sopenharmony_ci                     &subpass_attachments,
340bf215546Sopenharmony_ci                     __typeof__(*subpass_attachments),
341bf215546Sopenharmony_ci                     subpass_attachment_count);
342bf215546Sopenharmony_ci   vk_multialloc_add(&ma,
343bf215546Sopenharmony_ci                     &dep_list,
344bf215546Sopenharmony_ci                     __typeof__(*dep_list),
345bf215546Sopenharmony_ci                     pCreateInfo->dependencyCount);
346bf215546Sopenharmony_ci   vk_multialloc_add(&ma,
347bf215546Sopenharmony_ci                     &flush_on_dep,
348bf215546Sopenharmony_ci                     __typeof__(*flush_on_dep),
349bf215546Sopenharmony_ci                     pCreateInfo->dependencyCount);
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci   if (!vk_multialloc_zalloc2(&ma,
352bf215546Sopenharmony_ci                              &device->vk.alloc,
353bf215546Sopenharmony_ci                              pAllocator,
354bf215546Sopenharmony_ci                              VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)) {
355bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
356bf215546Sopenharmony_ci   }
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   vk_object_base_init(&device->vk, &pass->base, VK_OBJECT_TYPE_RENDER_PASS);
359bf215546Sopenharmony_ci   pass->attachment_count = pCreateInfo->attachmentCount;
360bf215546Sopenharmony_ci   pass->attachments = attachments;
361bf215546Sopenharmony_ci   pass->subpass_count = pCreateInfo->subpassCount;
362bf215546Sopenharmony_ci   pass->subpasses = subpasses;
363bf215546Sopenharmony_ci   pass->max_sample_count = 1;
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   /* Copy attachment descriptions. */
366bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pass->attachment_count; i++) {
367bf215546Sopenharmony_ci      const VkAttachmentDescription2 *desc = &pCreateInfo->pAttachments[i];
368bf215546Sopenharmony_ci      struct pvr_render_pass_attachment *attachment = &pass->attachments[i];
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci      pvr_assert(!(desc->flags & ~VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT));
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci      attachment->load_op = desc->loadOp;
373bf215546Sopenharmony_ci      attachment->store_op = desc->storeOp;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci      attachment->has_stencil = vk_format_has_stencil(attachment->vk_format);
376bf215546Sopenharmony_ci      if (attachment->has_stencil) {
377bf215546Sopenharmony_ci         attachment->stencil_load_op = desc->stencilLoadOp;
378bf215546Sopenharmony_ci         attachment->stencil_store_op = desc->stencilStoreOp;
379bf215546Sopenharmony_ci      }
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci      attachment->vk_format = desc->format;
382bf215546Sopenharmony_ci      attachment->sample_count = desc->samples;
383bf215546Sopenharmony_ci      attachment->initial_layout = desc->initialLayout;
384bf215546Sopenharmony_ci      attachment->is_pbe_downscalable =
385bf215546Sopenharmony_ci         pvr_format_is_pbe_downscalable(attachment->vk_format);
386bf215546Sopenharmony_ci      attachment->index = i;
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci      if (attachment->sample_count > pass->max_sample_count)
389bf215546Sopenharmony_ci         pass->max_sample_count = attachment->sample_count;
390bf215546Sopenharmony_ci   }
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   /* Count how many dependencies each subpass has. */
393bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) {
394bf215546Sopenharmony_ci      const VkSubpassDependency2 *dep = &pCreateInfo->pDependencies[i];
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci      if (dep->srcSubpass != VK_SUBPASS_EXTERNAL &&
397bf215546Sopenharmony_ci          dep->dstSubpass != VK_SUBPASS_EXTERNAL &&
398bf215546Sopenharmony_ci          dep->srcSubpass != dep->dstSubpass) {
399bf215546Sopenharmony_ci         pass->subpasses[dep->dstSubpass].dep_count++;
400bf215546Sopenharmony_ci      }
401bf215546Sopenharmony_ci   }
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci   /* Assign reference pointers to lists, and fill in the attachments list, we
404bf215546Sopenharmony_ci    * need to re-walk the dependencies array later to fill the per-subpass
405bf215546Sopenharmony_ci    * dependencies lists in.
406bf215546Sopenharmony_ci    */
407bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pass->subpass_count; i++) {
408bf215546Sopenharmony_ci      const VkSubpassDescription2 *desc = &pCreateInfo->pSubpasses[i];
409bf215546Sopenharmony_ci      struct pvr_render_subpass *subpass = &pass->subpasses[i];
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci      subpass->pipeline_bind_point = desc->pipelineBindPoint;
412bf215546Sopenharmony_ci      subpass->sample_count = 1;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci      subpass->color_count = desc->colorAttachmentCount;
415bf215546Sopenharmony_ci      if (subpass->color_count > 0) {
416bf215546Sopenharmony_ci         bool has_used_color_attachment = false;
417bf215546Sopenharmony_ci         uint32_t index;
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci         subpass->color_attachments = subpass_attachments;
420bf215546Sopenharmony_ci         subpass_attachments += subpass->color_count;
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci         for (uint32_t j = 0; j < subpass->color_count; j++) {
423bf215546Sopenharmony_ci            subpass->color_attachments[j] =
424bf215546Sopenharmony_ci               desc->pColorAttachments[j].attachment;
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci            if (subpass->color_attachments[j] == VK_ATTACHMENT_UNUSED)
427bf215546Sopenharmony_ci               continue;
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci            index = subpass->color_attachments[j];
430bf215546Sopenharmony_ci            subpass->sample_count = pass->attachments[index].sample_count;
431bf215546Sopenharmony_ci            has_used_color_attachment = true;
432bf215546Sopenharmony_ci         }
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci         if (!has_used_color_attachment && desc->pDepthStencilAttachment &&
435bf215546Sopenharmony_ci             desc->pDepthStencilAttachment->attachment !=
436bf215546Sopenharmony_ci                VK_ATTACHMENT_UNUSED) {
437bf215546Sopenharmony_ci            index = desc->pDepthStencilAttachment->attachment;
438bf215546Sopenharmony_ci            subpass->sample_count = pass->attachments[index].sample_count;
439bf215546Sopenharmony_ci         }
440bf215546Sopenharmony_ci      }
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci      if (desc->pResolveAttachments) {
443bf215546Sopenharmony_ci         subpass->resolve_attachments = subpass_attachments;
444bf215546Sopenharmony_ci         subpass_attachments += subpass->color_count;
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci         for (uint32_t j = 0; j < subpass->color_count; j++) {
447bf215546Sopenharmony_ci            subpass->resolve_attachments[j] =
448bf215546Sopenharmony_ci               desc->pResolveAttachments[j].attachment;
449bf215546Sopenharmony_ci         }
450bf215546Sopenharmony_ci      }
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci      subpass->input_count = desc->inputAttachmentCount;
453bf215546Sopenharmony_ci      if (subpass->input_count > 0) {
454bf215546Sopenharmony_ci         subpass->input_attachments = subpass_attachments;
455bf215546Sopenharmony_ci         subpass_attachments += subpass->input_count;
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci         for (uint32_t j = 0; j < subpass->input_count; j++) {
458bf215546Sopenharmony_ci            subpass->input_attachments[j] =
459bf215546Sopenharmony_ci               desc->pInputAttachments[j].attachment;
460bf215546Sopenharmony_ci         }
461bf215546Sopenharmony_ci      }
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci      if (desc->pDepthStencilAttachment) {
464bf215546Sopenharmony_ci         subpass->depth_stencil_attachment = subpass_attachments++;
465bf215546Sopenharmony_ci         *subpass->depth_stencil_attachment =
466bf215546Sopenharmony_ci            desc->pDepthStencilAttachment->attachment;
467bf215546Sopenharmony_ci      }
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci      /* Give the dependencies a slice of the subpass_attachments array. */
470bf215546Sopenharmony_ci      subpass->dep_list = dep_list;
471bf215546Sopenharmony_ci      dep_list += subpass->dep_count;
472bf215546Sopenharmony_ci      subpass->flush_on_dep = flush_on_dep;
473bf215546Sopenharmony_ci      flush_on_dep += subpass->dep_count;
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci      /* Reset the dependencies count so we can start from 0 and index into
476bf215546Sopenharmony_ci       * the dependencies array.
477bf215546Sopenharmony_ci       */
478bf215546Sopenharmony_ci      subpass->dep_count = 0;
479bf215546Sopenharmony_ci      subpass->index = i;
480bf215546Sopenharmony_ci   }
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   /* Compute dependencies and populate dep_list and flush_on_dep. */
483bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) {
484bf215546Sopenharmony_ci      const VkSubpassDependency2 *dep = &pCreateInfo->pDependencies[i];
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci      if (dep->srcSubpass != VK_SUBPASS_EXTERNAL &&
487bf215546Sopenharmony_ci          dep->dstSubpass != VK_SUBPASS_EXTERNAL &&
488bf215546Sopenharmony_ci          dep->srcSubpass != dep->dstSubpass) {
489bf215546Sopenharmony_ci         struct pvr_render_subpass *subpass = &pass->subpasses[dep->dstSubpass];
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci         subpass->dep_list[subpass->dep_count] = dep->srcSubpass;
492bf215546Sopenharmony_ci         if (pvr_subpass_has_msaa_input_attachment(subpass, pCreateInfo))
493bf215546Sopenharmony_ci            subpass->flush_on_dep[subpass->dep_count] = true;
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci         subpass->dep_count++;
496bf215546Sopenharmony_ci      }
497bf215546Sopenharmony_ci   }
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   pass->max_tilebuffer_count =
500bf215546Sopenharmony_ci      PVR_SPM_LOAD_IN_BUFFERS_COUNT(&device->pdevice->dev_info);
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci   pass->hw_setup = pvr_create_renderpass_hwsetup(device, pass, false);
503bf215546Sopenharmony_ci   if (!pass->hw_setup) {
504bf215546Sopenharmony_ci      result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
505bf215546Sopenharmony_ci      goto err_free_pass;
506bf215546Sopenharmony_ci   }
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   pvr_init_subpass_userpass_spawn(pass->hw_setup, pass, pass->subpasses);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pass->hw_setup->render_count; i++) {
511bf215546Sopenharmony_ci      struct pvr_renderpass_hwsetup_render *hw_render =
512bf215546Sopenharmony_ci         &pass->hw_setup->renders[i];
513bf215546Sopenharmony_ci      struct pvr_load_op *load_op = NULL;
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci      if (hw_render->tile_buffers_count)
516bf215546Sopenharmony_ci         pvr_finishme("Set up tile buffer table");
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci      if (!hw_render->color_init_count) {
519bf215546Sopenharmony_ci         assert(!hw_render->client_data);
520bf215546Sopenharmony_ci         continue;
521bf215546Sopenharmony_ci      }
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci      if (!pvr_has_output_register_writes(hw_render))
524bf215546Sopenharmony_ci         pvr_finishme("Add output register write");
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci      result = pvr_load_op_create(device, pAllocator, hw_render, &load_op);
527bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
528bf215546Sopenharmony_ci         goto err_load_op_destroy;
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_ci      hw_render->client_data = load_op;
531bf215546Sopenharmony_ci   }
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci   *pRenderPass = pvr_render_pass_to_handle(pass);
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   return VK_SUCCESS;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_cierr_load_op_destroy:
538bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pass->hw_setup->render_count; i++) {
539bf215546Sopenharmony_ci      struct pvr_renderpass_hwsetup_render *hw_render =
540bf215546Sopenharmony_ci         &pass->hw_setup->renders[i];
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci      if (hw_render->client_data)
543bf215546Sopenharmony_ci         pvr_load_op_destroy(device, pAllocator, hw_render->client_data);
544bf215546Sopenharmony_ci   }
545bf215546Sopenharmony_ci
546bf215546Sopenharmony_ci   pvr_destroy_renderpass_hwsetup(device, pass->hw_setup);
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_cierr_free_pass:
549bf215546Sopenharmony_ci   vk_object_base_finish(&pass->base);
550bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, pAllocator, pass);
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ci   return result;
553bf215546Sopenharmony_ci}
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_civoid pvr_DestroyRenderPass(VkDevice _device,
556bf215546Sopenharmony_ci                           VkRenderPass _pass,
557bf215546Sopenharmony_ci                           const VkAllocationCallbacks *pAllocator)
558bf215546Sopenharmony_ci{
559bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_device, device, _device);
560bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_render_pass, pass, _pass);
561bf215546Sopenharmony_ci
562bf215546Sopenharmony_ci   if (!pass)
563bf215546Sopenharmony_ci      return;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pass->hw_setup->render_count; i++) {
566bf215546Sopenharmony_ci      struct pvr_renderpass_hwsetup_render *hw_render =
567bf215546Sopenharmony_ci         &pass->hw_setup->renders[i];
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci      pvr_load_op_destroy(device, pAllocator, hw_render->client_data);
570bf215546Sopenharmony_ci   }
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci   pvr_destroy_renderpass_hwsetup(device, pass->hw_setup);
573bf215546Sopenharmony_ci   vk_object_base_finish(&pass->base);
574bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, pAllocator, pass);
575bf215546Sopenharmony_ci}
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_civoid pvr_GetRenderAreaGranularity(VkDevice _device,
578bf215546Sopenharmony_ci                                  VkRenderPass renderPass,
579bf215546Sopenharmony_ci                                  VkExtent2D *pGranularity)
580bf215546Sopenharmony_ci{
581bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_device, device, _device);
582bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci   /* Granularity does not depend on any settings in the render pass, so return
585bf215546Sopenharmony_ci    * the tile granularity.
586bf215546Sopenharmony_ci    *
587bf215546Sopenharmony_ci    * The default value is based on the minimum value found in all existing
588bf215546Sopenharmony_ci    * cores.
589bf215546Sopenharmony_ci    */
590bf215546Sopenharmony_ci   pGranularity->width = PVR_GET_FEATURE_VALUE(dev_info, tile_size_x, 16);
591bf215546Sopenharmony_ci   pGranularity->height = PVR_GET_FEATURE_VALUE(dev_info, tile_size_y, 16);
592bf215546Sopenharmony_ci}
593