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 <assert.h>
25bf215546Sopenharmony_ci#include <stdbool.h>
26bf215546Sopenharmony_ci#include <stddef.h>
27bf215546Sopenharmony_ci#include <stdint.h>
28bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "hwdef/rogue_hw_utils.h"
31bf215546Sopenharmony_ci#include "pvr_bo.h"
32bf215546Sopenharmony_ci#include "pvr_cdm_load_sr.h"
33bf215546Sopenharmony_ci#include "pvr_csb.h"
34bf215546Sopenharmony_ci#include "pvr_job_context.h"
35bf215546Sopenharmony_ci#include "pvr_pds.h"
36bf215546Sopenharmony_ci#include "pvr_private.h"
37bf215546Sopenharmony_ci#include "pvr_transfer_eot.h"
38bf215546Sopenharmony_ci#include "pvr_types.h"
39bf215546Sopenharmony_ci#include "pvr_vdm_load_sr.h"
40bf215546Sopenharmony_ci#include "pvr_vdm_store_sr.h"
41bf215546Sopenharmony_ci#include "pvr_winsys.h"
42bf215546Sopenharmony_ci#include "util/macros.h"
43bf215546Sopenharmony_ci#include "vk_alloc.h"
44bf215546Sopenharmony_ci#include "vk_log.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci/* TODO: Is there some way to ensure the Vulkan driver doesn't exceed this
47bf215546Sopenharmony_ci * value when constructing the control stream?
48bf215546Sopenharmony_ci */
49bf215546Sopenharmony_ci/* The VDM callstack is used by the hardware to implement control stream links
50bf215546Sopenharmony_ci * with a return, i.e. sub-control streams/subroutines. This value specifies the
51bf215546Sopenharmony_ci * maximum callstack depth.
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_ci#define PVR_VDM_CALLSTACK_MAX_DEPTH 1U
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci#define ROGUE_PDS_TASK_PROGRAM_SIZE 256U
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_cistatic VkResult pvr_ctx_reset_cmd_init(struct pvr_device *device,
58bf215546Sopenharmony_ci                                       struct pvr_reset_cmd *const reset_cmd)
59bf215546Sopenharmony_ci{
60bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   /* The reset framework depends on compute support in the hw. */
63bf215546Sopenharmony_ci   assert(PVR_HAS_FEATURE(dev_info, compute));
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   if (PVR_HAS_QUIRK(dev_info, 51764))
66bf215546Sopenharmony_ci      pvr_finishme("Missing reset support for brn51764");
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   if (PVR_HAS_QUIRK(dev_info, 58839))
69bf215546Sopenharmony_ci      pvr_finishme("Missing reset support for brn58839");
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   return VK_SUCCESS;
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic void pvr_ctx_reset_cmd_fini(struct pvr_device *device,
75bf215546Sopenharmony_ci                                   struct pvr_reset_cmd *reset_cmd)
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   /* TODO: reset command cleanup. */
79bf215546Sopenharmony_ci}
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_cistatic VkResult pvr_pds_pt_store_program_create_and_upload(
82bf215546Sopenharmony_ci   struct pvr_device *device,
83bf215546Sopenharmony_ci   struct pvr_bo *pt_bo,
84bf215546Sopenharmony_ci   uint32_t pt_bo_size,
85bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci   struct pvr_pds_stream_out_terminate_program program = { 0 };
88bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
89bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
90bf215546Sopenharmony_ci   size_t staging_buffer_size;
91bf215546Sopenharmony_ci   uint32_t *staging_buffer;
92bf215546Sopenharmony_ci   uint32_t *data_buffer;
93bf215546Sopenharmony_ci   uint32_t *code_buffer;
94bf215546Sopenharmony_ci   VkResult result;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   /* Check the bo size can be converted to dwords without any rounding. */
97bf215546Sopenharmony_ci   assert(pt_bo_size % 4 == 0);
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   program.pds_persistent_temp_size_to_store = pt_bo_size / 4;
100bf215546Sopenharmony_ci   program.dev_address_for_storing_persistent_temp = pt_bo->vma->dev_addr.addr;
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   pvr_pds_generate_stream_out_terminate_program(&program,
103bf215546Sopenharmony_ci                                                 NULL,
104bf215546Sopenharmony_ci                                                 PDS_GENERATE_SIZES,
105bf215546Sopenharmony_ci                                                 dev_info);
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   staging_buffer_size = (program.stream_out_terminate_pds_data_size +
108bf215546Sopenharmony_ci                          program.stream_out_terminate_pds_code_size) *
109bf215546Sopenharmony_ci                         sizeof(*staging_buffer);
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   staging_buffer = vk_zalloc(&device->vk.alloc,
112bf215546Sopenharmony_ci                              staging_buffer_size,
113bf215546Sopenharmony_ci                              8,
114bf215546Sopenharmony_ci                              VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
115bf215546Sopenharmony_ci   if (!staging_buffer)
116bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   data_buffer = staging_buffer;
119bf215546Sopenharmony_ci   code_buffer =
120bf215546Sopenharmony_ci      pvr_pds_generate_stream_out_terminate_program(&program,
121bf215546Sopenharmony_ci                                                    data_buffer,
122bf215546Sopenharmony_ci                                                    PDS_GENERATE_DATA_SEGMENT,
123bf215546Sopenharmony_ci                                                    dev_info);
124bf215546Sopenharmony_ci   pvr_pds_generate_stream_out_terminate_program(&program,
125bf215546Sopenharmony_ci                                                 code_buffer,
126bf215546Sopenharmony_ci                                                 PDS_GENERATE_CODE_SEGMENT,
127bf215546Sopenharmony_ci                                                 dev_info);
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci   /* This PDS program is passed to the HW via the PPP state words. These only
130bf215546Sopenharmony_ci    * allow the data segment address to be specified and expect the code
131bf215546Sopenharmony_ci    * segment to immediately follow. Assume the code alignment is the same as
132bf215546Sopenharmony_ci    * the data.
133bf215546Sopenharmony_ci    */
134bf215546Sopenharmony_ci   result =
135bf215546Sopenharmony_ci      pvr_gpu_upload_pds(device,
136bf215546Sopenharmony_ci                         data_buffer,
137bf215546Sopenharmony_ci                         program.stream_out_terminate_pds_data_size,
138bf215546Sopenharmony_ci                         PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE),
139bf215546Sopenharmony_ci                         code_buffer,
140bf215546Sopenharmony_ci                         program.stream_out_terminate_pds_code_size,
141bf215546Sopenharmony_ci                         PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE),
142bf215546Sopenharmony_ci                         cache_line_size,
143bf215546Sopenharmony_ci                         pds_upload_out);
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, staging_buffer);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci   return result;
148bf215546Sopenharmony_ci}
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_cistatic VkResult pvr_pds_pt_resume_program_create_and_upload(
151bf215546Sopenharmony_ci   struct pvr_device *device,
152bf215546Sopenharmony_ci   struct pvr_bo *pt_bo,
153bf215546Sopenharmony_ci   uint32_t pt_bo_size,
154bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
155bf215546Sopenharmony_ci{
156bf215546Sopenharmony_ci   struct pvr_pds_stream_out_init_program program = { 0 };
157bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
158bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
159bf215546Sopenharmony_ci   size_t staging_buffer_size;
160bf215546Sopenharmony_ci   uint32_t *staging_buffer;
161bf215546Sopenharmony_ci   uint32_t *data_buffer;
162bf215546Sopenharmony_ci   uint32_t *code_buffer;
163bf215546Sopenharmony_ci   VkResult result;
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   /* Check the bo size can be converted to dwords without any rounding. */
166bf215546Sopenharmony_ci   assert(pt_bo_size % 4 == 0);
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   program.num_buffers = 1;
169bf215546Sopenharmony_ci   program.pds_buffer_data_size[0] = pt_bo_size / 4;
170bf215546Sopenharmony_ci   program.dev_address_for_buffer_data[0] = pt_bo->vma->dev_addr.addr;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   pvr_pds_generate_stream_out_init_program(&program,
173bf215546Sopenharmony_ci                                            NULL,
174bf215546Sopenharmony_ci                                            false,
175bf215546Sopenharmony_ci                                            PDS_GENERATE_SIZES,
176bf215546Sopenharmony_ci                                            dev_info);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   staging_buffer_size = (program.stream_out_init_pds_data_size +
179bf215546Sopenharmony_ci                          program.stream_out_init_pds_code_size) *
180bf215546Sopenharmony_ci                         sizeof(*staging_buffer);
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   staging_buffer = vk_zalloc(&device->vk.alloc,
183bf215546Sopenharmony_ci                              staging_buffer_size,
184bf215546Sopenharmony_ci                              8,
185bf215546Sopenharmony_ci                              VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
186bf215546Sopenharmony_ci   if (!staging_buffer)
187bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   data_buffer = staging_buffer;
190bf215546Sopenharmony_ci   code_buffer =
191bf215546Sopenharmony_ci      pvr_pds_generate_stream_out_init_program(&program,
192bf215546Sopenharmony_ci                                               data_buffer,
193bf215546Sopenharmony_ci                                               false,
194bf215546Sopenharmony_ci                                               PDS_GENERATE_DATA_SEGMENT,
195bf215546Sopenharmony_ci                                               dev_info);
196bf215546Sopenharmony_ci   pvr_pds_generate_stream_out_init_program(&program,
197bf215546Sopenharmony_ci                                            code_buffer,
198bf215546Sopenharmony_ci                                            false,
199bf215546Sopenharmony_ci                                            PDS_GENERATE_CODE_SEGMENT,
200bf215546Sopenharmony_ci                                            dev_info);
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   /* This PDS program is passed to the HW via the PPP state words. These only
203bf215546Sopenharmony_ci    * allow the data segment address to be specified and expect the code
204bf215546Sopenharmony_ci    * segment to immediately follow. Assume the code alignment is the same as
205bf215546Sopenharmony_ci    * the data.
206bf215546Sopenharmony_ci    */
207bf215546Sopenharmony_ci   result =
208bf215546Sopenharmony_ci      pvr_gpu_upload_pds(device,
209bf215546Sopenharmony_ci                         data_buffer,
210bf215546Sopenharmony_ci                         program.stream_out_init_pds_data_size,
211bf215546Sopenharmony_ci                         PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE),
212bf215546Sopenharmony_ci                         code_buffer,
213bf215546Sopenharmony_ci                         program.stream_out_init_pds_code_size,
214bf215546Sopenharmony_ci                         PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE),
215bf215546Sopenharmony_ci                         cache_line_size,
216bf215546Sopenharmony_ci                         pds_upload_out);
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, staging_buffer);
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   return result;
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_cistatic VkResult
224bf215546Sopenharmony_cipvr_render_job_pt_programs_setup(struct pvr_device *device,
225bf215546Sopenharmony_ci                                 struct rogue_pt_programs *pt_programs)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   VkResult result;
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
230bf215546Sopenharmony_ci                         device->heaps.pds_heap,
231bf215546Sopenharmony_ci                         ROGUE_LLS_PDS_PERSISTENT_TEMPS_BUFFER_SIZE,
232bf215546Sopenharmony_ci                         ROGUE_LLS_PDS_PERSISTENT_TEMPS_BUFFER_ALIGNMENT,
233bf215546Sopenharmony_ci                         PVR_BO_ALLOC_FLAG_CPU_ACCESS,
234bf215546Sopenharmony_ci                         &pt_programs->store_resume_state_bo);
235bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
236bf215546Sopenharmony_ci      return result;
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   result = pvr_pds_pt_store_program_create_and_upload(
239bf215546Sopenharmony_ci      device,
240bf215546Sopenharmony_ci      pt_programs->store_resume_state_bo,
241bf215546Sopenharmony_ci      ROGUE_LLS_PDS_PERSISTENT_TEMPS_BUFFER_SIZE,
242bf215546Sopenharmony_ci      &pt_programs->pds_store_program);
243bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
244bf215546Sopenharmony_ci      goto err_free_store_resume_state_bo;
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   result = pvr_pds_pt_resume_program_create_and_upload(
247bf215546Sopenharmony_ci      device,
248bf215546Sopenharmony_ci      pt_programs->store_resume_state_bo,
249bf215546Sopenharmony_ci      ROGUE_LLS_PDS_PERSISTENT_TEMPS_BUFFER_SIZE,
250bf215546Sopenharmony_ci      &pt_programs->pds_resume_program);
251bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
252bf215546Sopenharmony_ci      goto err_free_pds_store_program;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   return VK_SUCCESS;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_cierr_free_pds_store_program:
257bf215546Sopenharmony_ci   pvr_bo_free(device, pt_programs->pds_store_program.pvr_bo);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_cierr_free_store_resume_state_bo:
260bf215546Sopenharmony_ci   pvr_bo_free(device, pt_programs->store_resume_state_bo);
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   return result;
263bf215546Sopenharmony_ci}
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_cistatic void
266bf215546Sopenharmony_cipvr_render_job_pt_programs_cleanup(struct pvr_device *device,
267bf215546Sopenharmony_ci                                   struct rogue_pt_programs *pt_programs)
268bf215546Sopenharmony_ci{
269bf215546Sopenharmony_ci   pvr_bo_free(device, pt_programs->pds_resume_program.pvr_bo);
270bf215546Sopenharmony_ci   pvr_bo_free(device, pt_programs->pds_store_program.pvr_bo);
271bf215546Sopenharmony_ci   pvr_bo_free(device, pt_programs->store_resume_state_bo);
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_cistatic void pvr_pds_ctx_sr_program_setup(
275bf215546Sopenharmony_ci   bool cc_enable,
276bf215546Sopenharmony_ci   uint64_t usc_program_upload_offset,
277bf215546Sopenharmony_ci   uint8_t usc_temps,
278bf215546Sopenharmony_ci   pvr_dev_addr_t sr_addr,
279bf215546Sopenharmony_ci   struct pvr_pds_shared_storing_program *const program_out)
280bf215546Sopenharmony_ci{
281bf215546Sopenharmony_ci   /* The PDS task is the same for stores and loads. */
282bf215546Sopenharmony_ci   *program_out = (struct pvr_pds_shared_storing_program){
283bf215546Sopenharmony_ci		.cc_enable = cc_enable,
284bf215546Sopenharmony_ci		.doutw_control = {
285bf215546Sopenharmony_ci			.dest_store = PDS_UNIFIED_STORE,
286bf215546Sopenharmony_ci			.num_const64 = 2,
287bf215546Sopenharmony_ci			.doutw_data = {
288bf215546Sopenharmony_ci				[0] = sr_addr.addr,
289bf215546Sopenharmony_ci				[1] = sr_addr.addr + ROGUE_LLS_SHARED_REGS_RESERVE_SIZE,
290bf215546Sopenharmony_ci			},
291bf215546Sopenharmony_ci			.last_instruction = false,
292bf215546Sopenharmony_ci		},
293bf215546Sopenharmony_ci	};
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   pvr_pds_setup_doutu(&program_out->usc_task.usc_task_control,
296bf215546Sopenharmony_ci                       usc_program_upload_offset,
297bf215546Sopenharmony_ci                       usc_temps,
298bf215546Sopenharmony_ci                       PVRX(PDSINST_DOUTU_SAMPLE_RATE_INSTANCE),
299bf215546Sopenharmony_ci                       false);
300bf215546Sopenharmony_ci}
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci/* Note: pvr_pds_compute_ctx_sr_program_create_and_upload() is very similar to
303bf215546Sopenharmony_ci * this. If there is a problem here it's likely that the same problem exists
304bf215546Sopenharmony_ci * there so don't forget to update the compute function.
305bf215546Sopenharmony_ci */
306bf215546Sopenharmony_cistatic VkResult pvr_pds_render_ctx_sr_program_create_and_upload(
307bf215546Sopenharmony_ci   struct pvr_device *device,
308bf215546Sopenharmony_ci   uint64_t usc_program_upload_offset,
309bf215546Sopenharmony_ci   uint8_t usc_temps,
310bf215546Sopenharmony_ci   pvr_dev_addr_t sr_addr,
311bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
312bf215546Sopenharmony_ci{
313bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
314bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
315bf215546Sopenharmony_ci   const uint32_t pds_data_alignment =
316bf215546Sopenharmony_ci      PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) / 4U;
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   /* FIXME: pvr_pds_generate_shared_storing_program() doesn't return the data
319bf215546Sopenharmony_ci    * and code size when using the PDS_GENERATE_SIZES mode.
320bf215546Sopenharmony_ci    */
321bf215546Sopenharmony_ci   STATIC_ASSERT(ROGUE_PDS_TASK_PROGRAM_SIZE % 4 == 0);
322bf215546Sopenharmony_ci   uint32_t staging_buffer[ROGUE_PDS_TASK_PROGRAM_SIZE / 4U] = { 0 };
323bf215546Sopenharmony_ci   struct pvr_pds_shared_storing_program program;
324bf215546Sopenharmony_ci   ASSERTED uint32_t *buffer_end;
325bf215546Sopenharmony_ci   uint32_t code_offset;
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   pvr_pds_ctx_sr_program_setup(false,
328bf215546Sopenharmony_ci                                usc_program_upload_offset,
329bf215546Sopenharmony_ci                                usc_temps,
330bf215546Sopenharmony_ci                                sr_addr,
331bf215546Sopenharmony_ci                                &program);
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci   pvr_pds_generate_shared_storing_program(&program,
334bf215546Sopenharmony_ci                                           &staging_buffer[0],
335bf215546Sopenharmony_ci                                           PDS_GENERATE_DATA_SEGMENT,
336bf215546Sopenharmony_ci                                           dev_info);
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   code_offset = ALIGN_POT(program.data_size, pds_data_alignment);
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci   buffer_end =
341bf215546Sopenharmony_ci      pvr_pds_generate_shared_storing_program(&program,
342bf215546Sopenharmony_ci                                              &staging_buffer[code_offset],
343bf215546Sopenharmony_ci                                              PDS_GENERATE_CODE_SEGMENT,
344bf215546Sopenharmony_ci                                              dev_info);
345bf215546Sopenharmony_ci
346bf215546Sopenharmony_ci   assert((uint32_t)(buffer_end - staging_buffer) * 4 <
347bf215546Sopenharmony_ci          ROGUE_PDS_TASK_PROGRAM_SIZE);
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   return pvr_gpu_upload_pds(device,
350bf215546Sopenharmony_ci                             &staging_buffer[0],
351bf215546Sopenharmony_ci                             program.data_size,
352bf215546Sopenharmony_ci                             PVRX(VDMCTRL_PDS_STATE1_PDS_DATA_ADDR_ALIGNMENT),
353bf215546Sopenharmony_ci                             &staging_buffer[code_offset],
354bf215546Sopenharmony_ci                             program.code_size,
355bf215546Sopenharmony_ci                             PVRX(VDMCTRL_PDS_STATE2_PDS_CODE_ADDR_ALIGNMENT),
356bf215546Sopenharmony_ci                             cache_line_size,
357bf215546Sopenharmony_ci                             pds_upload_out);
358bf215546Sopenharmony_ci}
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci/* Note: pvr_pds_render_ctx_sr_program_create_and_upload() is very similar to
361bf215546Sopenharmony_ci * this. If there is a problem here it's likely that the same problem exists
362bf215546Sopenharmony_ci * there so don't forget to update the render_ctx function.
363bf215546Sopenharmony_ci */
364bf215546Sopenharmony_cistatic VkResult pvr_pds_compute_ctx_sr_program_create_and_upload(
365bf215546Sopenharmony_ci   struct pvr_device *device,
366bf215546Sopenharmony_ci   bool is_loading_program,
367bf215546Sopenharmony_ci   uint64_t usc_program_upload_offset,
368bf215546Sopenharmony_ci   uint8_t usc_temps,
369bf215546Sopenharmony_ci   pvr_dev_addr_t sr_addr,
370bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
371bf215546Sopenharmony_ci{
372bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
373bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
374bf215546Sopenharmony_ci   const uint32_t pds_data_alignment =
375bf215546Sopenharmony_ci      PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) / 4U;
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   /* FIXME: pvr_pds_generate_shared_storing_program() doesn't return the data
378bf215546Sopenharmony_ci    * and code size when using the PDS_GENERATE_SIZES mode.
379bf215546Sopenharmony_ci    */
380bf215546Sopenharmony_ci   STATIC_ASSERT(ROGUE_PDS_TASK_PROGRAM_SIZE % 4 == 0);
381bf215546Sopenharmony_ci   uint32_t staging_buffer[ROGUE_PDS_TASK_PROGRAM_SIZE / 4U] = { 0 };
382bf215546Sopenharmony_ci   struct pvr_pds_shared_storing_program program;
383bf215546Sopenharmony_ci   uint32_t *buffer_ptr;
384bf215546Sopenharmony_ci   uint32_t code_offset;
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci   pvr_pds_ctx_sr_program_setup(PVR_HAS_ERN(dev_info, 35421),
387bf215546Sopenharmony_ci                                usc_program_upload_offset,
388bf215546Sopenharmony_ci                                usc_temps,
389bf215546Sopenharmony_ci                                sr_addr,
390bf215546Sopenharmony_ci                                &program);
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   if (is_loading_program && PVR_NEED_SW_COMPUTE_PDS_BARRIER(dev_info)) {
393bf215546Sopenharmony_ci      pvr_pds_generate_compute_shared_loading_program(&program,
394bf215546Sopenharmony_ci                                                      &staging_buffer[0],
395bf215546Sopenharmony_ci                                                      PDS_GENERATE_DATA_SEGMENT,
396bf215546Sopenharmony_ci                                                      dev_info);
397bf215546Sopenharmony_ci   } else {
398bf215546Sopenharmony_ci      pvr_pds_generate_shared_storing_program(&program,
399bf215546Sopenharmony_ci                                              &staging_buffer[0],
400bf215546Sopenharmony_ci                                              PDS_GENERATE_DATA_SEGMENT,
401bf215546Sopenharmony_ci                                              dev_info);
402bf215546Sopenharmony_ci   }
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   code_offset = ALIGN_POT(program.data_size, pds_data_alignment);
405bf215546Sopenharmony_ci
406bf215546Sopenharmony_ci   buffer_ptr =
407bf215546Sopenharmony_ci      pvr_pds_generate_compute_barrier_conditional(&staging_buffer[code_offset],
408bf215546Sopenharmony_ci                                                   PDS_GENERATE_CODE_SEGMENT);
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci   if (is_loading_program && PVR_NEED_SW_COMPUTE_PDS_BARRIER(dev_info)) {
411bf215546Sopenharmony_ci      buffer_ptr = pvr_pds_generate_compute_shared_loading_program(
412bf215546Sopenharmony_ci         &program,
413bf215546Sopenharmony_ci         buffer_ptr,
414bf215546Sopenharmony_ci         PDS_GENERATE_CODE_SEGMENT,
415bf215546Sopenharmony_ci         dev_info);
416bf215546Sopenharmony_ci   } else {
417bf215546Sopenharmony_ci      buffer_ptr =
418bf215546Sopenharmony_ci         pvr_pds_generate_shared_storing_program(&program,
419bf215546Sopenharmony_ci                                                 buffer_ptr,
420bf215546Sopenharmony_ci                                                 PDS_GENERATE_CODE_SEGMENT,
421bf215546Sopenharmony_ci                                                 dev_info);
422bf215546Sopenharmony_ci   }
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   assert((uint32_t)(buffer_ptr - staging_buffer) * 4 <
425bf215546Sopenharmony_ci          ROGUE_PDS_TASK_PROGRAM_SIZE);
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   STATIC_ASSERT(PVRX(CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNMENT) ==
428bf215546Sopenharmony_ci                 PVRX(CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_ALIGNMENT));
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   STATIC_ASSERT(PVRX(CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNMENT) ==
431bf215546Sopenharmony_ci                 PVRX(CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_ALIGNMENT));
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   return pvr_gpu_upload_pds(
434bf215546Sopenharmony_ci      device,
435bf215546Sopenharmony_ci      &staging_buffer[0],
436bf215546Sopenharmony_ci      program.data_size,
437bf215546Sopenharmony_ci      PVRX(CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNMENT),
438bf215546Sopenharmony_ci      &staging_buffer[code_offset],
439bf215546Sopenharmony_ci      (uint32_t)(buffer_ptr - &staging_buffer[code_offset]),
440bf215546Sopenharmony_ci      PVRX(CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNMENT),
441bf215546Sopenharmony_ci      cache_line_size,
442bf215546Sopenharmony_ci      pds_upload_out);
443bf215546Sopenharmony_ci}
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_cienum pvr_ctx_sr_program_target {
446bf215546Sopenharmony_ci   PVR_CTX_SR_RENDER_TARGET,
447bf215546Sopenharmony_ci   PVR_CTX_SR_COMPUTE_TARGET,
448bf215546Sopenharmony_ci};
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_cistatic VkResult pvr_ctx_sr_programs_setup(struct pvr_device *device,
451bf215546Sopenharmony_ci                                          enum pvr_ctx_sr_program_target target,
452bf215546Sopenharmony_ci                                          struct rogue_sr_programs *sr_programs)
453bf215546Sopenharmony_ci{
454bf215546Sopenharmony_ci   const uint64_t store_load_state_bo_size =
455bf215546Sopenharmony_ci      PVRX(LLS_USC_SHARED_REGS_BUFFER_SIZE) +
456bf215546Sopenharmony_ci      ROGUE_LLS_SHARED_REGS_RESERVE_SIZE;
457bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
458bf215546Sopenharmony_ci   const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
459bf215546Sopenharmony_ci   uint64_t usc_store_program_upload_offset;
460bf215546Sopenharmony_ci   uint64_t usc_load_program_upload_offset;
461bf215546Sopenharmony_ci   const uint8_t *usc_load_sr_code;
462bf215546Sopenharmony_ci   uint32_t usc_load_sr_code_size;
463bf215546Sopenharmony_ci   VkResult result;
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci   /* Note that this is being used for both compute and render ctx. There is no
466bf215546Sopenharmony_ci    * compute equivalent define for the VDMCTRL unit size.
467bf215546Sopenharmony_ci    */
468bf215546Sopenharmony_ci   /* 4 blocks (16 dwords / 64 bytes) in USC to prevent fragmentation. */
469bf215546Sopenharmony_ci   sr_programs->usc.unified_size =
470bf215546Sopenharmony_ci      DIV_ROUND_UP(64, PVRX(VDMCTRL_PDS_STATE0_USC_UNIFIED_SIZE_UNIT_SIZE));
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
473bf215546Sopenharmony_ci                         device->heaps.pds_heap,
474bf215546Sopenharmony_ci                         store_load_state_bo_size,
475bf215546Sopenharmony_ci                         cache_line_size,
476bf215546Sopenharmony_ci                         PVR_WINSYS_BO_FLAG_CPU_ACCESS,
477bf215546Sopenharmony_ci                         &sr_programs->store_load_state_bo);
478bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
479bf215546Sopenharmony_ci      return result;
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   /* USC state update: SR state store. */
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   assert(sizeof(pvr_vdm_store_sr_code) < ROGUE_USC_TASK_PROGRAM_SIZE);
484bf215546Sopenharmony_ci
485bf215546Sopenharmony_ci   result = pvr_gpu_upload_usc(device,
486bf215546Sopenharmony_ci                               pvr_vdm_store_sr_code,
487bf215546Sopenharmony_ci                               sizeof(pvr_vdm_store_sr_code),
488bf215546Sopenharmony_ci                               cache_line_size,
489bf215546Sopenharmony_ci                               &sr_programs->usc.store_program_bo);
490bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
491bf215546Sopenharmony_ci      goto err_free_store_load_state_bo;
492bf215546Sopenharmony_ci
493bf215546Sopenharmony_ci   usc_store_program_upload_offset =
494bf215546Sopenharmony_ci      sr_programs->usc.store_program_bo->vma->dev_addr.addr -
495bf215546Sopenharmony_ci      device->heaps.usc_heap->base_addr.addr;
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   /* USC state update: SR state load. */
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   if (target == PVR_CTX_SR_COMPUTE_TARGET && PVR_HAS_QUIRK(dev_info, 62269)) {
500bf215546Sopenharmony_ci      STATIC_ASSERT(sizeof(pvr_cdm_load_sr_code) < ROGUE_USC_TASK_PROGRAM_SIZE);
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci      usc_load_sr_code = pvr_cdm_load_sr_code;
503bf215546Sopenharmony_ci      usc_load_sr_code_size = sizeof(pvr_cdm_load_sr_code);
504bf215546Sopenharmony_ci   } else {
505bf215546Sopenharmony_ci      STATIC_ASSERT(sizeof(pvr_vdm_load_sr_code) < ROGUE_USC_TASK_PROGRAM_SIZE);
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci      usc_load_sr_code = pvr_vdm_load_sr_code;
508bf215546Sopenharmony_ci      usc_load_sr_code_size = sizeof(pvr_vdm_load_sr_code);
509bf215546Sopenharmony_ci   }
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   result = pvr_gpu_upload_usc(device,
512bf215546Sopenharmony_ci                               usc_load_sr_code,
513bf215546Sopenharmony_ci                               usc_load_sr_code_size,
514bf215546Sopenharmony_ci                               cache_line_size,
515bf215546Sopenharmony_ci                               &sr_programs->usc.load_program_bo);
516bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
517bf215546Sopenharmony_ci      goto err_free_usc_store_program_bo;
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   usc_load_program_upload_offset =
520bf215546Sopenharmony_ci      sr_programs->usc.load_program_bo->vma->dev_addr.addr -
521bf215546Sopenharmony_ci      device->heaps.usc_heap->base_addr.addr;
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   /* FIXME: The number of USC temps should be output alongside
524bf215546Sopenharmony_ci    * pvr_vdm_store_sr_code rather than hard coded.
525bf215546Sopenharmony_ci    */
526bf215546Sopenharmony_ci   /* Create and upload the PDS load and store programs. Point them to the
527bf215546Sopenharmony_ci    * appropriate USC load and store programs.
528bf215546Sopenharmony_ci    */
529bf215546Sopenharmony_ci   switch (target) {
530bf215546Sopenharmony_ci   case PVR_CTX_SR_RENDER_TARGET:
531bf215546Sopenharmony_ci      /* PDS state update: SR state store. */
532bf215546Sopenharmony_ci      result = pvr_pds_render_ctx_sr_program_create_and_upload(
533bf215546Sopenharmony_ci         device,
534bf215546Sopenharmony_ci         usc_store_program_upload_offset,
535bf215546Sopenharmony_ci         8,
536bf215546Sopenharmony_ci         sr_programs->store_load_state_bo->vma->dev_addr,
537bf215546Sopenharmony_ci         &sr_programs->pds.store_program);
538bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
539bf215546Sopenharmony_ci         goto err_free_usc_load_program_bo;
540bf215546Sopenharmony_ci
541bf215546Sopenharmony_ci      /* PDS state update: SR state load. */
542bf215546Sopenharmony_ci      result = pvr_pds_render_ctx_sr_program_create_and_upload(
543bf215546Sopenharmony_ci         device,
544bf215546Sopenharmony_ci         usc_load_program_upload_offset,
545bf215546Sopenharmony_ci         20,
546bf215546Sopenharmony_ci         sr_programs->store_load_state_bo->vma->dev_addr,
547bf215546Sopenharmony_ci         &sr_programs->pds.load_program);
548bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
549bf215546Sopenharmony_ci         goto err_free_pds_store_program_bo;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci      break;
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   case PVR_CTX_SR_COMPUTE_TARGET:
554bf215546Sopenharmony_ci      /* PDS state update: SR state store. */
555bf215546Sopenharmony_ci      result = pvr_pds_compute_ctx_sr_program_create_and_upload(
556bf215546Sopenharmony_ci         device,
557bf215546Sopenharmony_ci         false,
558bf215546Sopenharmony_ci         usc_store_program_upload_offset,
559bf215546Sopenharmony_ci         8,
560bf215546Sopenharmony_ci         sr_programs->store_load_state_bo->vma->dev_addr,
561bf215546Sopenharmony_ci         &sr_programs->pds.store_program);
562bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
563bf215546Sopenharmony_ci         goto err_free_usc_load_program_bo;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_ci      /* PDS state update: SR state load. */
566bf215546Sopenharmony_ci      result = pvr_pds_compute_ctx_sr_program_create_and_upload(
567bf215546Sopenharmony_ci         device,
568bf215546Sopenharmony_ci         true,
569bf215546Sopenharmony_ci         usc_load_program_upload_offset,
570bf215546Sopenharmony_ci         20,
571bf215546Sopenharmony_ci         sr_programs->store_load_state_bo->vma->dev_addr,
572bf215546Sopenharmony_ci         &sr_programs->pds.load_program);
573bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
574bf215546Sopenharmony_ci         goto err_free_pds_store_program_bo;
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci      break;
577bf215546Sopenharmony_ci
578bf215546Sopenharmony_ci   default:
579bf215546Sopenharmony_ci      unreachable("Invalid target.");
580bf215546Sopenharmony_ci      break;
581bf215546Sopenharmony_ci   }
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   return VK_SUCCESS;
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_cierr_free_pds_store_program_bo:
586bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->pds.store_program.pvr_bo);
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_cierr_free_usc_load_program_bo:
589bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->usc.load_program_bo);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_cierr_free_usc_store_program_bo:
592bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->usc.store_program_bo);
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_cierr_free_store_load_state_bo:
595bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->store_load_state_bo);
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   return VK_SUCCESS;
598bf215546Sopenharmony_ci}
599bf215546Sopenharmony_ci
600bf215546Sopenharmony_cistatic void pvr_ctx_sr_programs_cleanup(struct pvr_device *device,
601bf215546Sopenharmony_ci                                        struct rogue_sr_programs *sr_programs)
602bf215546Sopenharmony_ci{
603bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->pds.load_program.pvr_bo);
604bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->pds.store_program.pvr_bo);
605bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->usc.load_program_bo);
606bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->usc.store_program_bo);
607bf215546Sopenharmony_ci   pvr_bo_free(device, sr_programs->store_load_state_bo);
608bf215546Sopenharmony_ci}
609bf215546Sopenharmony_ci
610bf215546Sopenharmony_cistatic VkResult
611bf215546Sopenharmony_cipvr_render_ctx_switch_programs_setup(struct pvr_device *device,
612bf215546Sopenharmony_ci                                     struct pvr_render_ctx_programs *programs)
613bf215546Sopenharmony_ci{
614bf215546Sopenharmony_ci   VkResult result;
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci   result = pvr_render_job_pt_programs_setup(device, &programs->pt);
617bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
618bf215546Sopenharmony_ci      return result;
619bf215546Sopenharmony_ci
620bf215546Sopenharmony_ci   result = pvr_ctx_sr_programs_setup(device,
621bf215546Sopenharmony_ci                                      PVR_CTX_SR_RENDER_TARGET,
622bf215546Sopenharmony_ci                                      &programs->sr);
623bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
624bf215546Sopenharmony_ci      goto err_pt_programs_cleanup;
625bf215546Sopenharmony_ci
626bf215546Sopenharmony_ci   return VK_SUCCESS;
627bf215546Sopenharmony_ci
628bf215546Sopenharmony_cierr_pt_programs_cleanup:
629bf215546Sopenharmony_ci   pvr_render_job_pt_programs_cleanup(device, &programs->pt);
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_ci   return result;
632bf215546Sopenharmony_ci}
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_cistatic void
635bf215546Sopenharmony_cipvr_render_ctx_switch_programs_cleanup(struct pvr_device *device,
636bf215546Sopenharmony_ci                                       struct pvr_render_ctx_programs *programs)
637bf215546Sopenharmony_ci{
638bf215546Sopenharmony_ci   pvr_ctx_sr_programs_cleanup(device, &programs->sr);
639bf215546Sopenharmony_ci   pvr_render_job_pt_programs_cleanup(device, &programs->pt);
640bf215546Sopenharmony_ci}
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_cistatic VkResult pvr_render_ctx_switch_init(struct pvr_device *device,
643bf215546Sopenharmony_ci                                           struct pvr_render_ctx *ctx)
644bf215546Sopenharmony_ci{
645bf215546Sopenharmony_ci   struct pvr_render_ctx_switch *ctx_switch = &ctx->ctx_switch;
646bf215546Sopenharmony_ci   const uint64_t vdm_state_bo_flags = PVR_BO_ALLOC_FLAG_GPU_UNCACHED |
647bf215546Sopenharmony_ci                                       PVR_BO_ALLOC_FLAG_CPU_ACCESS;
648bf215546Sopenharmony_ci   const uint64_t geom_state_bo_flags = PVR_BO_ALLOC_FLAG_GPU_UNCACHED |
649bf215546Sopenharmony_ci                                        PVR_BO_ALLOC_FLAG_CPU_ACCESS;
650bf215546Sopenharmony_ci   VkResult result;
651bf215546Sopenharmony_ci
652bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
653bf215546Sopenharmony_ci                         device->heaps.general_heap,
654bf215546Sopenharmony_ci                         ROGUE_LLS_VDM_CONTEXT_RESUME_BUFFER_SIZE,
655bf215546Sopenharmony_ci                         ROGUE_LLS_VDM_CONTEXT_RESUME_BUFFER_ALIGNMENT,
656bf215546Sopenharmony_ci                         vdm_state_bo_flags,
657bf215546Sopenharmony_ci                         &ctx_switch->vdm_state_bo);
658bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
659bf215546Sopenharmony_ci      return result;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
662bf215546Sopenharmony_ci                         device->heaps.general_heap,
663bf215546Sopenharmony_ci                         ROGUE_LLS_TA_STATE_BUFFER_SIZE,
664bf215546Sopenharmony_ci                         ROGUE_LLS_TA_STATE_BUFFER_ALIGNMENT,
665bf215546Sopenharmony_ci                         geom_state_bo_flags,
666bf215546Sopenharmony_ci                         &ctx_switch->geom_state_bo);
667bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
668bf215546Sopenharmony_ci      goto err_pvr_bo_free_vdm_state_bo;
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx_switch->programs); i++) {
671bf215546Sopenharmony_ci      result =
672bf215546Sopenharmony_ci         pvr_render_ctx_switch_programs_setup(device, &ctx_switch->programs[i]);
673bf215546Sopenharmony_ci      if (result)
674bf215546Sopenharmony_ci         goto err_programs_cleanup;
675bf215546Sopenharmony_ci   }
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ci   return result;
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_cierr_programs_cleanup:
680bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx_switch->programs); i++) {
681bf215546Sopenharmony_ci      pvr_render_ctx_switch_programs_cleanup(device, &ctx_switch->programs[i]);
682bf215546Sopenharmony_ci   }
683bf215546Sopenharmony_ci
684bf215546Sopenharmony_ci   pvr_bo_free(device, ctx_switch->geom_state_bo);
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_cierr_pvr_bo_free_vdm_state_bo:
687bf215546Sopenharmony_ci   pvr_bo_free(device, ctx_switch->vdm_state_bo);
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci   return result;
690bf215546Sopenharmony_ci}
691bf215546Sopenharmony_ci
692bf215546Sopenharmony_cistatic void pvr_render_ctx_switch_fini(struct pvr_device *device,
693bf215546Sopenharmony_ci                                       struct pvr_render_ctx *ctx)
694bf215546Sopenharmony_ci{
695bf215546Sopenharmony_ci   struct pvr_render_ctx_switch *ctx_switch = &ctx->ctx_switch;
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx_switch->programs); i++) {
698bf215546Sopenharmony_ci      pvr_render_ctx_switch_programs_cleanup(device, &ctx_switch->programs[i]);
699bf215546Sopenharmony_ci   }
700bf215546Sopenharmony_ci
701bf215546Sopenharmony_ci   pvr_bo_free(device, ctx_switch->geom_state_bo);
702bf215546Sopenharmony_ci   pvr_bo_free(device, ctx_switch->vdm_state_bo);
703bf215546Sopenharmony_ci}
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_cistatic void
706bf215546Sopenharmony_cipvr_rogue_get_vdmctrl_pds_state_words(struct pvr_pds_upload *pds_program,
707bf215546Sopenharmony_ci                                      enum PVRX(VDMCTRL_USC_TARGET) usc_target,
708bf215546Sopenharmony_ci                                      uint8_t usc_unified_size,
709bf215546Sopenharmony_ci                                      uint32_t *const state0_out,
710bf215546Sopenharmony_ci                                      uint32_t *const state1_out)
711bf215546Sopenharmony_ci{
712bf215546Sopenharmony_ci   pvr_csb_pack (state0_out, VDMCTRL_PDS_STATE0, state) {
713bf215546Sopenharmony_ci      /* Convert the data size from dwords to bytes. */
714bf215546Sopenharmony_ci      const uint32_t pds_data_size = pds_program->data_size * 4;
715bf215546Sopenharmony_ci
716bf215546Sopenharmony_ci      state.dm_target = PVRX(VDMCTRL_DM_TARGET_VDM);
717bf215546Sopenharmony_ci      state.usc_target = usc_target;
718bf215546Sopenharmony_ci      state.usc_common_size = 0;
719bf215546Sopenharmony_ci      state.usc_unified_size = usc_unified_size;
720bf215546Sopenharmony_ci      state.pds_temp_size = 0;
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci      assert(pds_data_size % PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) ==
723bf215546Sopenharmony_ci             0);
724bf215546Sopenharmony_ci      state.pds_data_size =
725bf215546Sopenharmony_ci         pds_data_size / PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE);
726bf215546Sopenharmony_ci   };
727bf215546Sopenharmony_ci
728bf215546Sopenharmony_ci   pvr_csb_pack (state1_out, VDMCTRL_PDS_STATE1, state) {
729bf215546Sopenharmony_ci      state.pds_data_addr = PVR_DEV_ADDR(pds_program->data_offset);
730bf215546Sopenharmony_ci      state.sd_type = PVRX(VDMCTRL_SD_TYPE_PDS);
731bf215546Sopenharmony_ci      state.sd_next_type = PVRX(VDMCTRL_SD_TYPE_PDS);
732bf215546Sopenharmony_ci   }
733bf215546Sopenharmony_ci}
734bf215546Sopenharmony_ci
735bf215546Sopenharmony_cistatic void
736bf215546Sopenharmony_cipvr_rogue_get_geom_state_stream_out_words(struct pvr_pds_upload *pds_program,
737bf215546Sopenharmony_ci                                          uint32_t *const stream_out1_out,
738bf215546Sopenharmony_ci                                          uint32_t *const stream_out2_out)
739bf215546Sopenharmony_ci{
740bf215546Sopenharmony_ci   pvr_csb_pack (stream_out1_out, TA_STATE_STREAM_OUT1, state) {
741bf215546Sopenharmony_ci      /* Convert the data size from dwords to bytes. */
742bf215546Sopenharmony_ci      const uint32_t pds_data_size = pds_program->data_size * 4;
743bf215546Sopenharmony_ci
744bf215546Sopenharmony_ci      state.sync = true;
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci      assert(pds_data_size %
747bf215546Sopenharmony_ci                PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE) ==
748bf215546Sopenharmony_ci             0);
749bf215546Sopenharmony_ci      state.pds_data_size =
750bf215546Sopenharmony_ci         pds_data_size / PVRX(TA_STATE_STREAM_OUT1_PDS_DATA_SIZE_UNIT_SIZE);
751bf215546Sopenharmony_ci
752bf215546Sopenharmony_ci      state.pds_temp_size = 0;
753bf215546Sopenharmony_ci   }
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci   pvr_csb_pack (stream_out2_out, TA_STATE_STREAM_OUT2, state) {
756bf215546Sopenharmony_ci      state.pds_data_addr = PVR_DEV_ADDR(pds_program->data_offset);
757bf215546Sopenharmony_ci   }
758bf215546Sopenharmony_ci}
759bf215546Sopenharmony_ci
760bf215546Sopenharmony_cistatic void pvr_render_ctx_ws_static_state_init(
761bf215546Sopenharmony_ci   struct pvr_render_ctx *ctx,
762bf215546Sopenharmony_ci   struct pvr_winsys_render_ctx_static_state *static_state)
763bf215546Sopenharmony_ci{
764bf215546Sopenharmony_ci   uint64_t *q_dst;
765bf215546Sopenharmony_ci   uint32_t *d_dst;
766bf215546Sopenharmony_ci
767bf215546Sopenharmony_ci   q_dst = &static_state->vdm_ctx_state_base_addr;
768bf215546Sopenharmony_ci   pvr_csb_pack (q_dst, CR_VDM_CONTEXT_STATE_BASE, base) {
769bf215546Sopenharmony_ci      base.addr = ctx->ctx_switch.vdm_state_bo->vma->dev_addr;
770bf215546Sopenharmony_ci   }
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_ci   q_dst = &static_state->geom_ctx_state_base_addr;
773bf215546Sopenharmony_ci   pvr_csb_pack (q_dst, CR_TA_CONTEXT_STATE_BASE, base) {
774bf215546Sopenharmony_ci      base.addr = ctx->ctx_switch.geom_state_bo->vma->dev_addr;
775bf215546Sopenharmony_ci   }
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx->ctx_switch.programs); i++) {
778bf215546Sopenharmony_ci      struct rogue_pt_programs *pt_prog = &ctx->ctx_switch.programs[i].pt;
779bf215546Sopenharmony_ci      struct rogue_sr_programs *sr_prog = &ctx->ctx_switch.programs[i].sr;
780bf215546Sopenharmony_ci
781bf215546Sopenharmony_ci      /* Context store state. */
782bf215546Sopenharmony_ci      q_dst = &static_state->geom_state[i].vdm_ctx_store_task0;
783bf215546Sopenharmony_ci      pvr_csb_pack (q_dst, CR_VDM_CONTEXT_STORE_TASK0, task0) {
784bf215546Sopenharmony_ci         pvr_rogue_get_vdmctrl_pds_state_words(&sr_prog->pds.store_program,
785bf215546Sopenharmony_ci                                               PVRX(VDMCTRL_USC_TARGET_ANY),
786bf215546Sopenharmony_ci                                               sr_prog->usc.unified_size,
787bf215546Sopenharmony_ci                                               &task0.pds_state0,
788bf215546Sopenharmony_ci                                               &task0.pds_state1);
789bf215546Sopenharmony_ci      }
790bf215546Sopenharmony_ci
791bf215546Sopenharmony_ci      d_dst = &static_state->geom_state[i].vdm_ctx_store_task1;
792bf215546Sopenharmony_ci      pvr_csb_pack (d_dst, CR_VDM_CONTEXT_STORE_TASK1, task1) {
793bf215546Sopenharmony_ci         pvr_csb_pack (&task1.pds_state2, VDMCTRL_PDS_STATE2, state) {
794bf215546Sopenharmony_ci            state.pds_code_addr =
795bf215546Sopenharmony_ci               PVR_DEV_ADDR(sr_prog->pds.store_program.code_offset);
796bf215546Sopenharmony_ci         }
797bf215546Sopenharmony_ci      }
798bf215546Sopenharmony_ci
799bf215546Sopenharmony_ci      q_dst = &static_state->geom_state[i].vdm_ctx_store_task2;
800bf215546Sopenharmony_ci      pvr_csb_pack (q_dst, CR_VDM_CONTEXT_STORE_TASK2, task2) {
801bf215546Sopenharmony_ci         pvr_rogue_get_geom_state_stream_out_words(&pt_prog->pds_store_program,
802bf215546Sopenharmony_ci                                                   &task2.stream_out1,
803bf215546Sopenharmony_ci                                                   &task2.stream_out2);
804bf215546Sopenharmony_ci      }
805bf215546Sopenharmony_ci
806bf215546Sopenharmony_ci      /* Context resume state. */
807bf215546Sopenharmony_ci      q_dst = &static_state->geom_state[i].vdm_ctx_resume_task0;
808bf215546Sopenharmony_ci      pvr_csb_pack (q_dst, CR_VDM_CONTEXT_RESUME_TASK0, task0) {
809bf215546Sopenharmony_ci         pvr_rogue_get_vdmctrl_pds_state_words(&sr_prog->pds.load_program,
810bf215546Sopenharmony_ci                                               PVRX(VDMCTRL_USC_TARGET_ALL),
811bf215546Sopenharmony_ci                                               sr_prog->usc.unified_size,
812bf215546Sopenharmony_ci                                               &task0.pds_state0,
813bf215546Sopenharmony_ci                                               &task0.pds_state1);
814bf215546Sopenharmony_ci      }
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_ci      d_dst = &static_state->geom_state[i].vdm_ctx_resume_task1;
817bf215546Sopenharmony_ci      pvr_csb_pack (d_dst, CR_VDM_CONTEXT_RESUME_TASK1, task1) {
818bf215546Sopenharmony_ci         pvr_csb_pack (&task1.pds_state2, VDMCTRL_PDS_STATE2, state) {
819bf215546Sopenharmony_ci            state.pds_code_addr =
820bf215546Sopenharmony_ci               PVR_DEV_ADDR(sr_prog->pds.load_program.code_offset);
821bf215546Sopenharmony_ci         }
822bf215546Sopenharmony_ci      }
823bf215546Sopenharmony_ci
824bf215546Sopenharmony_ci      q_dst = &static_state->geom_state[i].vdm_ctx_resume_task2;
825bf215546Sopenharmony_ci      pvr_csb_pack (q_dst, CR_VDM_CONTEXT_RESUME_TASK2, task2) {
826bf215546Sopenharmony_ci         pvr_rogue_get_geom_state_stream_out_words(&pt_prog->pds_resume_program,
827bf215546Sopenharmony_ci                                                   &task2.stream_out1,
828bf215546Sopenharmony_ci                                                   &task2.stream_out2);
829bf215546Sopenharmony_ci      }
830bf215546Sopenharmony_ci   }
831bf215546Sopenharmony_ci}
832bf215546Sopenharmony_ci
833bf215546Sopenharmony_cistatic void pvr_render_ctx_ws_create_info_init(
834bf215546Sopenharmony_ci   struct pvr_render_ctx *ctx,
835bf215546Sopenharmony_ci   enum pvr_winsys_ctx_priority priority,
836bf215546Sopenharmony_ci   struct pvr_winsys_render_ctx_create_info *create_info)
837bf215546Sopenharmony_ci{
838bf215546Sopenharmony_ci   create_info->priority = priority;
839bf215546Sopenharmony_ci   create_info->vdm_callstack_addr = ctx->vdm_callstack_bo->vma->dev_addr;
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_ci   pvr_render_ctx_ws_static_state_init(ctx, &create_info->static_state);
842bf215546Sopenharmony_ci}
843bf215546Sopenharmony_ci
844bf215546Sopenharmony_ciVkResult pvr_render_ctx_create(struct pvr_device *device,
845bf215546Sopenharmony_ci                               enum pvr_winsys_ctx_priority priority,
846bf215546Sopenharmony_ci                               struct pvr_render_ctx **const ctx_out)
847bf215546Sopenharmony_ci{
848bf215546Sopenharmony_ci   const uint64_t vdm_callstack_size =
849bf215546Sopenharmony_ci      sizeof(uint64_t) * PVR_VDM_CALLSTACK_MAX_DEPTH;
850bf215546Sopenharmony_ci   struct pvr_winsys_render_ctx_create_info create_info;
851bf215546Sopenharmony_ci   struct pvr_render_ctx *ctx;
852bf215546Sopenharmony_ci   VkResult result;
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci   ctx = vk_alloc(&device->vk.alloc,
855bf215546Sopenharmony_ci                  sizeof(*ctx),
856bf215546Sopenharmony_ci                  8,
857bf215546Sopenharmony_ci                  VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
858bf215546Sopenharmony_ci   if (!ctx)
859bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci   ctx->device = device;
862bf215546Sopenharmony_ci
863bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
864bf215546Sopenharmony_ci                         device->heaps.general_heap,
865bf215546Sopenharmony_ci                         vdm_callstack_size,
866bf215546Sopenharmony_ci                         PVRX(CR_VDM_CALL_STACK_POINTER_ADDR_ALIGNMENT),
867bf215546Sopenharmony_ci                         0,
868bf215546Sopenharmony_ci                         &ctx->vdm_callstack_bo);
869bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
870bf215546Sopenharmony_ci      goto err_vk_free_ctx;
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_ci   result = pvr_render_ctx_switch_init(device, ctx);
873bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
874bf215546Sopenharmony_ci      goto err_free_vdm_callstack_bo;
875bf215546Sopenharmony_ci
876bf215546Sopenharmony_ci   result = pvr_ctx_reset_cmd_init(device, &ctx->reset_cmd);
877bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
878bf215546Sopenharmony_ci      goto err_render_ctx_switch_fini;
879bf215546Sopenharmony_ci
880bf215546Sopenharmony_ci   /* ctx must be fully initialized by this point since
881bf215546Sopenharmony_ci    * pvr_render_ctx_ws_create_info_init() depends on this.
882bf215546Sopenharmony_ci    */
883bf215546Sopenharmony_ci   pvr_render_ctx_ws_create_info_init(ctx, priority, &create_info);
884bf215546Sopenharmony_ci
885bf215546Sopenharmony_ci   result = device->ws->ops->render_ctx_create(device->ws,
886bf215546Sopenharmony_ci                                               &create_info,
887bf215546Sopenharmony_ci                                               &ctx->ws_ctx);
888bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
889bf215546Sopenharmony_ci      goto err_render_ctx_reset_cmd_fini;
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci   *ctx_out = ctx;
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_ci   return VK_SUCCESS;
894bf215546Sopenharmony_ci
895bf215546Sopenharmony_cierr_render_ctx_reset_cmd_fini:
896bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
897bf215546Sopenharmony_ci
898bf215546Sopenharmony_cierr_render_ctx_switch_fini:
899bf215546Sopenharmony_ci   pvr_render_ctx_switch_fini(device, ctx);
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_cierr_free_vdm_callstack_bo:
902bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->vdm_callstack_bo);
903bf215546Sopenharmony_ci
904bf215546Sopenharmony_cierr_vk_free_ctx:
905bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
906bf215546Sopenharmony_ci
907bf215546Sopenharmony_ci   return result;
908bf215546Sopenharmony_ci}
909bf215546Sopenharmony_ci
910bf215546Sopenharmony_civoid pvr_render_ctx_destroy(struct pvr_render_ctx *ctx)
911bf215546Sopenharmony_ci{
912bf215546Sopenharmony_ci   struct pvr_device *device = ctx->device;
913bf215546Sopenharmony_ci
914bf215546Sopenharmony_ci   device->ws->ops->render_ctx_destroy(ctx->ws_ctx);
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
917bf215546Sopenharmony_ci   pvr_render_ctx_switch_fini(device, ctx);
918bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->vdm_callstack_bo);
919bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
920bf215546Sopenharmony_ci}
921bf215546Sopenharmony_ci
922bf215546Sopenharmony_cistatic VkResult pvr_pds_sr_fence_terminate_program_create_and_upload(
923bf215546Sopenharmony_ci   struct pvr_device *device,
924bf215546Sopenharmony_ci   struct pvr_pds_upload *const pds_upload_out)
925bf215546Sopenharmony_ci{
926bf215546Sopenharmony_ci   const uint32_t pds_data_alignment =
927bf215546Sopenharmony_ci      PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) / 4U;
928bf215546Sopenharmony_ci   const struct pvr_device_runtime_info *dev_runtime_info =
929bf215546Sopenharmony_ci      &device->pdevice->dev_runtime_info;
930bf215546Sopenharmony_ci   ASSERTED const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
931bf215546Sopenharmony_ci   uint32_t staging_buffer[PVRX(PDS_TASK_PROGRAM_SIZE) >> 2U];
932bf215546Sopenharmony_ci   struct pvr_pds_fence_program program = { 0 };
933bf215546Sopenharmony_ci   ASSERTED uint32_t *buffer_end;
934bf215546Sopenharmony_ci   uint32_t code_offset;
935bf215546Sopenharmony_ci   uint32_t data_size;
936bf215546Sopenharmony_ci
937bf215546Sopenharmony_ci   /* SW_COMPUTE_PDS_BARRIER is not supported with 2 or more phantoms. */
938bf215546Sopenharmony_ci   assert(!(PVR_NEED_SW_COMPUTE_PDS_BARRIER(dev_info) &&
939bf215546Sopenharmony_ci            dev_runtime_info->num_phantoms >= 2));
940bf215546Sopenharmony_ci
941bf215546Sopenharmony_ci   pvr_pds_generate_fence_terminate_program(&program,
942bf215546Sopenharmony_ci                                            staging_buffer,
943bf215546Sopenharmony_ci                                            PDS_GENERATE_DATA_SEGMENT,
944bf215546Sopenharmony_ci                                            &device->pdevice->dev_info);
945bf215546Sopenharmony_ci
946bf215546Sopenharmony_ci   /* FIXME: pvr_pds_generate_fence_terminate_program() zeros out the data_size
947bf215546Sopenharmony_ci    * when we generate the code segment. Implement
948bf215546Sopenharmony_ci    * PDS_GENERATE_CODEDATA_SEGMENTS? Or wait for the pds gen api to change?
949bf215546Sopenharmony_ci    * This behavior doesn't seem consistent with the rest of the api. For now
950bf215546Sopenharmony_ci    * we store the size in a variable.
951bf215546Sopenharmony_ci    */
952bf215546Sopenharmony_ci   data_size = program.data_size;
953bf215546Sopenharmony_ci   code_offset = ALIGN_POT(program.data_size, pds_data_alignment);
954bf215546Sopenharmony_ci
955bf215546Sopenharmony_ci   buffer_end =
956bf215546Sopenharmony_ci      pvr_pds_generate_fence_terminate_program(&program,
957bf215546Sopenharmony_ci                                               &staging_buffer[code_offset],
958bf215546Sopenharmony_ci                                               PDS_GENERATE_CODE_SEGMENT,
959bf215546Sopenharmony_ci                                               &device->pdevice->dev_info);
960bf215546Sopenharmony_ci
961bf215546Sopenharmony_ci   assert((uint64_t)(buffer_end - staging_buffer) * 4U <
962bf215546Sopenharmony_ci          ROGUE_PDS_TASK_PROGRAM_SIZE);
963bf215546Sopenharmony_ci
964bf215546Sopenharmony_ci   return pvr_gpu_upload_pds(device,
965bf215546Sopenharmony_ci                             staging_buffer,
966bf215546Sopenharmony_ci                             data_size,
967bf215546Sopenharmony_ci                             PVRX(CR_CDM_TERMINATE_PDS_DATA_ADDR_ALIGNMENT),
968bf215546Sopenharmony_ci                             &staging_buffer[code_offset],
969bf215546Sopenharmony_ci                             program.code_size,
970bf215546Sopenharmony_ci                             PVRX(CR_CDM_TERMINATE_PDS_CODE_ADDR_ALIGNMENT),
971bf215546Sopenharmony_ci                             0,
972bf215546Sopenharmony_ci                             pds_upload_out);
973bf215546Sopenharmony_ci}
974bf215546Sopenharmony_ci
975bf215546Sopenharmony_cistatic void pvr_compute_ctx_ws_static_state_init(
976bf215546Sopenharmony_ci   const struct pvr_device_info *const dev_info,
977bf215546Sopenharmony_ci   const struct pvr_compute_ctx *const ctx,
978bf215546Sopenharmony_ci   struct pvr_winsys_compute_ctx_static_state *const static_state)
979bf215546Sopenharmony_ci{
980bf215546Sopenharmony_ci   const struct pvr_compute_ctx_switch *const ctx_switch = &ctx->ctx_switch;
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_ci   /* CR_CDM_CONTEXT_... use state store program info. */
983bf215546Sopenharmony_ci
984bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_store_pds0,
985bf215546Sopenharmony_ci                 CR_CDM_CONTEXT_PDS0,
986bf215546Sopenharmony_ci                 state) {
987bf215546Sopenharmony_ci      state.data_addr =
988bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[0].pds.store_program.data_offset);
989bf215546Sopenharmony_ci      state.code_addr =
990bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[0].pds.store_program.code_offset);
991bf215546Sopenharmony_ci   }
992bf215546Sopenharmony_ci
993bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_store_pds0_b,
994bf215546Sopenharmony_ci                 CR_CDM_CONTEXT_PDS0,
995bf215546Sopenharmony_ci                 state) {
996bf215546Sopenharmony_ci      state.data_addr =
997bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[1].pds.store_program.data_offset);
998bf215546Sopenharmony_ci      state.code_addr =
999bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[1].pds.store_program.code_offset);
1000bf215546Sopenharmony_ci   }
1001bf215546Sopenharmony_ci
1002bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_store_pds1,
1003bf215546Sopenharmony_ci                 CR_CDM_CONTEXT_PDS1,
1004bf215546Sopenharmony_ci                 state) {
1005bf215546Sopenharmony_ci      /* Convert the data size from dwords to bytes. */
1006bf215546Sopenharmony_ci      const uint32_t store_program_data_size =
1007bf215546Sopenharmony_ci         ctx_switch->sr[0].pds.store_program.data_size * 4U;
1008bf215546Sopenharmony_ci
1009bf215546Sopenharmony_ci      state.pds_seq_dep = true;
1010bf215546Sopenharmony_ci      state.usc_seq_dep = false;
1011bf215546Sopenharmony_ci      state.target = true;
1012bf215546Sopenharmony_ci      state.unified_size = ctx_switch->sr[0].usc.unified_size;
1013bf215546Sopenharmony_ci      state.common_shared = false;
1014bf215546Sopenharmony_ci      state.common_size = 0;
1015bf215546Sopenharmony_ci      state.temp_size = 0;
1016bf215546Sopenharmony_ci
1017bf215546Sopenharmony_ci      assert(store_program_data_size %
1018bf215546Sopenharmony_ci                PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) ==
1019bf215546Sopenharmony_ci             0);
1020bf215546Sopenharmony_ci      state.data_size = store_program_data_size /
1021bf215546Sopenharmony_ci                        PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE);
1022bf215546Sopenharmony_ci
1023bf215546Sopenharmony_ci      state.fence = true;
1024bf215546Sopenharmony_ci   }
1025bf215546Sopenharmony_ci
1026bf215546Sopenharmony_ci   /* CR_CDM_TERMINATE_... use fence terminate info. */
1027bf215546Sopenharmony_ci
1028bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_terminate_pds,
1029bf215546Sopenharmony_ci                 CR_CDM_TERMINATE_PDS,
1030bf215546Sopenharmony_ci                 state) {
1031bf215546Sopenharmony_ci      state.data_addr =
1032bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr_fence_terminate_program.data_offset);
1033bf215546Sopenharmony_ci      state.code_addr =
1034bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr_fence_terminate_program.code_offset);
1035bf215546Sopenharmony_ci   }
1036bf215546Sopenharmony_ci
1037bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_terminate_pds1,
1038bf215546Sopenharmony_ci                 CR_CDM_TERMINATE_PDS1,
1039bf215546Sopenharmony_ci                 state) {
1040bf215546Sopenharmony_ci      /* Convert the data size from dwords to bytes. */
1041bf215546Sopenharmony_ci      const uint32_t fence_terminate_program_data_size =
1042bf215546Sopenharmony_ci         ctx_switch->sr_fence_terminate_program.data_size * 4U;
1043bf215546Sopenharmony_ci
1044bf215546Sopenharmony_ci      state.pds_seq_dep = true;
1045bf215546Sopenharmony_ci      state.usc_seq_dep = false;
1046bf215546Sopenharmony_ci      state.target = !PVR_HAS_FEATURE(dev_info, compute_morton_capable);
1047bf215546Sopenharmony_ci      state.unified_size = 0;
1048bf215546Sopenharmony_ci      /* Common store is for shareds -- this will free the partitions. */
1049bf215546Sopenharmony_ci      state.common_shared = true;
1050bf215546Sopenharmony_ci      state.common_size = 0;
1051bf215546Sopenharmony_ci      state.temp_size = 0;
1052bf215546Sopenharmony_ci
1053bf215546Sopenharmony_ci      assert(fence_terminate_program_data_size %
1054bf215546Sopenharmony_ci                PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE) ==
1055bf215546Sopenharmony_ci             0);
1056bf215546Sopenharmony_ci      state.data_size = fence_terminate_program_data_size /
1057bf215546Sopenharmony_ci                        PVRX(VDMCTRL_PDS_STATE0_PDS_DATA_SIZE_UNIT_SIZE);
1058bf215546Sopenharmony_ci      state.fence = true;
1059bf215546Sopenharmony_ci   }
1060bf215546Sopenharmony_ci
1061bf215546Sopenharmony_ci   /* CR_CDM_RESUME_... use state load program info. */
1062bf215546Sopenharmony_ci
1063bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_resume_pds0,
1064bf215546Sopenharmony_ci                 CR_CDM_CONTEXT_LOAD_PDS0,
1065bf215546Sopenharmony_ci                 state) {
1066bf215546Sopenharmony_ci      state.data_addr =
1067bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[0].pds.load_program.data_offset);
1068bf215546Sopenharmony_ci      state.code_addr =
1069bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[0].pds.load_program.code_offset);
1070bf215546Sopenharmony_ci   }
1071bf215546Sopenharmony_ci
1072bf215546Sopenharmony_ci   pvr_csb_pack (&static_state->cdm_ctx_resume_pds0_b,
1073bf215546Sopenharmony_ci                 CR_CDM_CONTEXT_LOAD_PDS0,
1074bf215546Sopenharmony_ci                 state) {
1075bf215546Sopenharmony_ci      state.data_addr =
1076bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[1].pds.load_program.data_offset);
1077bf215546Sopenharmony_ci      state.code_addr =
1078bf215546Sopenharmony_ci         PVR_DEV_ADDR(ctx_switch->sr[1].pds.load_program.code_offset);
1079bf215546Sopenharmony_ci   }
1080bf215546Sopenharmony_ci}
1081bf215546Sopenharmony_ci
1082bf215546Sopenharmony_cistatic void pvr_compute_ctx_ws_create_info_init(
1083bf215546Sopenharmony_ci   const struct pvr_compute_ctx *const ctx,
1084bf215546Sopenharmony_ci   enum pvr_winsys_ctx_priority priority,
1085bf215546Sopenharmony_ci   struct pvr_winsys_compute_ctx_create_info *const create_info)
1086bf215546Sopenharmony_ci{
1087bf215546Sopenharmony_ci   create_info->priority = priority;
1088bf215546Sopenharmony_ci
1089bf215546Sopenharmony_ci   pvr_compute_ctx_ws_static_state_init(&ctx->device->pdevice->dev_info,
1090bf215546Sopenharmony_ci                                        ctx,
1091bf215546Sopenharmony_ci                                        &create_info->static_state);
1092bf215546Sopenharmony_ci}
1093bf215546Sopenharmony_ci
1094bf215546Sopenharmony_ciVkResult pvr_compute_ctx_create(struct pvr_device *const device,
1095bf215546Sopenharmony_ci                                enum pvr_winsys_ctx_priority priority,
1096bf215546Sopenharmony_ci                                struct pvr_compute_ctx **const ctx_out)
1097bf215546Sopenharmony_ci{
1098bf215546Sopenharmony_ci   struct pvr_winsys_compute_ctx_create_info create_info;
1099bf215546Sopenharmony_ci   struct pvr_compute_ctx *ctx;
1100bf215546Sopenharmony_ci   VkResult result;
1101bf215546Sopenharmony_ci
1102bf215546Sopenharmony_ci   ctx = vk_alloc(&device->vk.alloc,
1103bf215546Sopenharmony_ci                  sizeof(*ctx),
1104bf215546Sopenharmony_ci                  8,
1105bf215546Sopenharmony_ci                  VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1106bf215546Sopenharmony_ci   if (!ctx)
1107bf215546Sopenharmony_ci      return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1108bf215546Sopenharmony_ci
1109bf215546Sopenharmony_ci   ctx->device = device;
1110bf215546Sopenharmony_ci
1111bf215546Sopenharmony_ci   result = pvr_bo_alloc(
1112bf215546Sopenharmony_ci      device,
1113bf215546Sopenharmony_ci      device->heaps.general_heap,
1114bf215546Sopenharmony_ci      rogue_get_cdm_context_resume_buffer_size(&device->pdevice->dev_info),
1115bf215546Sopenharmony_ci      rogue_get_cdm_context_resume_buffer_alignment(&device->pdevice->dev_info),
1116bf215546Sopenharmony_ci      PVR_WINSYS_BO_FLAG_CPU_ACCESS | PVR_WINSYS_BO_FLAG_GPU_UNCACHED,
1117bf215546Sopenharmony_ci      &ctx->ctx_switch.compute_state_bo);
1118bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1119bf215546Sopenharmony_ci      goto err_free_ctx;
1120bf215546Sopenharmony_ci
1121bf215546Sopenharmony_ci   /* TODO: Change this so that enabling storage to B doesn't change the array
1122bf215546Sopenharmony_ci    * size. Instead of looping we could unroll this and have the second
1123bf215546Sopenharmony_ci    * programs setup depending on the B enable. Doing it that way would make
1124bf215546Sopenharmony_ci    * things more obvious.
1125bf215546Sopenharmony_ci    */
1126bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx->ctx_switch.sr); i++) {
1127bf215546Sopenharmony_ci      result = pvr_ctx_sr_programs_setup(device,
1128bf215546Sopenharmony_ci                                         PVR_CTX_SR_COMPUTE_TARGET,
1129bf215546Sopenharmony_ci                                         &ctx->ctx_switch.sr[i]);
1130bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
1131bf215546Sopenharmony_ci         for (uint32_t j = 0; j < i; j++)
1132bf215546Sopenharmony_ci            pvr_ctx_sr_programs_cleanup(device, &ctx->ctx_switch.sr[j]);
1133bf215546Sopenharmony_ci
1134bf215546Sopenharmony_ci         goto err_free_state_buffer;
1135bf215546Sopenharmony_ci      }
1136bf215546Sopenharmony_ci   }
1137bf215546Sopenharmony_ci
1138bf215546Sopenharmony_ci   result = pvr_pds_sr_fence_terminate_program_create_and_upload(
1139bf215546Sopenharmony_ci      device,
1140bf215546Sopenharmony_ci      &ctx->ctx_switch.sr_fence_terminate_program);
1141bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1142bf215546Sopenharmony_ci      goto err_free_sr_programs;
1143bf215546Sopenharmony_ci
1144bf215546Sopenharmony_ci   pvr_compute_ctx_ws_create_info_init(ctx, priority, &create_info);
1145bf215546Sopenharmony_ci
1146bf215546Sopenharmony_ci   result = pvr_ctx_reset_cmd_init(device, &ctx->reset_cmd);
1147bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1148bf215546Sopenharmony_ci      goto err_free_pds_fence_terminate_program;
1149bf215546Sopenharmony_ci
1150bf215546Sopenharmony_ci   result = device->ws->ops->compute_ctx_create(device->ws,
1151bf215546Sopenharmony_ci                                                &create_info,
1152bf215546Sopenharmony_ci                                                &ctx->ws_ctx);
1153bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1154bf215546Sopenharmony_ci      goto err_fini_reset_cmd;
1155bf215546Sopenharmony_ci
1156bf215546Sopenharmony_ci   *ctx_out = ctx;
1157bf215546Sopenharmony_ci
1158bf215546Sopenharmony_ci   return VK_SUCCESS;
1159bf215546Sopenharmony_ci
1160bf215546Sopenharmony_cierr_fini_reset_cmd:
1161bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
1162bf215546Sopenharmony_ci
1163bf215546Sopenharmony_cierr_free_pds_fence_terminate_program:
1164bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->ctx_switch.sr_fence_terminate_program.pvr_bo);
1165bf215546Sopenharmony_ci
1166bf215546Sopenharmony_cierr_free_sr_programs:
1167bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx->ctx_switch.sr); ++i)
1168bf215546Sopenharmony_ci      pvr_ctx_sr_programs_cleanup(device, &ctx->ctx_switch.sr[i]);
1169bf215546Sopenharmony_ci
1170bf215546Sopenharmony_cierr_free_state_buffer:
1171bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->ctx_switch.compute_state_bo);
1172bf215546Sopenharmony_ci
1173bf215546Sopenharmony_cierr_free_ctx:
1174bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
1175bf215546Sopenharmony_ci
1176bf215546Sopenharmony_ci   return result;
1177bf215546Sopenharmony_ci}
1178bf215546Sopenharmony_ci
1179bf215546Sopenharmony_civoid pvr_compute_ctx_destroy(struct pvr_compute_ctx *const ctx)
1180bf215546Sopenharmony_ci{
1181bf215546Sopenharmony_ci   struct pvr_device *device = ctx->device;
1182bf215546Sopenharmony_ci
1183bf215546Sopenharmony_ci   device->ws->ops->compute_ctx_destroy(ctx->ws_ctx);
1184bf215546Sopenharmony_ci
1185bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->ctx_switch.sr_fence_terminate_program.pvr_bo);
1188bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(ctx->ctx_switch.sr); ++i)
1189bf215546Sopenharmony_ci      pvr_ctx_sr_programs_cleanup(device, &ctx->ctx_switch.sr[i]);
1190bf215546Sopenharmony_ci
1191bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->ctx_switch.compute_state_bo);
1192bf215546Sopenharmony_ci
1193bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
1194bf215546Sopenharmony_ci}
1195bf215546Sopenharmony_ci
1196bf215546Sopenharmony_cistatic void pvr_transfer_ctx_ws_create_info_init(
1197bf215546Sopenharmony_ci   enum pvr_winsys_ctx_priority priority,
1198bf215546Sopenharmony_ci   struct pvr_winsys_transfer_ctx_create_info *const create_info)
1199bf215546Sopenharmony_ci{
1200bf215546Sopenharmony_ci   create_info->priority = priority;
1201bf215546Sopenharmony_ci}
1202bf215546Sopenharmony_ci
1203bf215546Sopenharmony_cistatic VkResult pvr_transfer_ctx_setup_shaders(struct pvr_device *device,
1204bf215546Sopenharmony_ci                                               struct pvr_transfer_ctx *ctx)
1205bf215546Sopenharmony_ci{
1206bf215546Sopenharmony_ci   const uint32_t cache_line_size =
1207bf215546Sopenharmony_ci      rogue_get_slc_cache_line_size(&device->pdevice->dev_info);
1208bf215546Sopenharmony_ci   VkResult result;
1209bf215546Sopenharmony_ci
1210bf215546Sopenharmony_ci   /* TODO: Setup USC fragments. */
1211bf215546Sopenharmony_ci
1212bf215546Sopenharmony_ci   /* Setup EOT program. */
1213bf215546Sopenharmony_ci   result = pvr_gpu_upload_usc(device,
1214bf215546Sopenharmony_ci                               pvr_transfer_eot_usc_code,
1215bf215546Sopenharmony_ci                               sizeof(pvr_transfer_eot_usc_code),
1216bf215546Sopenharmony_ci                               cache_line_size,
1217bf215546Sopenharmony_ci                               &ctx->usc_eot_bo);
1218bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1219bf215546Sopenharmony_ci      return result;
1220bf215546Sopenharmony_ci
1221bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(pvr_transfer_eot_usc_offsets) ==
1222bf215546Sopenharmony_ci                 ARRAY_SIZE(ctx->transfer_mrts));
1223bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < ARRAY_SIZE(pvr_transfer_eot_usc_offsets); i++) {
1224bf215546Sopenharmony_ci      ctx->transfer_mrts[i] =
1225bf215546Sopenharmony_ci         PVR_DEV_ADDR_OFFSET(ctx->usc_eot_bo->vma->dev_addr,
1226bf215546Sopenharmony_ci                             pvr_transfer_eot_usc_offsets[i]);
1227bf215546Sopenharmony_ci   }
1228bf215546Sopenharmony_ci
1229bf215546Sopenharmony_ci   return VK_SUCCESS;
1230bf215546Sopenharmony_ci}
1231bf215546Sopenharmony_ci
1232bf215546Sopenharmony_cistatic void pvr_transfer_ctx_fini_shaders(struct pvr_device *device,
1233bf215546Sopenharmony_ci                                          struct pvr_transfer_ctx *ctx)
1234bf215546Sopenharmony_ci{
1235bf215546Sopenharmony_ci   pvr_bo_free(device, ctx->usc_eot_bo);
1236bf215546Sopenharmony_ci}
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ciVkResult pvr_transfer_ctx_create(struct pvr_device *const device,
1239bf215546Sopenharmony_ci                                 enum pvr_winsys_ctx_priority priority,
1240bf215546Sopenharmony_ci                                 struct pvr_transfer_ctx **const ctx_out)
1241bf215546Sopenharmony_ci{
1242bf215546Sopenharmony_ci   struct pvr_winsys_transfer_ctx_create_info create_info;
1243bf215546Sopenharmony_ci   struct pvr_transfer_ctx *ctx;
1244bf215546Sopenharmony_ci   VkResult result;
1245bf215546Sopenharmony_ci
1246bf215546Sopenharmony_ci   ctx = vk_zalloc(&device->vk.alloc,
1247bf215546Sopenharmony_ci                   sizeof(*ctx),
1248bf215546Sopenharmony_ci                   8U,
1249bf215546Sopenharmony_ci                   VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1250bf215546Sopenharmony_ci   if (!ctx)
1251bf215546Sopenharmony_ci      return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1252bf215546Sopenharmony_ci
1253bf215546Sopenharmony_ci   ctx->device = device;
1254bf215546Sopenharmony_ci
1255bf215546Sopenharmony_ci   result = pvr_ctx_reset_cmd_init(device, &ctx->reset_cmd);
1256bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1257bf215546Sopenharmony_ci      goto err_free_ctx;
1258bf215546Sopenharmony_ci
1259bf215546Sopenharmony_ci   pvr_transfer_ctx_ws_create_info_init(priority, &create_info);
1260bf215546Sopenharmony_ci
1261bf215546Sopenharmony_ci   result = device->ws->ops->transfer_ctx_create(device->ws,
1262bf215546Sopenharmony_ci                                                 &create_info,
1263bf215546Sopenharmony_ci                                                 &ctx->ws_ctx);
1264bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1265bf215546Sopenharmony_ci      goto err_fini_reset_cmd;
1266bf215546Sopenharmony_ci
1267bf215546Sopenharmony_ci   result = pvr_transfer_ctx_setup_shaders(device, ctx);
1268bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1269bf215546Sopenharmony_ci      goto err_destroy_transfer_ctx;
1270bf215546Sopenharmony_ci
1271bf215546Sopenharmony_ci   /* Create the PDS Uniform/Tex state code segment array. */
1272bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < ARRAY_SIZE(ctx->pds_unitex_code); i++) {
1273bf215546Sopenharmony_ci      for (uint32_t j = 0U; j < ARRAY_SIZE(ctx->pds_unitex_code[0U]); j++) {
1274bf215546Sopenharmony_ci         if (i == 0U && j == 0U)
1275bf215546Sopenharmony_ci            continue;
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_ci         result = pvr_pds_unitex_state_program_create_and_upload(
1278bf215546Sopenharmony_ci            device,
1279bf215546Sopenharmony_ci            NULL,
1280bf215546Sopenharmony_ci            i,
1281bf215546Sopenharmony_ci            j,
1282bf215546Sopenharmony_ci            &ctx->pds_unitex_code[i][j]);
1283bf215546Sopenharmony_ci         if (result != VK_SUCCESS) {
1284bf215546Sopenharmony_ci            goto err_free_pds_unitex_bos;
1285bf215546Sopenharmony_ci         }
1286bf215546Sopenharmony_ci      }
1287bf215546Sopenharmony_ci   }
1288bf215546Sopenharmony_ci
1289bf215546Sopenharmony_ci   *ctx_out = ctx;
1290bf215546Sopenharmony_ci
1291bf215546Sopenharmony_ci   return VK_SUCCESS;
1292bf215546Sopenharmony_ci
1293bf215546Sopenharmony_cierr_free_pds_unitex_bos:
1294bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < ARRAY_SIZE(ctx->pds_unitex_code); i++) {
1295bf215546Sopenharmony_ci      for (uint32_t j = 0U; j < ARRAY_SIZE(ctx->pds_unitex_code[0U]); j++) {
1296bf215546Sopenharmony_ci         if (!ctx->pds_unitex_code[i][j].pvr_bo)
1297bf215546Sopenharmony_ci            continue;
1298bf215546Sopenharmony_ci
1299bf215546Sopenharmony_ci         pvr_bo_free(device, ctx->pds_unitex_code[i][j].pvr_bo);
1300bf215546Sopenharmony_ci      }
1301bf215546Sopenharmony_ci   }
1302bf215546Sopenharmony_ci
1303bf215546Sopenharmony_ci   pvr_transfer_ctx_fini_shaders(device, ctx);
1304bf215546Sopenharmony_ci
1305bf215546Sopenharmony_cierr_destroy_transfer_ctx:
1306bf215546Sopenharmony_ci   device->ws->ops->transfer_ctx_destroy(ctx->ws_ctx);
1307bf215546Sopenharmony_ci
1308bf215546Sopenharmony_cierr_fini_reset_cmd:
1309bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
1310bf215546Sopenharmony_ci
1311bf215546Sopenharmony_cierr_free_ctx:
1312bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
1313bf215546Sopenharmony_ci
1314bf215546Sopenharmony_ci   return result;
1315bf215546Sopenharmony_ci}
1316bf215546Sopenharmony_ci
1317bf215546Sopenharmony_civoid pvr_transfer_ctx_destroy(struct pvr_transfer_ctx *const ctx)
1318bf215546Sopenharmony_ci{
1319bf215546Sopenharmony_ci   struct pvr_device *device = ctx->device;
1320bf215546Sopenharmony_ci
1321bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < ARRAY_SIZE(ctx->pds_unitex_code); i++) {
1322bf215546Sopenharmony_ci      for (uint32_t j = 0U; j < ARRAY_SIZE(ctx->pds_unitex_code[0U]); j++) {
1323bf215546Sopenharmony_ci         if (!ctx->pds_unitex_code[i][j].pvr_bo)
1324bf215546Sopenharmony_ci            continue;
1325bf215546Sopenharmony_ci
1326bf215546Sopenharmony_ci         pvr_bo_free(device, ctx->pds_unitex_code[i][j].pvr_bo);
1327bf215546Sopenharmony_ci      }
1328bf215546Sopenharmony_ci   }
1329bf215546Sopenharmony_ci
1330bf215546Sopenharmony_ci   pvr_transfer_ctx_fini_shaders(device, ctx);
1331bf215546Sopenharmony_ci   device->ws->ops->transfer_ctx_destroy(ctx->ws_ctx);
1332bf215546Sopenharmony_ci   pvr_ctx_reset_cmd_fini(device, &ctx->reset_cmd);
1333bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, ctx);
1334bf215546Sopenharmony_ci}
1335