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 <stdint.h>
27bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "hwdef/rogue_hw_defs.h"
30bf215546Sopenharmony_ci#include "hwdef/rogue_hw_utils.h"
31bf215546Sopenharmony_ci#include "pvr_bo.h"
32bf215546Sopenharmony_ci#include "pvr_csb.h"
33bf215546Sopenharmony_ci#include "pvr_csb_enum_helpers.h"
34bf215546Sopenharmony_ci#include "pvr_debug.h"
35bf215546Sopenharmony_ci#include "pvr_job_common.h"
36bf215546Sopenharmony_ci#include "pvr_job_context.h"
37bf215546Sopenharmony_ci#include "pvr_job_render.h"
38bf215546Sopenharmony_ci#include "pvr_pds.h"
39bf215546Sopenharmony_ci#include "pvr_private.h"
40bf215546Sopenharmony_ci#include "pvr_rogue_fw.h"
41bf215546Sopenharmony_ci#include "pvr_types.h"
42bf215546Sopenharmony_ci#include "pvr_winsys.h"
43bf215546Sopenharmony_ci#include "util/compiler.h"
44bf215546Sopenharmony_ci#include "util/macros.h"
45bf215546Sopenharmony_ci#include "util/u_math.h"
46bf215546Sopenharmony_ci#include "vk_alloc.h"
47bf215546Sopenharmony_ci#include "vk_log.h"
48bf215546Sopenharmony_ci#include "vk_util.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#define ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE 16U
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci/* FIXME: Is there a hardware define we can use instead? */
53bf215546Sopenharmony_ci/* 1 DWord per PM physical page stored in the free list */
54bf215546Sopenharmony_ci#define ROGUE_FREE_LIST_ENTRY_SIZE ((uint32_t)sizeof(uint32_t))
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci/* FIXME: The three defines below, for the number of PC, PD and PT entries in a
57bf215546Sopenharmony_ci * 4KB page, come from rgxmmudefs_km.h (meaning they're part of the
58bf215546Sopenharmony_ci * auto-generated hwdefs). Should these be defined in rogue_mmu.xml? Keeping in
59bf215546Sopenharmony_ci * mind that we probably only need these three values. */
60bf215546Sopenharmony_ci#define ROGUE_NUM_PC_ENTRIES_PER_PAGE 0x400U
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci#define ROGUE_NUM_PD_ENTRIES_PER_PAGE 0x200U
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci#define ROGUE_NUM_PT_ENTRIES_PER_PAGE 0x200U
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_cistruct pvr_free_list {
67bf215546Sopenharmony_ci   struct pvr_device *device;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   uint64_t size;
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   struct pvr_bo *bo;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   struct pvr_winsys_free_list *ws_free_list;
74bf215546Sopenharmony_ci};
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci/* Macrotile information. */
77bf215546Sopenharmony_cistruct pvr_rt_mtile_info {
78bf215546Sopenharmony_ci   uint32_t tile_size_x;
79bf215546Sopenharmony_ci   uint32_t tile_size_y;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   uint32_t num_tiles_x;
82bf215546Sopenharmony_ci   uint32_t num_tiles_y;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   uint32_t tiles_per_mtile_x;
85bf215546Sopenharmony_ci   uint32_t tiles_per_mtile_y;
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   uint32_t x_tile_max;
88bf215546Sopenharmony_ci   uint32_t y_tile_max;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci   uint32_t mtiles_x;
91bf215546Sopenharmony_ci   uint32_t mtiles_y;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   uint32_t mtile_x1;
94bf215546Sopenharmony_ci   uint32_t mtile_y1;
95bf215546Sopenharmony_ci   uint32_t mtile_x2;
96bf215546Sopenharmony_ci   uint32_t mtile_y2;
97bf215546Sopenharmony_ci   uint32_t mtile_x3;
98bf215546Sopenharmony_ci   uint32_t mtile_y3;
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   uint32_t mtile_stride;
101bf215546Sopenharmony_ci};
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_cistruct pvr_rt_dataset {
104bf215546Sopenharmony_ci   struct pvr_device *device;
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci   /* RT dataset information */
107bf215546Sopenharmony_ci   uint32_t width;
108bf215546Sopenharmony_ci   uint32_t height;
109bf215546Sopenharmony_ci   uint32_t samples;
110bf215546Sopenharmony_ci   uint32_t layers;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   struct pvr_free_list *global_free_list;
113bf215546Sopenharmony_ci   struct pvr_free_list *local_free_list;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   struct pvr_bo *vheap_rtc_bo;
116bf215546Sopenharmony_ci   pvr_dev_addr_t vheap_dev_addr;
117bf215546Sopenharmony_ci   pvr_dev_addr_t rtc_dev_addr;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   struct pvr_bo *tpc_bo;
120bf215546Sopenharmony_ci   uint64_t tpc_stride;
121bf215546Sopenharmony_ci   uint64_t tpc_size;
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_ci   struct pvr_winsys_rt_dataset *ws_rt_dataset;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   /* RT data information */
126bf215546Sopenharmony_ci   struct pvr_bo *mta_mlist_bo;
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   struct pvr_bo *rgn_headers_bo;
129bf215546Sopenharmony_ci   uint64_t rgn_headers_stride;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   bool need_frag;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   uint8_t rt_data_idx;
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   struct {
136bf215546Sopenharmony_ci      pvr_dev_addr_t mta_dev_addr;
137bf215546Sopenharmony_ci      pvr_dev_addr_t mlist_dev_addr;
138bf215546Sopenharmony_ci      pvr_dev_addr_t rgn_headers_dev_addr;
139bf215546Sopenharmony_ci   } rt_datas[ROGUE_NUM_RTDATAS];
140bf215546Sopenharmony_ci};
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ciVkResult pvr_free_list_create(struct pvr_device *device,
143bf215546Sopenharmony_ci                              uint32_t initial_size,
144bf215546Sopenharmony_ci                              uint32_t max_size,
145bf215546Sopenharmony_ci                              uint32_t grow_size,
146bf215546Sopenharmony_ci                              uint32_t grow_threshold,
147bf215546Sopenharmony_ci                              struct pvr_free_list *parent_free_list,
148bf215546Sopenharmony_ci                              struct pvr_free_list **const free_list_out)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   struct pvr_winsys_free_list *parent_ws_free_list =
151bf215546Sopenharmony_ci      parent_free_list ? parent_free_list->ws_free_list : NULL;
152bf215546Sopenharmony_ci   const uint64_t bo_flags = PVR_BO_ALLOC_FLAG_GPU_UNCACHED |
153bf215546Sopenharmony_ci                             PVR_BO_ALLOC_FLAG_PM_FW_PROTECT;
154bf215546Sopenharmony_ci   struct pvr_free_list *free_list;
155bf215546Sopenharmony_ci   uint32_t cache_line_size;
156bf215546Sopenharmony_ci   uint32_t initial_num_pages;
157bf215546Sopenharmony_ci   uint32_t grow_num_pages;
158bf215546Sopenharmony_ci   uint32_t max_num_pages;
159bf215546Sopenharmony_ci   uint64_t addr_alignment;
160bf215546Sopenharmony_ci   uint64_t size_alignment;
161bf215546Sopenharmony_ci   uint64_t size;
162bf215546Sopenharmony_ci   VkResult result;
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   assert((initial_size + grow_size) <= max_size);
165bf215546Sopenharmony_ci   assert(max_size != 0);
166bf215546Sopenharmony_ci   assert(grow_threshold <= 100);
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   /* Make sure the free list is created with at least a single page. */
169bf215546Sopenharmony_ci   if (initial_size == 0)
170bf215546Sopenharmony_ci      initial_size = ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   /* The freelists sizes must respect the PM freelist base address alignment
173bf215546Sopenharmony_ci    * requirement. As the freelist entries are cached by the SLC, it's also
174bf215546Sopenharmony_ci    * necessary to ensure the sizes respect the SLC cache line size to avoid
175bf215546Sopenharmony_ci    * invalid entries appearing in the cache, which would be problematic after
176bf215546Sopenharmony_ci    * a grow operation, as the SLC entries aren't invalidated. We do this by
177bf215546Sopenharmony_ci    * making sure the freelist values are appropriately aligned.
178bf215546Sopenharmony_ci    *
179bf215546Sopenharmony_ci    * To calculate the alignment, we first take the largest of the freelist
180bf215546Sopenharmony_ci    * base address alignment and the SLC cache line size. We then divide this
181bf215546Sopenharmony_ci    * by the freelist entry size to determine the number of freelist entries
182bf215546Sopenharmony_ci    * required by the PM. Finally, as each entry holds a single PM physical
183bf215546Sopenharmony_ci    * page, we multiple the number of entries by the page size.
184bf215546Sopenharmony_ci    *
185bf215546Sopenharmony_ci    * As an example, if the base address alignment is 16 bytes, the SLC cache
186bf215546Sopenharmony_ci    * line size is 64 bytes and the freelist entry size is 4 bytes then 16
187bf215546Sopenharmony_ci    * entries are required, as we take the SLC cacheline size (being the larger
188bf215546Sopenharmony_ci    * of the two values) and divide this by 4. If the PM page size is 4096
189bf215546Sopenharmony_ci    * bytes then we end up with an alignment of 65536 bytes.
190bf215546Sopenharmony_ci    */
191bf215546Sopenharmony_ci   cache_line_size = rogue_get_slc_cache_line_size(&device->pdevice->dev_info);
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   addr_alignment =
194bf215546Sopenharmony_ci      MAX2(ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE, cache_line_size);
195bf215546Sopenharmony_ci   size_alignment = (addr_alignment / ROGUE_FREE_LIST_ENTRY_SIZE) *
196bf215546Sopenharmony_ci                    ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   assert(util_is_power_of_two_nonzero(size_alignment));
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   initial_size = align64(initial_size, size_alignment);
201bf215546Sopenharmony_ci   max_size = align64(max_size, size_alignment);
202bf215546Sopenharmony_ci   grow_size = align64(grow_size, size_alignment);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   /* Make sure the 'max' size doesn't exceed what the firmware supports and
205bf215546Sopenharmony_ci    * adjust the other sizes accordingly.
206bf215546Sopenharmony_ci    */
207bf215546Sopenharmony_ci   if (max_size > ROGUE_FREE_LIST_MAX_SIZE) {
208bf215546Sopenharmony_ci      max_size = ROGUE_FREE_LIST_MAX_SIZE;
209bf215546Sopenharmony_ci      assert(align64(max_size, size_alignment) == max_size);
210bf215546Sopenharmony_ci   }
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   if (initial_size > max_size)
213bf215546Sopenharmony_ci      initial_size = max_size;
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   if (initial_size == max_size)
216bf215546Sopenharmony_ci      grow_size = 0;
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   initial_num_pages = initial_size >> ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
219bf215546Sopenharmony_ci   max_num_pages = max_size >> ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
220bf215546Sopenharmony_ci   grow_num_pages = grow_size >> ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci   /* Calculate the size of the buffer needed to store the free list entries
223bf215546Sopenharmony_ci    * based on the maximum number of pages we can have.
224bf215546Sopenharmony_ci    */
225bf215546Sopenharmony_ci   size = max_num_pages * ROGUE_FREE_LIST_ENTRY_SIZE;
226bf215546Sopenharmony_ci   assert(align64(size, addr_alignment) == size);
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   free_list = vk_alloc(&device->vk.alloc,
229bf215546Sopenharmony_ci                        sizeof(*free_list),
230bf215546Sopenharmony_ci                        8,
231bf215546Sopenharmony_ci                        VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
232bf215546Sopenharmony_ci   if (!free_list)
233bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   /* FIXME: The memory is mapped GPU uncached, but this seems to contradict
236bf215546Sopenharmony_ci    * the comment above about aligning to the SLC cache line size.
237bf215546Sopenharmony_ci    */
238bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
239bf215546Sopenharmony_ci                         device->heaps.general_heap,
240bf215546Sopenharmony_ci                         size,
241bf215546Sopenharmony_ci                         addr_alignment,
242bf215546Sopenharmony_ci                         bo_flags,
243bf215546Sopenharmony_ci                         &free_list->bo);
244bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
245bf215546Sopenharmony_ci      goto err_vk_free_free_list;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   result = device->ws->ops->free_list_create(device->ws,
248bf215546Sopenharmony_ci                                              free_list->bo->vma,
249bf215546Sopenharmony_ci                                              initial_num_pages,
250bf215546Sopenharmony_ci                                              max_num_pages,
251bf215546Sopenharmony_ci                                              grow_num_pages,
252bf215546Sopenharmony_ci                                              grow_threshold,
253bf215546Sopenharmony_ci                                              parent_ws_free_list,
254bf215546Sopenharmony_ci                                              &free_list->ws_free_list);
255bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
256bf215546Sopenharmony_ci      goto err_pvr_bo_free_bo;
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci   free_list->device = device;
259bf215546Sopenharmony_ci   free_list->size = size;
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   *free_list_out = free_list;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   return VK_SUCCESS;
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_cierr_pvr_bo_free_bo:
266bf215546Sopenharmony_ci   pvr_bo_free(device, free_list->bo);
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_cierr_vk_free_free_list:
269bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, free_list);
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   return result;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_civoid pvr_free_list_destroy(struct pvr_free_list *free_list)
275bf215546Sopenharmony_ci{
276bf215546Sopenharmony_ci   struct pvr_device *device = free_list->device;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   device->ws->ops->free_list_destroy(free_list->ws_free_list);
279bf215546Sopenharmony_ci   pvr_bo_free(device, free_list->bo);
280bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, free_list);
281bf215546Sopenharmony_ci}
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_cistatic inline void pvr_get_samples_in_xy(uint32_t samples,
284bf215546Sopenharmony_ci                                         uint32_t *const x_out,
285bf215546Sopenharmony_ci                                         uint32_t *const y_out)
286bf215546Sopenharmony_ci{
287bf215546Sopenharmony_ci   switch (samples) {
288bf215546Sopenharmony_ci   case 1:
289bf215546Sopenharmony_ci      *x_out = 1;
290bf215546Sopenharmony_ci      *y_out = 1;
291bf215546Sopenharmony_ci      break;
292bf215546Sopenharmony_ci   case 2:
293bf215546Sopenharmony_ci      *x_out = 1;
294bf215546Sopenharmony_ci      *y_out = 2;
295bf215546Sopenharmony_ci      break;
296bf215546Sopenharmony_ci   case 4:
297bf215546Sopenharmony_ci      *x_out = 2;
298bf215546Sopenharmony_ci      *y_out = 2;
299bf215546Sopenharmony_ci      break;
300bf215546Sopenharmony_ci   case 8:
301bf215546Sopenharmony_ci      *x_out = 2;
302bf215546Sopenharmony_ci      *y_out = 4;
303bf215546Sopenharmony_ci      break;
304bf215546Sopenharmony_ci   default:
305bf215546Sopenharmony_ci      unreachable("Unsupported number of samples");
306bf215546Sopenharmony_ci   }
307bf215546Sopenharmony_ci}
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_cistatic void pvr_rt_mtile_info_init(struct pvr_device *device,
310bf215546Sopenharmony_ci                                   struct pvr_rt_mtile_info *info,
311bf215546Sopenharmony_ci                                   uint32_t width,
312bf215546Sopenharmony_ci                                   uint32_t height,
313bf215546Sopenharmony_ci                                   uint32_t samples)
314bf215546Sopenharmony_ci{
315bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
316bf215546Sopenharmony_ci   uint32_t samples_in_x;
317bf215546Sopenharmony_ci   uint32_t samples_in_y;
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   pvr_get_samples_in_xy(samples, &samples_in_x, &samples_in_y);
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   info->tile_size_x = PVR_GET_FEATURE_VALUE(dev_info, tile_size_x, 1);
322bf215546Sopenharmony_ci   info->tile_size_y = PVR_GET_FEATURE_VALUE(dev_info, tile_size_y, 1);
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   info->num_tiles_x = DIV_ROUND_UP(width, info->tile_size_x);
325bf215546Sopenharmony_ci   info->num_tiles_y = DIV_ROUND_UP(height, info->tile_size_y);
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   rogue_get_num_macrotiles_xy(dev_info, &info->mtiles_x, &info->mtiles_y);
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
330bf215546Sopenharmony_ci      assert(PVR_GET_FEATURE_VALUE(dev_info,
331bf215546Sopenharmony_ci                                   simple_parameter_format_version,
332bf215546Sopenharmony_ci                                   0) == 2);
333bf215546Sopenharmony_ci      /* Set up 16 macrotiles with a multiple of 2x2 tiles per macrotile,
334bf215546Sopenharmony_ci       * which is aligned to a tile group.
335bf215546Sopenharmony_ci       */
336bf215546Sopenharmony_ci      info->mtile_x1 = DIV_ROUND_UP(info->num_tiles_x, 8) * 2;
337bf215546Sopenharmony_ci      info->mtile_y1 = DIV_ROUND_UP(info->num_tiles_y, 8) * 2;
338bf215546Sopenharmony_ci      info->mtile_x2 = 0;
339bf215546Sopenharmony_ci      info->mtile_y2 = 0;
340bf215546Sopenharmony_ci      info->mtile_x3 = 0;
341bf215546Sopenharmony_ci      info->mtile_y3 = 0;
342bf215546Sopenharmony_ci      info->x_tile_max = ALIGN_POT(info->num_tiles_x, 2) - 1;
343bf215546Sopenharmony_ci      info->y_tile_max = ALIGN_POT(info->num_tiles_y, 2) - 1;
344bf215546Sopenharmony_ci   } else {
345bf215546Sopenharmony_ci      /* Set up 16 macrotiles with a multiple of 4x4 tiles per macrotile. */
346bf215546Sopenharmony_ci      info->mtile_x1 = ALIGN_POT(DIV_ROUND_UP(info->num_tiles_x, 4), 4);
347bf215546Sopenharmony_ci      info->mtile_y1 = ALIGN_POT(DIV_ROUND_UP(info->num_tiles_y, 4), 4);
348bf215546Sopenharmony_ci      info->mtile_x2 = info->mtile_x1 * 2;
349bf215546Sopenharmony_ci      info->mtile_y2 = info->mtile_y1 * 2;
350bf215546Sopenharmony_ci      info->mtile_x3 = info->mtile_x1 * 3;
351bf215546Sopenharmony_ci      info->mtile_y3 = info->mtile_y1 * 3;
352bf215546Sopenharmony_ci      info->x_tile_max = info->num_tiles_x - 1;
353bf215546Sopenharmony_ci      info->y_tile_max = info->num_tiles_y - 1;
354bf215546Sopenharmony_ci   }
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   info->tiles_per_mtile_x = info->mtile_x1 * samples_in_x;
357bf215546Sopenharmony_ci   info->tiles_per_mtile_y = info->mtile_y1 * samples_in_y;
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   info->mtile_stride = info->mtile_x1 * info->mtile_y1;
360bf215546Sopenharmony_ci}
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci/* Note that the unit of the return value depends on the GPU. For cores with the
363bf215546Sopenharmony_ci * simple_internal_parameter_format feature the returned size is interpreted as
364bf215546Sopenharmony_ci * the number of region headers. For cores without this feature its interpreted
365bf215546Sopenharmony_ci * as the size in dwords.
366bf215546Sopenharmony_ci */
367bf215546Sopenharmony_cistatic uint64_t
368bf215546Sopenharmony_cipvr_rt_get_isp_region_size(struct pvr_device *device,
369bf215546Sopenharmony_ci                           const struct pvr_rt_mtile_info *mtile_info)
370bf215546Sopenharmony_ci{
371bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
372bf215546Sopenharmony_ci   uint64_t rgn_size =
373bf215546Sopenharmony_ci      mtile_info->tiles_per_mtile_x * mtile_info->tiles_per_mtile_y;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
376bf215546Sopenharmony_ci      uint32_t version;
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci      rgn_size *= mtile_info->mtiles_x * mtile_info->mtiles_y;
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci      if (PVR_FEATURE_VALUE(dev_info,
381bf215546Sopenharmony_ci                            simple_parameter_format_version,
382bf215546Sopenharmony_ci                            &version)) {
383bf215546Sopenharmony_ci         version = 0;
384bf215546Sopenharmony_ci      }
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci      if (version == 2) {
387bf215546Sopenharmony_ci         /* One region header per 2x2 tile group. */
388bf215546Sopenharmony_ci         rgn_size /= (2U * 2U);
389bf215546Sopenharmony_ci      }
390bf215546Sopenharmony_ci   } else {
391bf215546Sopenharmony_ci      const uint64_t rgn_header_size = rogue_get_region_header_size(dev_info);
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci      /* Round up to next dword to prevent IPF overrun and convert to bytes.
394bf215546Sopenharmony_ci       */
395bf215546Sopenharmony_ci      rgn_size = DIV_ROUND_UP(rgn_size * rgn_header_size, 4);
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   return rgn_size;
399bf215546Sopenharmony_ci}
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_cistatic VkResult pvr_rt_vheap_rtc_data_init(struct pvr_device *device,
402bf215546Sopenharmony_ci                                           struct pvr_rt_dataset *rt_dataset,
403bf215546Sopenharmony_ci                                           uint32_t layers)
404bf215546Sopenharmony_ci{
405bf215546Sopenharmony_ci   const uint64_t bo_flags = PVR_BO_ALLOC_FLAG_GPU_UNCACHED |
406bf215546Sopenharmony_ci                             PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC;
407bf215546Sopenharmony_ci   uint64_t vheap_size;
408bf215546Sopenharmony_ci   uint32_t alignment;
409bf215546Sopenharmony_ci   uint64_t rtc_size;
410bf215546Sopenharmony_ci   VkResult result;
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   vheap_size = ROGUE_CR_PM_VHEAP_TABLE_SIZE * ROGUE_PM_VHEAP_ENTRY_SIZE;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci   if (layers > 1) {
415bf215546Sopenharmony_ci      uint64_t rtc_entries;
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci      vheap_size = ALIGN_POT(vheap_size, PVRX(CR_TA_RTC_ADDR_BASE_ALIGNMENT));
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci      rtc_entries = ROGUE_NUM_TEAC + ROGUE_NUM_TE + ROGUE_NUM_VCE;
420bf215546Sopenharmony_ci      if (PVR_HAS_QUIRK(&device->pdevice->dev_info, 48545))
421bf215546Sopenharmony_ci         rtc_entries += ROGUE_NUM_TE;
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci      rtc_size = rtc_entries * ROGUE_RTC_SIZE_IN_BYTES;
424bf215546Sopenharmony_ci   } else {
425bf215546Sopenharmony_ci      rtc_size = 0;
426bf215546Sopenharmony_ci   }
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   alignment = MAX2(PVRX(CR_PM_VHEAP_TABLE_BASE_ADDR_ALIGNMENT),
429bf215546Sopenharmony_ci                    PVRX(CR_TA_RTC_ADDR_BASE_ALIGNMENT));
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
432bf215546Sopenharmony_ci                         device->heaps.general_heap,
433bf215546Sopenharmony_ci                         vheap_size + rtc_size,
434bf215546Sopenharmony_ci                         alignment,
435bf215546Sopenharmony_ci                         bo_flags,
436bf215546Sopenharmony_ci                         &rt_dataset->vheap_rtc_bo);
437bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
438bf215546Sopenharmony_ci      return result;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   rt_dataset->vheap_dev_addr = rt_dataset->vheap_rtc_bo->vma->dev_addr;
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   if (rtc_size > 0) {
443bf215546Sopenharmony_ci      rt_dataset->rtc_dev_addr =
444bf215546Sopenharmony_ci         PVR_DEV_ADDR_OFFSET(rt_dataset->vheap_dev_addr, vheap_size);
445bf215546Sopenharmony_ci   } else {
446bf215546Sopenharmony_ci      rt_dataset->rtc_dev_addr = PVR_DEV_ADDR_INVALID;
447bf215546Sopenharmony_ci   }
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   return VK_SUCCESS;
450bf215546Sopenharmony_ci}
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_cistatic void pvr_rt_vheap_rtc_data_fini(struct pvr_rt_dataset *rt_dataset)
453bf215546Sopenharmony_ci{
454bf215546Sopenharmony_ci   rt_dataset->rtc_dev_addr = PVR_DEV_ADDR_INVALID;
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   pvr_bo_free(rt_dataset->device, rt_dataset->vheap_rtc_bo);
457bf215546Sopenharmony_ci   rt_dataset->vheap_rtc_bo = NULL;
458bf215546Sopenharmony_ci}
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_cistatic void
461bf215546Sopenharmony_cipvr_rt_get_tail_ptr_stride_size(const struct pvr_device *device,
462bf215546Sopenharmony_ci                                const struct pvr_rt_mtile_info *mtile_info,
463bf215546Sopenharmony_ci                                uint32_t layers,
464bf215546Sopenharmony_ci                                uint64_t *const stride_out,
465bf215546Sopenharmony_ci                                uint64_t *const size_out)
466bf215546Sopenharmony_ci{
467bf215546Sopenharmony_ci   uint32_t max_num_mtiles;
468bf215546Sopenharmony_ci   uint32_t num_mtiles_x;
469bf215546Sopenharmony_ci   uint32_t num_mtiles_y;
470bf215546Sopenharmony_ci   uint32_t version;
471bf215546Sopenharmony_ci   uint64_t size;
472bf215546Sopenharmony_ci
473bf215546Sopenharmony_ci   num_mtiles_x = mtile_info->mtiles_x * mtile_info->tiles_per_mtile_x;
474bf215546Sopenharmony_ci   num_mtiles_y = mtile_info->mtiles_y * mtile_info->tiles_per_mtile_y;
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   max_num_mtiles = MAX2(util_next_power_of_two64(num_mtiles_x),
477bf215546Sopenharmony_ci                         util_next_power_of_two64(num_mtiles_y));
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   size = max_num_mtiles * max_num_mtiles;
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   if (PVR_FEATURE_VALUE(&device->pdevice->dev_info,
482bf215546Sopenharmony_ci                         simple_parameter_format_version,
483bf215546Sopenharmony_ci                         &version)) {
484bf215546Sopenharmony_ci      version = 0;
485bf215546Sopenharmony_ci   }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   if (version == 2) {
488bf215546Sopenharmony_ci      /* One tail pointer cache entry per 2x2 tile group. */
489bf215546Sopenharmony_ci      size /= (2U * 2U);
490bf215546Sopenharmony_ci   }
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci   size *= ROGUE_TAIL_POINTER_SIZE;
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci   if (layers > 1) {
495bf215546Sopenharmony_ci      size = ALIGN_POT(size, ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE);
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci      *stride_out = size / ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE;
498bf215546Sopenharmony_ci      *size_out = size * layers;
499bf215546Sopenharmony_ci   } else {
500bf215546Sopenharmony_ci      *stride_out = 0;
501bf215546Sopenharmony_ci      *size_out = size;
502bf215546Sopenharmony_ci   }
503bf215546Sopenharmony_ci}
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_cistatic VkResult pvr_rt_tpc_data_init(struct pvr_device *device,
506bf215546Sopenharmony_ci                                     struct pvr_rt_dataset *rt_dataset,
507bf215546Sopenharmony_ci                                     const struct pvr_rt_mtile_info *mtile_info,
508bf215546Sopenharmony_ci                                     uint32_t layers)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci   const uint64_t bo_flags = PVR_BO_ALLOC_FLAG_GPU_UNCACHED |
511bf215546Sopenharmony_ci                             PVR_BO_ALLOC_FLAG_ZERO_ON_ALLOC;
512bf215546Sopenharmony_ci   uint64_t tpc_size;
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_ci   pvr_rt_get_tail_ptr_stride_size(device,
515bf215546Sopenharmony_ci                                   mtile_info,
516bf215546Sopenharmony_ci                                   layers,
517bf215546Sopenharmony_ci                                   &rt_dataset->tpc_stride,
518bf215546Sopenharmony_ci                                   &rt_dataset->tpc_size);
519bf215546Sopenharmony_ci   tpc_size = ALIGN_POT(rt_dataset->tpc_size, ROGUE_TE_TPC_CACHE_LINE_SIZE);
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci   return pvr_bo_alloc(device,
522bf215546Sopenharmony_ci                       device->heaps.general_heap,
523bf215546Sopenharmony_ci                       tpc_size,
524bf215546Sopenharmony_ci                       PVRX(CR_TE_TPC_ADDR_BASE_ALIGNMENT),
525bf215546Sopenharmony_ci                       bo_flags,
526bf215546Sopenharmony_ci                       &rt_dataset->tpc_bo);
527bf215546Sopenharmony_ci}
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_cistatic void pvr_rt_tpc_data_fini(struct pvr_rt_dataset *rt_dataset)
530bf215546Sopenharmony_ci{
531bf215546Sopenharmony_ci   pvr_bo_free(rt_dataset->device, rt_dataset->tpc_bo);
532bf215546Sopenharmony_ci   rt_dataset->tpc_bo = NULL;
533bf215546Sopenharmony_ci}
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_cistatic uint32_t
536bf215546Sopenharmony_cipvr_rt_get_mlist_size(const struct pvr_free_list *global_free_list,
537bf215546Sopenharmony_ci                      const struct pvr_free_list *local_free_list)
538bf215546Sopenharmony_ci{
539bf215546Sopenharmony_ci   uint32_t num_pte_pages;
540bf215546Sopenharmony_ci   uint32_t num_pde_pages;
541bf215546Sopenharmony_ci   uint32_t num_pce_pages;
542bf215546Sopenharmony_ci   uint64_t total_pages;
543bf215546Sopenharmony_ci   uint32_t mlist_size;
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_ci   assert(global_free_list->size + local_free_list->size <=
546bf215546Sopenharmony_ci          ROGUE_PM_MAX_PB_VIRT_ADDR_SPACE);
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_ci   total_pages = (global_free_list->size + local_free_list->size) >>
549bf215546Sopenharmony_ci                 ROGUE_BIF_PM_PHYSICAL_PAGE_SHIFT;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci   /* Calculate the total number of physical pages required to hold the page
552bf215546Sopenharmony_ci    * table, directory and catalog entries for the freelist pages.
553bf215546Sopenharmony_ci    */
554bf215546Sopenharmony_ci   num_pte_pages = DIV_ROUND_UP(total_pages, ROGUE_NUM_PT_ENTRIES_PER_PAGE);
555bf215546Sopenharmony_ci   num_pde_pages = DIV_ROUND_UP(num_pte_pages, ROGUE_NUM_PD_ENTRIES_PER_PAGE);
556bf215546Sopenharmony_ci   num_pce_pages = DIV_ROUND_UP(num_pde_pages, ROGUE_NUM_PC_ENTRIES_PER_PAGE);
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   /* Calculate the MList size considering the total number of pages in the PB
559bf215546Sopenharmony_ci    * are shared among all the PM address spaces.
560bf215546Sopenharmony_ci    */
561bf215546Sopenharmony_ci   mlist_size = (num_pce_pages + num_pde_pages + num_pte_pages) *
562bf215546Sopenharmony_ci                ROGUE_NUM_PM_ADDRESS_SPACES * ROGUE_MLIST_ENTRY_STRIDE;
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_ci   return ALIGN_POT(mlist_size, ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE);
565bf215546Sopenharmony_ci}
566bf215546Sopenharmony_ci
567bf215546Sopenharmony_cistatic void pvr_rt_get_region_headers_stride_size(
568bf215546Sopenharmony_ci   const struct pvr_device *device,
569bf215546Sopenharmony_ci   const struct pvr_rt_mtile_info *mtile_info,
570bf215546Sopenharmony_ci   uint32_t layers,
571bf215546Sopenharmony_ci   uint64_t *const stride_out,
572bf215546Sopenharmony_ci   uint64_t *const size_out)
573bf215546Sopenharmony_ci{
574bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
575bf215546Sopenharmony_ci   const uint32_t rgn_header_size = rogue_get_region_header_size(dev_info);
576bf215546Sopenharmony_ci   uint32_t rgn_headers_size;
577bf215546Sopenharmony_ci   uint32_t num_tiles_x;
578bf215546Sopenharmony_ci   uint32_t num_tiles_y;
579bf215546Sopenharmony_ci   uint32_t group_size;
580bf215546Sopenharmony_ci   uint32_t version;
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci   if (PVR_FEATURE_VALUE(dev_info, simple_parameter_format_version, &version))
583bf215546Sopenharmony_ci      version = 0;
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   group_size = version == 2 ? 2 : 1;
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   num_tiles_x = mtile_info->mtiles_x * mtile_info->tiles_per_mtile_x;
588bf215546Sopenharmony_ci   num_tiles_y = mtile_info->mtiles_y * mtile_info->tiles_per_mtile_y;
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ci   rgn_headers_size =
591bf215546Sopenharmony_ci      (num_tiles_x / group_size) * (num_tiles_y / group_size) * rgn_header_size;
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
594bf215546Sopenharmony_ci      rgn_headers_size =
595bf215546Sopenharmony_ci         ALIGN_POT(rgn_headers_size, PVRX(CR_TE_PSGREGION_ADDR_BASE_ALIGNMENT));
596bf215546Sopenharmony_ci   }
597bf215546Sopenharmony_ci
598bf215546Sopenharmony_ci   if (layers > 1) {
599bf215546Sopenharmony_ci      rgn_headers_size =
600bf215546Sopenharmony_ci         ALIGN_POT(rgn_headers_size, PVRX(CR_TE_PSG_REGION_STRIDE_UNIT_SIZE));
601bf215546Sopenharmony_ci   }
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci   *stride_out = rgn_header_size;
604bf215546Sopenharmony_ci   *size_out = rgn_headers_size * layers;
605bf215546Sopenharmony_ci}
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_cistatic VkResult
608bf215546Sopenharmony_cipvr_rt_mta_mlist_data_init(struct pvr_device *device,
609bf215546Sopenharmony_ci                           struct pvr_rt_dataset *rt_dataset,
610bf215546Sopenharmony_ci                           const struct pvr_free_list *global_free_list,
611bf215546Sopenharmony_ci                           const struct pvr_free_list *local_free_list,
612bf215546Sopenharmony_ci                           const struct pvr_rt_mtile_info *mtile_info)
613bf215546Sopenharmony_ci{
614bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
615bf215546Sopenharmony_ci   const uint32_t mlist_size =
616bf215546Sopenharmony_ci      pvr_rt_get_mlist_size(global_free_list, local_free_list);
617bf215546Sopenharmony_ci   uint32_t mta_size = rogue_get_macrotile_array_size(dev_info);
618bf215546Sopenharmony_ci   const uint32_t num_rt_datas = ARRAY_SIZE(rt_dataset->rt_datas);
619bf215546Sopenharmony_ci   uint32_t rt_datas_mlist_size;
620bf215546Sopenharmony_ci   uint32_t rt_datas_mta_size;
621bf215546Sopenharmony_ci   pvr_dev_addr_t dev_addr;
622bf215546Sopenharmony_ci   VkResult result;
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_ci   /* Allocate memory for macrotile array and Mlist for all RT datas.
625bf215546Sopenharmony_ci    *
626bf215546Sopenharmony_ci    * Allocation layout: MTA[0..N] + Mlist alignment padding + Mlist[0..N].
627bf215546Sopenharmony_ci    *
628bf215546Sopenharmony_ci    * N is number of RT datas.
629bf215546Sopenharmony_ci    */
630bf215546Sopenharmony_ci   rt_datas_mta_size = ALIGN_POT(mta_size * num_rt_datas,
631bf215546Sopenharmony_ci                                 PVRX(CR_PM_MLIST0_BASE_ADDR_ALIGNMENT));
632bf215546Sopenharmony_ci   rt_datas_mlist_size = mlist_size * num_rt_datas;
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
635bf215546Sopenharmony_ci                         device->heaps.general_heap,
636bf215546Sopenharmony_ci                         rt_datas_mta_size + rt_datas_mlist_size,
637bf215546Sopenharmony_ci                         PVRX(CR_PM_MTILE_ARRAY_BASE_ADDR_ALIGNMENT),
638bf215546Sopenharmony_ci                         PVR_BO_ALLOC_FLAG_GPU_UNCACHED,
639bf215546Sopenharmony_ci                         &rt_dataset->mta_mlist_bo);
640bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
641bf215546Sopenharmony_ci      return result;
642bf215546Sopenharmony_ci
643bf215546Sopenharmony_ci   dev_addr = rt_dataset->mta_mlist_bo->vma->dev_addr;
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci   for (uint32_t i = 0; i < num_rt_datas; i++) {
646bf215546Sopenharmony_ci      if (mta_size != 0) {
647bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mta_dev_addr = dev_addr;
648bf215546Sopenharmony_ci         dev_addr = PVR_DEV_ADDR_OFFSET(dev_addr, mta_size);
649bf215546Sopenharmony_ci      } else {
650bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mta_dev_addr = PVR_DEV_ADDR_INVALID;
651bf215546Sopenharmony_ci      }
652bf215546Sopenharmony_ci   }
653bf215546Sopenharmony_ci
654bf215546Sopenharmony_ci   dev_addr = PVR_DEV_ADDR_OFFSET(rt_dataset->mta_mlist_bo->vma->dev_addr,
655bf215546Sopenharmony_ci                                  rt_datas_mta_size);
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci   for (uint32_t i = 0; i < num_rt_datas; i++) {
658bf215546Sopenharmony_ci      if (mlist_size != 0) {
659bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mlist_dev_addr = dev_addr;
660bf215546Sopenharmony_ci         dev_addr = PVR_DEV_ADDR_OFFSET(dev_addr, mlist_size);
661bf215546Sopenharmony_ci      } else {
662bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mlist_dev_addr = PVR_DEV_ADDR_INVALID;
663bf215546Sopenharmony_ci      }
664bf215546Sopenharmony_ci   }
665bf215546Sopenharmony_ci
666bf215546Sopenharmony_ci   return VK_SUCCESS;
667bf215546Sopenharmony_ci}
668bf215546Sopenharmony_ci
669bf215546Sopenharmony_cistatic void pvr_rt_mta_mlist_data_fini(struct pvr_rt_dataset *rt_dataset)
670bf215546Sopenharmony_ci{
671bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(rt_dataset->rt_datas); i++) {
672bf215546Sopenharmony_ci      rt_dataset->rt_datas[i].mlist_dev_addr = PVR_DEV_ADDR_INVALID;
673bf215546Sopenharmony_ci      rt_dataset->rt_datas[i].mta_dev_addr = PVR_DEV_ADDR_INVALID;
674bf215546Sopenharmony_ci   }
675bf215546Sopenharmony_ci
676bf215546Sopenharmony_ci   pvr_bo_free(rt_dataset->device, rt_dataset->mta_mlist_bo);
677bf215546Sopenharmony_ci   rt_dataset->mta_mlist_bo = NULL;
678bf215546Sopenharmony_ci}
679bf215546Sopenharmony_ci
680bf215546Sopenharmony_cistatic VkResult
681bf215546Sopenharmony_cipvr_rt_rgn_headers_data_init(struct pvr_device *device,
682bf215546Sopenharmony_ci                             struct pvr_rt_dataset *rt_dataset,
683bf215546Sopenharmony_ci                             const struct pvr_rt_mtile_info *mtile_info,
684bf215546Sopenharmony_ci                             uint32_t layers)
685bf215546Sopenharmony_ci{
686bf215546Sopenharmony_ci   const uint32_t num_rt_datas = ARRAY_SIZE(rt_dataset->rt_datas);
687bf215546Sopenharmony_ci   uint64_t rgn_headers_size;
688bf215546Sopenharmony_ci   pvr_dev_addr_t dev_addr;
689bf215546Sopenharmony_ci   VkResult result;
690bf215546Sopenharmony_ci
691bf215546Sopenharmony_ci   pvr_rt_get_region_headers_stride_size(device,
692bf215546Sopenharmony_ci                                         mtile_info,
693bf215546Sopenharmony_ci                                         layers,
694bf215546Sopenharmony_ci                                         &rt_dataset->rgn_headers_stride,
695bf215546Sopenharmony_ci                                         &rgn_headers_size);
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci   result = pvr_bo_alloc(device,
698bf215546Sopenharmony_ci                         device->heaps.rgn_hdr_heap,
699bf215546Sopenharmony_ci                         rgn_headers_size * num_rt_datas,
700bf215546Sopenharmony_ci                         PVRX(CR_TE_PSGREGION_ADDR_BASE_ALIGNMENT),
701bf215546Sopenharmony_ci                         PVR_BO_ALLOC_FLAG_GPU_UNCACHED,
702bf215546Sopenharmony_ci                         &rt_dataset->rgn_headers_bo);
703bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
704bf215546Sopenharmony_ci      return result;
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_ci   dev_addr = rt_dataset->rgn_headers_bo->vma->dev_addr;
707bf215546Sopenharmony_ci
708bf215546Sopenharmony_ci   for (uint32_t i = 0; i < num_rt_datas; i++) {
709bf215546Sopenharmony_ci      rt_dataset->rt_datas[i].rgn_headers_dev_addr = dev_addr;
710bf215546Sopenharmony_ci      dev_addr = PVR_DEV_ADDR_OFFSET(dev_addr, rgn_headers_size);
711bf215546Sopenharmony_ci   }
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci   return VK_SUCCESS;
714bf215546Sopenharmony_ci}
715bf215546Sopenharmony_ci
716bf215546Sopenharmony_cistatic void pvr_rt_rgn_headers_data_fini(struct pvr_rt_dataset *rt_dataset)
717bf215546Sopenharmony_ci{
718bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(rt_dataset->rt_datas); i++)
719bf215546Sopenharmony_ci      rt_dataset->rt_datas[i].rgn_headers_dev_addr = PVR_DEV_ADDR_INVALID;
720bf215546Sopenharmony_ci
721bf215546Sopenharmony_ci   pvr_bo_free(rt_dataset->device, rt_dataset->rgn_headers_bo);
722bf215546Sopenharmony_ci   rt_dataset->rgn_headers_bo = NULL;
723bf215546Sopenharmony_ci}
724bf215546Sopenharmony_ci
725bf215546Sopenharmony_cistatic VkResult pvr_rt_datas_init(struct pvr_device *device,
726bf215546Sopenharmony_ci                                  struct pvr_rt_dataset *rt_dataset,
727bf215546Sopenharmony_ci                                  const struct pvr_free_list *global_free_list,
728bf215546Sopenharmony_ci                                  const struct pvr_free_list *local_free_list,
729bf215546Sopenharmony_ci                                  const struct pvr_rt_mtile_info *mtile_info,
730bf215546Sopenharmony_ci                                  uint32_t layers)
731bf215546Sopenharmony_ci{
732bf215546Sopenharmony_ci   VkResult result;
733bf215546Sopenharmony_ci
734bf215546Sopenharmony_ci   result = pvr_rt_mta_mlist_data_init(device,
735bf215546Sopenharmony_ci                                       rt_dataset,
736bf215546Sopenharmony_ci                                       global_free_list,
737bf215546Sopenharmony_ci                                       local_free_list,
738bf215546Sopenharmony_ci                                       mtile_info);
739bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
740bf215546Sopenharmony_ci      return result;
741bf215546Sopenharmony_ci
742bf215546Sopenharmony_ci   result =
743bf215546Sopenharmony_ci      pvr_rt_rgn_headers_data_init(device, rt_dataset, mtile_info, layers);
744bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
745bf215546Sopenharmony_ci      goto err_pvr_rt_mta_mlist_data_fini;
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_ci   return VK_SUCCESS;
748bf215546Sopenharmony_ci
749bf215546Sopenharmony_cierr_pvr_rt_mta_mlist_data_fini:
750bf215546Sopenharmony_ci   pvr_rt_mta_mlist_data_fini(rt_dataset);
751bf215546Sopenharmony_ci
752bf215546Sopenharmony_ci   return VK_SUCCESS;
753bf215546Sopenharmony_ci}
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_cistatic void pvr_rt_datas_fini(struct pvr_rt_dataset *rt_dataset)
756bf215546Sopenharmony_ci{
757bf215546Sopenharmony_ci   pvr_rt_rgn_headers_data_fini(rt_dataset);
758bf215546Sopenharmony_ci   pvr_rt_mta_mlist_data_fini(rt_dataset);
759bf215546Sopenharmony_ci}
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_cistatic uint32_t
762bf215546Sopenharmony_cipvr_rogue_get_cr_isp_mtile_size_val(const struct pvr_device_info *dev_info,
763bf215546Sopenharmony_ci                                    uint32_t samples,
764bf215546Sopenharmony_ci                                    const struct pvr_rt_mtile_info *mtile_info)
765bf215546Sopenharmony_ci{
766bf215546Sopenharmony_ci   uint32_t samples_per_pixel =
767bf215546Sopenharmony_ci      PVR_GET_FEATURE_VALUE(dev_info, isp_samples_per_pixel, 0);
768bf215546Sopenharmony_ci   uint32_t isp_mtile_size;
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci   pvr_csb_pack (&isp_mtile_size, CR_ISP_MTILE_SIZE, value) {
771bf215546Sopenharmony_ci      value.x = mtile_info->mtile_x1;
772bf215546Sopenharmony_ci      value.y = mtile_info->mtile_y1;
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci      if (samples_per_pixel == 1) {
775bf215546Sopenharmony_ci         if (samples >= 4)
776bf215546Sopenharmony_ci            value.x <<= 1;
777bf215546Sopenharmony_ci
778bf215546Sopenharmony_ci         if (samples >= 2)
779bf215546Sopenharmony_ci            value.y <<= 1;
780bf215546Sopenharmony_ci      } else if (samples_per_pixel == 2) {
781bf215546Sopenharmony_ci         if (samples >= 8)
782bf215546Sopenharmony_ci            value.x <<= 1;
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_ci         if (samples >= 4)
785bf215546Sopenharmony_ci            value.y <<= 1;
786bf215546Sopenharmony_ci      } else if (samples_per_pixel == 4) {
787bf215546Sopenharmony_ci         if (samples >= 8)
788bf215546Sopenharmony_ci            value.y <<= 1;
789bf215546Sopenharmony_ci      } else {
790bf215546Sopenharmony_ci         assert(!"Unsupported ISP samples per pixel value");
791bf215546Sopenharmony_ci      }
792bf215546Sopenharmony_ci   }
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   return isp_mtile_size;
795bf215546Sopenharmony_ci}
796bf215546Sopenharmony_ci
797bf215546Sopenharmony_cistatic uint64_t pvr_rogue_get_cr_multisamplectl_val(uint32_t samples,
798bf215546Sopenharmony_ci                                                    bool y_flip)
799bf215546Sopenharmony_ci{
800bf215546Sopenharmony_ci   static const struct {
801bf215546Sopenharmony_ci      uint8_t x[8];
802bf215546Sopenharmony_ci      uint8_t y[8];
803bf215546Sopenharmony_ci   } sample_positions[4] = {
804bf215546Sopenharmony_ci      /* 1 sample */
805bf215546Sopenharmony_ci      {
806bf215546Sopenharmony_ci         .x = { 8 },
807bf215546Sopenharmony_ci         .y = { 8 },
808bf215546Sopenharmony_ci      },
809bf215546Sopenharmony_ci      /* 2 samples */
810bf215546Sopenharmony_ci      {
811bf215546Sopenharmony_ci         .x = { 12, 4 },
812bf215546Sopenharmony_ci         .y = { 12, 4 },
813bf215546Sopenharmony_ci      },
814bf215546Sopenharmony_ci      /* 4 samples */
815bf215546Sopenharmony_ci      {
816bf215546Sopenharmony_ci         .x = { 6, 14, 2, 10 },
817bf215546Sopenharmony_ci         .y = { 2, 6, 10, 14 },
818bf215546Sopenharmony_ci      },
819bf215546Sopenharmony_ci      /* 8 samples */
820bf215546Sopenharmony_ci      {
821bf215546Sopenharmony_ci         .x = { 9, 7, 13, 5, 3, 1, 11, 15 },
822bf215546Sopenharmony_ci         .y = { 5, 11, 9, 3, 13, 7, 15, 1 },
823bf215546Sopenharmony_ci      },
824bf215546Sopenharmony_ci   };
825bf215546Sopenharmony_ci   uint64_t multisamplectl;
826bf215546Sopenharmony_ci   uint8_t idx;
827bf215546Sopenharmony_ci
828bf215546Sopenharmony_ci   idx = util_fast_log2(samples);
829bf215546Sopenharmony_ci   assert(idx < ARRAY_SIZE(sample_positions));
830bf215546Sopenharmony_ci
831bf215546Sopenharmony_ci   pvr_csb_pack (&multisamplectl, CR_PPP_MULTISAMPLECTL, value) {
832bf215546Sopenharmony_ci      switch (samples) {
833bf215546Sopenharmony_ci      case 8:
834bf215546Sopenharmony_ci         value.msaa_x7 = sample_positions[idx].x[7];
835bf215546Sopenharmony_ci         value.msaa_x6 = sample_positions[idx].x[6];
836bf215546Sopenharmony_ci         value.msaa_x5 = sample_positions[idx].x[5];
837bf215546Sopenharmony_ci         value.msaa_x4 = sample_positions[idx].x[4];
838bf215546Sopenharmony_ci
839bf215546Sopenharmony_ci         if (y_flip) {
840bf215546Sopenharmony_ci            value.msaa_y7 = 16U - sample_positions[idx].y[7];
841bf215546Sopenharmony_ci            value.msaa_y6 = 16U - sample_positions[idx].y[6];
842bf215546Sopenharmony_ci            value.msaa_y5 = 16U - sample_positions[idx].y[5];
843bf215546Sopenharmony_ci            value.msaa_y4 = 16U - sample_positions[idx].y[4];
844bf215546Sopenharmony_ci         } else {
845bf215546Sopenharmony_ci            value.msaa_y7 = sample_positions[idx].y[7];
846bf215546Sopenharmony_ci            value.msaa_y6 = sample_positions[idx].y[6];
847bf215546Sopenharmony_ci            value.msaa_y5 = sample_positions[idx].y[5];
848bf215546Sopenharmony_ci            value.msaa_y4 = sample_positions[idx].y[4];
849bf215546Sopenharmony_ci         }
850bf215546Sopenharmony_ci
851bf215546Sopenharmony_ci         FALLTHROUGH;
852bf215546Sopenharmony_ci      case 4:
853bf215546Sopenharmony_ci         value.msaa_x3 = sample_positions[idx].x[3];
854bf215546Sopenharmony_ci         value.msaa_x2 = sample_positions[idx].x[2];
855bf215546Sopenharmony_ci
856bf215546Sopenharmony_ci         if (y_flip) {
857bf215546Sopenharmony_ci            value.msaa_y3 = 16U - sample_positions[idx].y[3];
858bf215546Sopenharmony_ci            value.msaa_y2 = 16U - sample_positions[idx].y[2];
859bf215546Sopenharmony_ci         } else {
860bf215546Sopenharmony_ci            value.msaa_y3 = sample_positions[idx].y[3];
861bf215546Sopenharmony_ci            value.msaa_y2 = sample_positions[idx].y[2];
862bf215546Sopenharmony_ci         }
863bf215546Sopenharmony_ci
864bf215546Sopenharmony_ci         FALLTHROUGH;
865bf215546Sopenharmony_ci      case 2:
866bf215546Sopenharmony_ci         value.msaa_x1 = sample_positions[idx].x[1];
867bf215546Sopenharmony_ci
868bf215546Sopenharmony_ci         if (y_flip) {
869bf215546Sopenharmony_ci            value.msaa_y1 = 16U - sample_positions[idx].y[1];
870bf215546Sopenharmony_ci         } else {
871bf215546Sopenharmony_ci            value.msaa_y1 = sample_positions[idx].y[1];
872bf215546Sopenharmony_ci         }
873bf215546Sopenharmony_ci
874bf215546Sopenharmony_ci         FALLTHROUGH;
875bf215546Sopenharmony_ci      case 1:
876bf215546Sopenharmony_ci         value.msaa_x0 = sample_positions[idx].x[0];
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci         if (y_flip) {
879bf215546Sopenharmony_ci            value.msaa_y0 = 16U - sample_positions[idx].y[0];
880bf215546Sopenharmony_ci         } else {
881bf215546Sopenharmony_ci            value.msaa_y0 = sample_positions[idx].y[0];
882bf215546Sopenharmony_ci         }
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_ci         break;
885bf215546Sopenharmony_ci      default:
886bf215546Sopenharmony_ci         unreachable("Unsupported number of samples");
887bf215546Sopenharmony_ci      }
888bf215546Sopenharmony_ci   }
889bf215546Sopenharmony_ci
890bf215546Sopenharmony_ci   return multisamplectl;
891bf215546Sopenharmony_ci}
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_cistatic uint32_t
894bf215546Sopenharmony_cipvr_rogue_get_cr_te_aa_val(const struct pvr_device_info *dev_info,
895bf215546Sopenharmony_ci                           uint32_t samples)
896bf215546Sopenharmony_ci{
897bf215546Sopenharmony_ci   uint32_t samples_per_pixel =
898bf215546Sopenharmony_ci      PVR_GET_FEATURE_VALUE(dev_info, isp_samples_per_pixel, 0);
899bf215546Sopenharmony_ci   uint32_t te_aa;
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_ci   pvr_csb_pack (&te_aa, CR_TE_AA, value) {
902bf215546Sopenharmony_ci      if (samples_per_pixel == 1) {
903bf215546Sopenharmony_ci         if (samples >= 2)
904bf215546Sopenharmony_ci            value.y = true;
905bf215546Sopenharmony_ci         if (samples >= 4)
906bf215546Sopenharmony_ci            value.x = true;
907bf215546Sopenharmony_ci      } else if (samples_per_pixel == 2) {
908bf215546Sopenharmony_ci         if (samples >= 2)
909bf215546Sopenharmony_ci            value.x2 = true;
910bf215546Sopenharmony_ci         if (samples >= 4)
911bf215546Sopenharmony_ci            value.y = true;
912bf215546Sopenharmony_ci         if (samples >= 8)
913bf215546Sopenharmony_ci            value.x = true;
914bf215546Sopenharmony_ci      } else if (samples_per_pixel == 4) {
915bf215546Sopenharmony_ci         if (samples >= 2)
916bf215546Sopenharmony_ci            value.x2 = true;
917bf215546Sopenharmony_ci         if (samples >= 4)
918bf215546Sopenharmony_ci            value.y2 = true;
919bf215546Sopenharmony_ci         if (samples >= 8)
920bf215546Sopenharmony_ci            value.y = true;
921bf215546Sopenharmony_ci      } else {
922bf215546Sopenharmony_ci         assert(!"Unsupported ISP samples per pixel value");
923bf215546Sopenharmony_ci      }
924bf215546Sopenharmony_ci   }
925bf215546Sopenharmony_ci
926bf215546Sopenharmony_ci   return te_aa;
927bf215546Sopenharmony_ci}
928bf215546Sopenharmony_ci
929bf215546Sopenharmony_cistatic void pvr_rt_dataset_ws_create_info_init(
930bf215546Sopenharmony_ci   struct pvr_rt_dataset *rt_dataset,
931bf215546Sopenharmony_ci   const struct pvr_rt_mtile_info *mtile_info,
932bf215546Sopenharmony_ci   struct pvr_winsys_rt_dataset_create_info *create_info)
933bf215546Sopenharmony_ci{
934bf215546Sopenharmony_ci   struct pvr_device *device = rt_dataset->device;
935bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
936bf215546Sopenharmony_ci
937bf215546Sopenharmony_ci   memset(create_info, 0, sizeof(*create_info));
938bf215546Sopenharmony_ci
939bf215546Sopenharmony_ci   /* Local freelist. */
940bf215546Sopenharmony_ci   create_info->local_free_list = rt_dataset->local_free_list->ws_free_list;
941bf215546Sopenharmony_ci
942bf215546Sopenharmony_ci   /* ISP register values. */
943bf215546Sopenharmony_ci   if (PVR_HAS_ERN(dev_info, 42307) &&
944bf215546Sopenharmony_ci       !(PVR_HAS_FEATURE(dev_info, roguexe) && mtile_info->tile_size_x == 16)) {
945bf215546Sopenharmony_ci      float value;
946bf215546Sopenharmony_ci
947bf215546Sopenharmony_ci      if (rt_dataset->width != 0) {
948bf215546Sopenharmony_ci         value =
949bf215546Sopenharmony_ci            ROGUE_ISP_MERGE_LOWER_LIMIT_NUMERATOR / (float)rt_dataset->width;
950bf215546Sopenharmony_ci         create_info->isp_merge_lower_x = fui(value);
951bf215546Sopenharmony_ci
952bf215546Sopenharmony_ci         value =
953bf215546Sopenharmony_ci            ROGUE_ISP_MERGE_UPPER_LIMIT_NUMERATOR / (float)rt_dataset->width;
954bf215546Sopenharmony_ci         create_info->isp_merge_upper_x = fui(value);
955bf215546Sopenharmony_ci      }
956bf215546Sopenharmony_ci
957bf215546Sopenharmony_ci      if (rt_dataset->height != 0) {
958bf215546Sopenharmony_ci         value =
959bf215546Sopenharmony_ci            ROGUE_ISP_MERGE_LOWER_LIMIT_NUMERATOR / (float)rt_dataset->height;
960bf215546Sopenharmony_ci         create_info->isp_merge_lower_y = fui(value);
961bf215546Sopenharmony_ci
962bf215546Sopenharmony_ci         value =
963bf215546Sopenharmony_ci            ROGUE_ISP_MERGE_UPPER_LIMIT_NUMERATOR / (float)rt_dataset->height;
964bf215546Sopenharmony_ci         create_info->isp_merge_upper_y = fui(value);
965bf215546Sopenharmony_ci      }
966bf215546Sopenharmony_ci
967bf215546Sopenharmony_ci      value = ((float)rt_dataset->width * ROGUE_ISP_MERGE_SCALE_FACTOR) /
968bf215546Sopenharmony_ci              (ROGUE_ISP_MERGE_UPPER_LIMIT_NUMERATOR -
969bf215546Sopenharmony_ci               ROGUE_ISP_MERGE_LOWER_LIMIT_NUMERATOR);
970bf215546Sopenharmony_ci      create_info->isp_merge_scale_x = fui(value);
971bf215546Sopenharmony_ci
972bf215546Sopenharmony_ci      value = ((float)rt_dataset->height * ROGUE_ISP_MERGE_SCALE_FACTOR) /
973bf215546Sopenharmony_ci              (ROGUE_ISP_MERGE_UPPER_LIMIT_NUMERATOR -
974bf215546Sopenharmony_ci               ROGUE_ISP_MERGE_LOWER_LIMIT_NUMERATOR);
975bf215546Sopenharmony_ci      create_info->isp_merge_scale_y = fui(value);
976bf215546Sopenharmony_ci   }
977bf215546Sopenharmony_ci
978bf215546Sopenharmony_ci   create_info->isp_mtile_size =
979bf215546Sopenharmony_ci      pvr_rogue_get_cr_isp_mtile_size_val(dev_info,
980bf215546Sopenharmony_ci                                          rt_dataset->samples,
981bf215546Sopenharmony_ci                                          mtile_info);
982bf215546Sopenharmony_ci
983bf215546Sopenharmony_ci   /* PPP register values. */
984bf215546Sopenharmony_ci   create_info->ppp_multi_sample_ctl =
985bf215546Sopenharmony_ci      pvr_rogue_get_cr_multisamplectl_val(rt_dataset->samples, false);
986bf215546Sopenharmony_ci   create_info->ppp_multi_sample_ctl_y_flipped =
987bf215546Sopenharmony_ci      pvr_rogue_get_cr_multisamplectl_val(rt_dataset->samples, true);
988bf215546Sopenharmony_ci
989bf215546Sopenharmony_ci   pvr_csb_pack (&create_info->ppp_screen, CR_PPP_SCREEN, value) {
990bf215546Sopenharmony_ci      value.pixxmax = rt_dataset->width - 1;
991bf215546Sopenharmony_ci      value.pixymax = rt_dataset->height - 1;
992bf215546Sopenharmony_ci   }
993bf215546Sopenharmony_ci
994bf215546Sopenharmony_ci   /* TE register values. */
995bf215546Sopenharmony_ci   create_info->te_aa =
996bf215546Sopenharmony_ci      pvr_rogue_get_cr_te_aa_val(dev_info, rt_dataset->samples);
997bf215546Sopenharmony_ci
998bf215546Sopenharmony_ci   pvr_csb_pack (&create_info->te_mtile1, CR_TE_MTILE1, value) {
999bf215546Sopenharmony_ci      value.x1 = mtile_info->mtile_x1;
1000bf215546Sopenharmony_ci      if (!PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
1001bf215546Sopenharmony_ci         value.x2 = mtile_info->mtile_x2;
1002bf215546Sopenharmony_ci         value.x3 = mtile_info->mtile_x3;
1003bf215546Sopenharmony_ci      }
1004bf215546Sopenharmony_ci   }
1005bf215546Sopenharmony_ci
1006bf215546Sopenharmony_ci   pvr_csb_pack (&create_info->te_mtile2, CR_TE_MTILE2, value) {
1007bf215546Sopenharmony_ci      value.y1 = mtile_info->mtile_y1;
1008bf215546Sopenharmony_ci      if (!PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
1009bf215546Sopenharmony_ci         value.y2 = mtile_info->mtile_y2;
1010bf215546Sopenharmony_ci         value.y3 = mtile_info->mtile_y3;
1011bf215546Sopenharmony_ci      }
1012bf215546Sopenharmony_ci   }
1013bf215546Sopenharmony_ci
1014bf215546Sopenharmony_ci   pvr_csb_pack (&create_info->te_screen, CR_TE_SCREEN, value) {
1015bf215546Sopenharmony_ci      value.xmax = mtile_info->x_tile_max;
1016bf215546Sopenharmony_ci      value.ymax = mtile_info->y_tile_max;
1017bf215546Sopenharmony_ci   }
1018bf215546Sopenharmony_ci
1019bf215546Sopenharmony_ci   /* Allocations and associated information. */
1020bf215546Sopenharmony_ci   create_info->vheap_table_dev_addr = rt_dataset->vheap_dev_addr;
1021bf215546Sopenharmony_ci   create_info->rtc_dev_addr = rt_dataset->rtc_dev_addr;
1022bf215546Sopenharmony_ci
1023bf215546Sopenharmony_ci   create_info->tpc_dev_addr = rt_dataset->tpc_bo->vma->dev_addr;
1024bf215546Sopenharmony_ci   create_info->tpc_stride = rt_dataset->tpc_stride;
1025bf215546Sopenharmony_ci   create_info->tpc_size = rt_dataset->tpc_size;
1026bf215546Sopenharmony_ci
1027bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(create_info->rt_datas) ==
1028bf215546Sopenharmony_ci                 ARRAY_SIZE(rt_dataset->rt_datas));
1029bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(create_info->rt_datas); i++) {
1030bf215546Sopenharmony_ci      create_info->rt_datas[i].pm_mlist_dev_addr =
1031bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mlist_dev_addr;
1032bf215546Sopenharmony_ci      create_info->rt_datas[i].macrotile_array_dev_addr =
1033bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].mta_dev_addr;
1034bf215546Sopenharmony_ci      create_info->rt_datas[i].rgn_header_dev_addr =
1035bf215546Sopenharmony_ci         rt_dataset->rt_datas[i].rgn_headers_dev_addr;
1036bf215546Sopenharmony_ci   }
1037bf215546Sopenharmony_ci
1038bf215546Sopenharmony_ci   create_info->rgn_header_size =
1039bf215546Sopenharmony_ci      pvr_rt_get_isp_region_size(device, mtile_info);
1040bf215546Sopenharmony_ci
1041bf215546Sopenharmony_ci   /* Miscellaneous. */
1042bf215546Sopenharmony_ci   create_info->mtile_stride = mtile_info->mtile_stride;
1043bf215546Sopenharmony_ci   create_info->max_rts = rt_dataset->layers;
1044bf215546Sopenharmony_ci}
1045bf215546Sopenharmony_ci
1046bf215546Sopenharmony_ciVkResult
1047bf215546Sopenharmony_cipvr_render_target_dataset_create(struct pvr_device *device,
1048bf215546Sopenharmony_ci                                 uint32_t width,
1049bf215546Sopenharmony_ci                                 uint32_t height,
1050bf215546Sopenharmony_ci                                 uint32_t samples,
1051bf215546Sopenharmony_ci                                 uint32_t layers,
1052bf215546Sopenharmony_ci                                 struct pvr_rt_dataset **const rt_dataset_out)
1053bf215546Sopenharmony_ci{
1054bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &device->pdevice->dev_info;
1055bf215546Sopenharmony_ci   struct pvr_winsys_rt_dataset_create_info rt_dataset_create_info;
1056bf215546Sopenharmony_ci   struct pvr_rt_mtile_info mtile_info;
1057bf215546Sopenharmony_ci   struct pvr_rt_dataset *rt_dataset;
1058bf215546Sopenharmony_ci   VkResult result;
1059bf215546Sopenharmony_ci
1060bf215546Sopenharmony_ci   assert(device->global_free_list);
1061bf215546Sopenharmony_ci   assert(width <= rogue_get_render_size_max_x(dev_info));
1062bf215546Sopenharmony_ci   assert(height <= rogue_get_render_size_max_y(dev_info));
1063bf215546Sopenharmony_ci   assert(layers > 0 && layers <= PVR_MAX_FRAMEBUFFER_LAYERS);
1064bf215546Sopenharmony_ci
1065bf215546Sopenharmony_ci   pvr_rt_mtile_info_init(device, &mtile_info, width, height, samples);
1066bf215546Sopenharmony_ci
1067bf215546Sopenharmony_ci   rt_dataset = vk_zalloc(&device->vk.alloc,
1068bf215546Sopenharmony_ci                          sizeof(*rt_dataset),
1069bf215546Sopenharmony_ci                          8,
1070bf215546Sopenharmony_ci                          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1071bf215546Sopenharmony_ci   if (!rt_dataset)
1072bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
1073bf215546Sopenharmony_ci
1074bf215546Sopenharmony_ci   rt_dataset->device = device;
1075bf215546Sopenharmony_ci   rt_dataset->width = width;
1076bf215546Sopenharmony_ci   rt_dataset->height = height;
1077bf215546Sopenharmony_ci   rt_dataset->samples = samples;
1078bf215546Sopenharmony_ci   rt_dataset->layers = layers;
1079bf215546Sopenharmony_ci   rt_dataset->global_free_list = device->global_free_list;
1080bf215546Sopenharmony_ci
1081bf215546Sopenharmony_ci   /* The maximum supported free list size is based on the assumption that this
1082bf215546Sopenharmony_ci    * freelist (the "local" freelist) is always the minimum size required by
1083bf215546Sopenharmony_ci    * the hardware. See the documentation of ROGUE_FREE_LIST_MAX_SIZE for more
1084bf215546Sopenharmony_ci    * details.
1085bf215546Sopenharmony_ci    */
1086bf215546Sopenharmony_ci   result = pvr_free_list_create(device,
1087bf215546Sopenharmony_ci                                 rogue_get_min_free_list_size(dev_info),
1088bf215546Sopenharmony_ci                                 rogue_get_min_free_list_size(dev_info),
1089bf215546Sopenharmony_ci                                 0 /* grow_size */,
1090bf215546Sopenharmony_ci                                 0 /* grow_threshold */,
1091bf215546Sopenharmony_ci                                 rt_dataset->global_free_list,
1092bf215546Sopenharmony_ci                                 &rt_dataset->local_free_list);
1093bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1094bf215546Sopenharmony_ci      goto err_vk_free_rt_dataset;
1095bf215546Sopenharmony_ci
1096bf215546Sopenharmony_ci   result = pvr_rt_vheap_rtc_data_init(device, rt_dataset, layers);
1097bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1098bf215546Sopenharmony_ci      goto err_pvr_free_list_destroy;
1099bf215546Sopenharmony_ci
1100bf215546Sopenharmony_ci   result = pvr_rt_tpc_data_init(device, rt_dataset, &mtile_info, layers);
1101bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1102bf215546Sopenharmony_ci      goto err_pvr_rt_vheap_rtc_data_fini;
1103bf215546Sopenharmony_ci
1104bf215546Sopenharmony_ci   result = pvr_rt_datas_init(device,
1105bf215546Sopenharmony_ci                              rt_dataset,
1106bf215546Sopenharmony_ci                              rt_dataset->global_free_list,
1107bf215546Sopenharmony_ci                              rt_dataset->local_free_list,
1108bf215546Sopenharmony_ci                              &mtile_info,
1109bf215546Sopenharmony_ci                              layers);
1110bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1111bf215546Sopenharmony_ci      goto err_pvr_rt_tpc_data_fini;
1112bf215546Sopenharmony_ci
1113bf215546Sopenharmony_ci   /* rt_dataset must be fully initialized by this point since
1114bf215546Sopenharmony_ci    * pvr_rt_dataset_ws_create_info_init() depends on this.
1115bf215546Sopenharmony_ci    */
1116bf215546Sopenharmony_ci   pvr_rt_dataset_ws_create_info_init(rt_dataset,
1117bf215546Sopenharmony_ci                                      &mtile_info,
1118bf215546Sopenharmony_ci                                      &rt_dataset_create_info);
1119bf215546Sopenharmony_ci
1120bf215546Sopenharmony_ci   result =
1121bf215546Sopenharmony_ci      device->ws->ops->render_target_dataset_create(device->ws,
1122bf215546Sopenharmony_ci                                                    &rt_dataset_create_info,
1123bf215546Sopenharmony_ci                                                    &rt_dataset->ws_rt_dataset);
1124bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1125bf215546Sopenharmony_ci      goto err_pvr_rt_datas_fini;
1126bf215546Sopenharmony_ci
1127bf215546Sopenharmony_ci   *rt_dataset_out = rt_dataset;
1128bf215546Sopenharmony_ci
1129bf215546Sopenharmony_ci   return VK_SUCCESS;
1130bf215546Sopenharmony_ci
1131bf215546Sopenharmony_cierr_pvr_rt_datas_fini:
1132bf215546Sopenharmony_ci   pvr_rt_datas_fini(rt_dataset);
1133bf215546Sopenharmony_ci
1134bf215546Sopenharmony_cierr_pvr_rt_tpc_data_fini:
1135bf215546Sopenharmony_ci   pvr_rt_tpc_data_fini(rt_dataset);
1136bf215546Sopenharmony_ci
1137bf215546Sopenharmony_cierr_pvr_rt_vheap_rtc_data_fini:
1138bf215546Sopenharmony_ci   pvr_rt_vheap_rtc_data_fini(rt_dataset);
1139bf215546Sopenharmony_ci
1140bf215546Sopenharmony_cierr_pvr_free_list_destroy:
1141bf215546Sopenharmony_ci   pvr_free_list_destroy(rt_dataset->local_free_list);
1142bf215546Sopenharmony_ci
1143bf215546Sopenharmony_cierr_vk_free_rt_dataset:
1144bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, rt_dataset);
1145bf215546Sopenharmony_ci
1146bf215546Sopenharmony_ci   return result;
1147bf215546Sopenharmony_ci}
1148bf215546Sopenharmony_ci
1149bf215546Sopenharmony_civoid pvr_render_target_dataset_destroy(struct pvr_rt_dataset *rt_dataset)
1150bf215546Sopenharmony_ci{
1151bf215546Sopenharmony_ci   struct pvr_device *device = rt_dataset->device;
1152bf215546Sopenharmony_ci
1153bf215546Sopenharmony_ci   device->ws->ops->render_target_dataset_destroy(rt_dataset->ws_rt_dataset);
1154bf215546Sopenharmony_ci
1155bf215546Sopenharmony_ci   pvr_rt_datas_fini(rt_dataset);
1156bf215546Sopenharmony_ci   pvr_rt_tpc_data_fini(rt_dataset);
1157bf215546Sopenharmony_ci   pvr_rt_vheap_rtc_data_fini(rt_dataset);
1158bf215546Sopenharmony_ci
1159bf215546Sopenharmony_ci   pvr_free_list_destroy(rt_dataset->local_free_list);
1160bf215546Sopenharmony_ci
1161bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, rt_dataset);
1162bf215546Sopenharmony_ci}
1163bf215546Sopenharmony_ci
1164bf215546Sopenharmony_cistatic void
1165bf215546Sopenharmony_cipvr_render_job_ws_geometry_state_init(struct pvr_render_ctx *ctx,
1166bf215546Sopenharmony_ci                                      struct pvr_render_job *job,
1167bf215546Sopenharmony_ci                                      struct pvr_winsys_geometry_state *state)
1168bf215546Sopenharmony_ci{
1169bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &ctx->device->pdevice->dev_info;
1170bf215546Sopenharmony_ci
1171bf215546Sopenharmony_ci   /* FIXME: Should this just be done unconditionally? The firmware will just
1172bf215546Sopenharmony_ci    * ignore the value anyway.
1173bf215546Sopenharmony_ci    */
1174bf215546Sopenharmony_ci   if (PVR_HAS_QUIRK(dev_info, 56279)) {
1175bf215546Sopenharmony_ci      pvr_csb_pack (&state->regs.pds_ctrl, CR_PDS_CTRL, value) {
1176bf215546Sopenharmony_ci         value.max_num_vdm_tasks = rogue_get_max_num_vdm_pds_tasks(dev_info);
1177bf215546Sopenharmony_ci      }
1178bf215546Sopenharmony_ci   } else {
1179bf215546Sopenharmony_ci      state->regs.pds_ctrl = 0;
1180bf215546Sopenharmony_ci   }
1181bf215546Sopenharmony_ci
1182bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.ppp_ctrl, CR_PPP_CTRL, value) {
1183bf215546Sopenharmony_ci      value.wclampen = true;
1184bf215546Sopenharmony_ci      value.fixed_point_format = 1;
1185bf215546Sopenharmony_ci   }
1186bf215546Sopenharmony_ci
1187bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.te_psg, CR_TE_PSG, value) {
1188bf215546Sopenharmony_ci      value.completeonterminate = job->geometry_terminate;
1189bf215546Sopenharmony_ci
1190bf215546Sopenharmony_ci      value.region_stride = job->rt_dataset->rgn_headers_stride /
1191bf215546Sopenharmony_ci                            PVRX(CR_TE_PSG_REGION_STRIDE_UNIT_SIZE);
1192bf215546Sopenharmony_ci
1193bf215546Sopenharmony_ci      value.forcenewstate = PVR_HAS_QUIRK(dev_info, 52942);
1194bf215546Sopenharmony_ci   }
1195bf215546Sopenharmony_ci
1196bf215546Sopenharmony_ci   /* The set up of CR_TPU must be identical to
1197bf215546Sopenharmony_ci    * pvr_render_job_ws_fragment_state_init().
1198bf215546Sopenharmony_ci    */
1199bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.tpu, CR_TPU, value) {
1200bf215546Sopenharmony_ci      value.tag_cem_4k_face_packing = true;
1201bf215546Sopenharmony_ci   }
1202bf215546Sopenharmony_ci
1203bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.tpu_border_colour_table,
1204bf215546Sopenharmony_ci                 CR_TPU_BORDER_COLOUR_TABLE_VDM,
1205bf215546Sopenharmony_ci                 value) {
1206bf215546Sopenharmony_ci      value.border_colour_table_address = job->border_colour_table_addr;
1207bf215546Sopenharmony_ci   }
1208bf215546Sopenharmony_ci
1209bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.vdm_ctrl_stream_base,
1210bf215546Sopenharmony_ci                 CR_VDM_CTRL_STREAM_BASE,
1211bf215546Sopenharmony_ci                 value) {
1212bf215546Sopenharmony_ci      value.addr = job->ctrl_stream_addr;
1213bf215546Sopenharmony_ci   }
1214bf215546Sopenharmony_ci
1215bf215546Sopenharmony_ci   /* Set up the USC common size for the context switch resume/load program
1216bf215546Sopenharmony_ci    * (ctx->ctx_switch.programs[i].sr->pds_load_program), which was created
1217bf215546Sopenharmony_ci    * as part of the render context.
1218bf215546Sopenharmony_ci    */
1219bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.vdm_ctx_resume_task0_size,
1220bf215546Sopenharmony_ci                 VDMCTRL_PDS_STATE0,
1221bf215546Sopenharmony_ci                 value) {
1222bf215546Sopenharmony_ci      /* Calculate the size in bytes. */
1223bf215546Sopenharmony_ci      const uint16_t shared_registers_size = job->max_shared_registers * 4;
1224bf215546Sopenharmony_ci
1225bf215546Sopenharmony_ci      value.usc_common_size =
1226bf215546Sopenharmony_ci         DIV_ROUND_UP(shared_registers_size,
1227bf215546Sopenharmony_ci                      PVRX(VDMCTRL_PDS_STATE0_USC_COMMON_SIZE_UNIT_SIZE));
1228bf215546Sopenharmony_ci   };
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci   state->flags = 0;
1231bf215546Sopenharmony_ci
1232bf215546Sopenharmony_ci   if (!job->rt_dataset->need_frag)
1233bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_GEOM_FLAG_FIRST_GEOMETRY;
1234bf215546Sopenharmony_ci
1235bf215546Sopenharmony_ci   if (job->geometry_terminate)
1236bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_GEOM_FLAG_LAST_GEOMETRY;
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ci   if (job->frag_uses_atomic_ops)
1239bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_GEOM_FLAG_SINGLE_CORE;
1240bf215546Sopenharmony_ci}
1241bf215546Sopenharmony_ci
1242bf215546Sopenharmony_cistatic inline void
1243bf215546Sopenharmony_cipvr_get_isp_num_tiles_xy(const struct pvr_device_info *dev_info,
1244bf215546Sopenharmony_ci                         uint32_t samples,
1245bf215546Sopenharmony_ci                         uint32_t width,
1246bf215546Sopenharmony_ci                         uint32_t height,
1247bf215546Sopenharmony_ci                         uint32_t *const x_out,
1248bf215546Sopenharmony_ci                         uint32_t *const y_out)
1249bf215546Sopenharmony_ci{
1250bf215546Sopenharmony_ci   uint32_t tile_samples_x;
1251bf215546Sopenharmony_ci   uint32_t tile_samples_y;
1252bf215546Sopenharmony_ci   uint32_t scale_x;
1253bf215546Sopenharmony_ci   uint32_t scale_y;
1254bf215546Sopenharmony_ci
1255bf215546Sopenharmony_ci   rogue_get_isp_samples_per_tile_xy(dev_info,
1256bf215546Sopenharmony_ci                                     samples,
1257bf215546Sopenharmony_ci                                     &tile_samples_x,
1258bf215546Sopenharmony_ci                                     &tile_samples_y);
1259bf215546Sopenharmony_ci
1260bf215546Sopenharmony_ci   switch (samples) {
1261bf215546Sopenharmony_ci   case 1:
1262bf215546Sopenharmony_ci      scale_x = 1;
1263bf215546Sopenharmony_ci      scale_y = 1;
1264bf215546Sopenharmony_ci      break;
1265bf215546Sopenharmony_ci   case 2:
1266bf215546Sopenharmony_ci      scale_x = 1;
1267bf215546Sopenharmony_ci      scale_y = 2;
1268bf215546Sopenharmony_ci      break;
1269bf215546Sopenharmony_ci   case 4:
1270bf215546Sopenharmony_ci      scale_x = 2;
1271bf215546Sopenharmony_ci      scale_y = 2;
1272bf215546Sopenharmony_ci      break;
1273bf215546Sopenharmony_ci   case 8:
1274bf215546Sopenharmony_ci      scale_x = 2;
1275bf215546Sopenharmony_ci      scale_y = 4;
1276bf215546Sopenharmony_ci      break;
1277bf215546Sopenharmony_ci   default:
1278bf215546Sopenharmony_ci      unreachable("Unsupported number of samples");
1279bf215546Sopenharmony_ci   }
1280bf215546Sopenharmony_ci
1281bf215546Sopenharmony_ci   *x_out = DIV_ROUND_UP(width * scale_x, tile_samples_x);
1282bf215546Sopenharmony_ci   *y_out = DIV_ROUND_UP(height * scale_y, tile_samples_y);
1283bf215546Sopenharmony_ci
1284bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, simple_internal_parameter_format)) {
1285bf215546Sopenharmony_ci      assert(PVR_GET_FEATURE_VALUE(dev_info,
1286bf215546Sopenharmony_ci                                   simple_parameter_format_version,
1287bf215546Sopenharmony_ci                                   0U) == 2U);
1288bf215546Sopenharmony_ci      /* Align to a 2x2 tile block. */
1289bf215546Sopenharmony_ci      *x_out = ALIGN_POT(*x_out, 2);
1290bf215546Sopenharmony_ci      *y_out = ALIGN_POT(*y_out, 2);
1291bf215546Sopenharmony_ci   }
1292bf215546Sopenharmony_ci}
1293bf215546Sopenharmony_ci
1294bf215546Sopenharmony_cistatic void
1295bf215546Sopenharmony_cipvr_render_job_ws_fragment_state_init(struct pvr_render_ctx *ctx,
1296bf215546Sopenharmony_ci                                      struct pvr_render_job *job,
1297bf215546Sopenharmony_ci                                      struct pvr_winsys_fragment_state *state)
1298bf215546Sopenharmony_ci{
1299bf215546Sopenharmony_ci   const enum PVRX(CR_ISP_AA_MODE_TYPE)
1300bf215546Sopenharmony_ci      isp_aa_mode = pvr_cr_isp_aa_mode_type(job->samples);
1301bf215546Sopenharmony_ci   const struct pvr_device_runtime_info *dev_runtime_info =
1302bf215546Sopenharmony_ci      &ctx->device->pdevice->dev_runtime_info;
1303bf215546Sopenharmony_ci   const struct pvr_device_info *dev_info = &ctx->device->pdevice->dev_info;
1304bf215546Sopenharmony_ci   uint32_t isp_ctl;
1305bf215546Sopenharmony_ci
1306bf215546Sopenharmony_ci   /* FIXME: what to do when job->run_frag is false? */
1307bf215546Sopenharmony_ci
1308bf215546Sopenharmony_ci   /* FIXME: pass in the number of samples rather than isp_aa_mode? */
1309bf215546Sopenharmony_ci   pvr_setup_tiles_in_flight(dev_info,
1310bf215546Sopenharmony_ci                             dev_runtime_info,
1311bf215546Sopenharmony_ci                             isp_aa_mode,
1312bf215546Sopenharmony_ci                             job->pixel_output_width,
1313bf215546Sopenharmony_ci                             false,
1314bf215546Sopenharmony_ci                             job->max_tiles_in_flight,
1315bf215546Sopenharmony_ci                             &isp_ctl,
1316bf215546Sopenharmony_ci                             &state->regs.usc_pixel_output_ctrl);
1317bf215546Sopenharmony_ci
1318bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_ctl, CR_ISP_CTL, value) {
1319bf215546Sopenharmony_ci      value.sample_pos = true;
1320bf215546Sopenharmony_ci
1321bf215546Sopenharmony_ci      /* FIXME: There are a number of things that cause this to be set, this
1322bf215546Sopenharmony_ci       * is just one of them.
1323bf215546Sopenharmony_ci       */
1324bf215546Sopenharmony_ci      value.process_empty_tiles = job->process_empty_tiles;
1325bf215546Sopenharmony_ci   }
1326bf215546Sopenharmony_ci
1327bf215546Sopenharmony_ci   /* FIXME: When pvr_setup_tiles_in_flight() is refactored it might be
1328bf215546Sopenharmony_ci    * possible to fully pack CR_ISP_CTL above rather than having to OR in part
1329bf215546Sopenharmony_ci    * of the value.
1330bf215546Sopenharmony_ci    */
1331bf215546Sopenharmony_ci   state->regs.isp_ctl |= isp_ctl;
1332bf215546Sopenharmony_ci
1333bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_aa, CR_ISP_AA, value) {
1334bf215546Sopenharmony_ci      value.mode = isp_aa_mode;
1335bf215546Sopenharmony_ci   }
1336bf215546Sopenharmony_ci
1337bf215546Sopenharmony_ci   /* The set up of CR_TPU must be identical to
1338bf215546Sopenharmony_ci    * pvr_render_job_ws_geometry_state_init().
1339bf215546Sopenharmony_ci    */
1340bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.tpu, CR_TPU, value) {
1341bf215546Sopenharmony_ci      value.tag_cem_4k_face_packing = true;
1342bf215546Sopenharmony_ci   }
1343bf215546Sopenharmony_ci
1344bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, cluster_grouping) &&
1345bf215546Sopenharmony_ci       PVR_HAS_FEATURE(dev_info, slc_mcu_cache_controls) &&
1346bf215546Sopenharmony_ci       dev_runtime_info->num_phantoms > 1 && job->frag_uses_atomic_ops) {
1347bf215546Sopenharmony_ci      /* Each phantom has its own MCU, so atomicity can only be guaranteed
1348bf215546Sopenharmony_ci       * when all work items are processed on the same phantom. This means we
1349bf215546Sopenharmony_ci       * need to disable all USCs other than those of the first phantom, which
1350bf215546Sopenharmony_ci       * has 4 clusters. Note that we only need to do this for atomic
1351bf215546Sopenharmony_ci       * operations in fragment shaders, since hardware prevents the TA to run
1352bf215546Sopenharmony_ci       * on more than one phantom anyway.
1353bf215546Sopenharmony_ci       */
1354bf215546Sopenharmony_ci      state->regs.pixel_phantom = 0xF;
1355bf215546Sopenharmony_ci   } else {
1356bf215546Sopenharmony_ci      state->regs.pixel_phantom = 0;
1357bf215546Sopenharmony_ci   }
1358bf215546Sopenharmony_ci
1359bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_bgobjvals, CR_ISP_BGOBJVALS, value) {
1360bf215546Sopenharmony_ci      value.enablebgtag = job->enable_bg_tag;
1361bf215546Sopenharmony_ci
1362bf215546Sopenharmony_ci      value.mask = true;
1363bf215546Sopenharmony_ci
1364bf215546Sopenharmony_ci      /* FIXME: Hard code this for now as we don't currently support any
1365bf215546Sopenharmony_ci       * stencil image formats.
1366bf215546Sopenharmony_ci       */
1367bf215546Sopenharmony_ci      value.stencil = 0xFF;
1368bf215546Sopenharmony_ci   }
1369bf215546Sopenharmony_ci
1370bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_bgobjdepth, CR_ISP_BGOBJDEPTH, value) {
1371bf215546Sopenharmony_ci      /* FIXME: This is suitable for the single depth format the driver
1372bf215546Sopenharmony_ci       * currently supports, but may need updating to handle other depth
1373bf215546Sopenharmony_ci       * formats.
1374bf215546Sopenharmony_ci       */
1375bf215546Sopenharmony_ci      value.value = fui(job->depth_clear_value);
1376bf215546Sopenharmony_ci   }
1377bf215546Sopenharmony_ci
1378bf215546Sopenharmony_ci   /* FIXME: Some additional set up needed to support depth and stencil
1379bf215546Sopenharmony_ci    * load/store operations.
1380bf215546Sopenharmony_ci    */
1381bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_zlsctl, CR_ISP_ZLSCTL, value) {
1382bf215546Sopenharmony_ci      uint32_t aligned_width =
1383bf215546Sopenharmony_ci         ALIGN_POT(job->depth_physical_width, ROGUE_IPF_TILE_SIZE_PIXELS);
1384bf215546Sopenharmony_ci      uint32_t aligned_height =
1385bf215546Sopenharmony_ci         ALIGN_POT(job->depth_physical_height, ROGUE_IPF_TILE_SIZE_PIXELS);
1386bf215546Sopenharmony_ci
1387bf215546Sopenharmony_ci      pvr_get_isp_num_tiles_xy(dev_info,
1388bf215546Sopenharmony_ci                               job->samples,
1389bf215546Sopenharmony_ci                               aligned_width,
1390bf215546Sopenharmony_ci                               aligned_height,
1391bf215546Sopenharmony_ci                               &value.zlsextent_x_z,
1392bf215546Sopenharmony_ci                               &value.zlsextent_y_z);
1393bf215546Sopenharmony_ci      value.zlsextent_x_z -= 1;
1394bf215546Sopenharmony_ci      value.zlsextent_y_z -= 1;
1395bf215546Sopenharmony_ci
1396bf215546Sopenharmony_ci      if (job->depth_memlayout == PVR_MEMLAYOUT_TWIDDLED) {
1397bf215546Sopenharmony_ci         value.loadtwiddled = true;
1398bf215546Sopenharmony_ci         value.storetwiddled = true;
1399bf215546Sopenharmony_ci      }
1400bf215546Sopenharmony_ci
1401bf215546Sopenharmony_ci      /* FIXME: This is suitable for the single depth format the driver
1402bf215546Sopenharmony_ci       * currently supports, but may need updating to handle other depth
1403bf215546Sopenharmony_ci       * formats.
1404bf215546Sopenharmony_ci       */
1405bf215546Sopenharmony_ci      assert(job->depth_vk_format == VK_FORMAT_D32_SFLOAT);
1406bf215546Sopenharmony_ci      value.zloadformat = PVRX(CR_ZLOADFORMAT_TYPE_F32Z);
1407bf215546Sopenharmony_ci      value.zstoreformat = PVRX(CR_ZSTOREFORMAT_TYPE_F32Z);
1408bf215546Sopenharmony_ci   }
1409bf215546Sopenharmony_ci
1410bf215546Sopenharmony_ci   if (PVR_HAS_FEATURE(dev_info, zls_subtile)) {
1411bf215546Sopenharmony_ci      pvr_csb_pack (&state->regs.isp_zls_pixels, CR_ISP_ZLS_PIXELS, value) {
1412bf215546Sopenharmony_ci         value.x = job->depth_stride - 1;
1413bf215546Sopenharmony_ci         value.y = job->depth_height - 1;
1414bf215546Sopenharmony_ci      }
1415bf215546Sopenharmony_ci   } else {
1416bf215546Sopenharmony_ci      state->regs.isp_zls_pixels = 0;
1417bf215546Sopenharmony_ci   }
1418bf215546Sopenharmony_ci
1419bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_zload_store_base, CR_ISP_ZLOAD_BASE, value) {
1420bf215546Sopenharmony_ci      value.addr = job->depth_addr;
1421bf215546Sopenharmony_ci   }
1422bf215546Sopenharmony_ci
1423bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_stencil_load_store_base,
1424bf215546Sopenharmony_ci                 CR_ISP_STENCIL_LOAD_BASE,
1425bf215546Sopenharmony_ci                 value) {
1426bf215546Sopenharmony_ci      value.addr = job->stencil_addr;
1427bf215546Sopenharmony_ci
1428bf215546Sopenharmony_ci      /* FIXME: May need to set value.enable to true. */
1429bf215546Sopenharmony_ci   }
1430bf215546Sopenharmony_ci
1431bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.tpu_border_colour_table,
1432bf215546Sopenharmony_ci                 CR_TPU_BORDER_COLOUR_TABLE_PDM,
1433bf215546Sopenharmony_ci                 value) {
1434bf215546Sopenharmony_ci      value.border_colour_table_address = job->border_colour_table_addr;
1435bf215546Sopenharmony_ci   }
1436bf215546Sopenharmony_ci
1437bf215546Sopenharmony_ci   state->regs.isp_oclqry_base = 0;
1438bf215546Sopenharmony_ci
1439bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_dbias_base, CR_ISP_DBIAS_BASE, value) {
1440bf215546Sopenharmony_ci      value.addr = job->depth_bias_table_addr;
1441bf215546Sopenharmony_ci   }
1442bf215546Sopenharmony_ci
1443bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.isp_scissor_base, CR_ISP_SCISSOR_BASE, value) {
1444bf215546Sopenharmony_ci      value.addr = job->scissor_table_addr;
1445bf215546Sopenharmony_ci   }
1446bf215546Sopenharmony_ci
1447bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.event_pixel_pds_info,
1448bf215546Sopenharmony_ci                 CR_EVENT_PIXEL_PDS_INFO,
1449bf215546Sopenharmony_ci                 value) {
1450bf215546Sopenharmony_ci      value.const_size =
1451bf215546Sopenharmony_ci         DIV_ROUND_UP(ctx->device->pixel_event_data_size_in_dwords,
1452bf215546Sopenharmony_ci                      PVRX(CR_EVENT_PIXEL_PDS_INFO_CONST_SIZE_UNIT_SIZE));
1453bf215546Sopenharmony_ci      value.temp_stride = 0;
1454bf215546Sopenharmony_ci      value.usc_sr_size =
1455bf215546Sopenharmony_ci         DIV_ROUND_UP(PVR_STATE_PBE_DWORDS,
1456bf215546Sopenharmony_ci                      PVRX(CR_EVENT_PIXEL_PDS_INFO_USC_SR_SIZE_UNIT_SIZE));
1457bf215546Sopenharmony_ci   }
1458bf215546Sopenharmony_ci
1459bf215546Sopenharmony_ci   pvr_csb_pack (&state->regs.event_pixel_pds_data,
1460bf215546Sopenharmony_ci                 CR_EVENT_PIXEL_PDS_DATA,
1461bf215546Sopenharmony_ci                 value) {
1462bf215546Sopenharmony_ci      value.addr = PVR_DEV_ADDR(job->pds_pixel_event_data_offset);
1463bf215546Sopenharmony_ci   }
1464bf215546Sopenharmony_ci
1465bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(state->regs.pbe_word) ==
1466bf215546Sopenharmony_ci                 ARRAY_SIZE(job->pbe_reg_words));
1467bf215546Sopenharmony_ci   STATIC_ASSERT(ARRAY_SIZE(state->regs.pbe_word[0]) ==
1468bf215546Sopenharmony_ci                 ARRAY_SIZE(job->pbe_reg_words[0]));
1469bf215546Sopenharmony_ci
1470bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(job->pbe_reg_words); i++) {
1471bf215546Sopenharmony_ci      state->regs.pbe_word[i][0] = job->pbe_reg_words[i][0];
1472bf215546Sopenharmony_ci      state->regs.pbe_word[i][1] = job->pbe_reg_words[i][1];
1473bf215546Sopenharmony_ci      state->regs.pbe_word[i][2] = job->pbe_reg_words[i][2];
1474bf215546Sopenharmony_ci   }
1475bf215546Sopenharmony_ci
1476bf215546Sopenharmony_ci   STATIC_ASSERT(__same_type(state->regs.pds_bgnd, job->pds_bgnd_reg_values));
1477bf215546Sopenharmony_ci   typed_memcpy(state->regs.pds_bgnd,
1478bf215546Sopenharmony_ci                job->pds_bgnd_reg_values,
1479bf215546Sopenharmony_ci                ARRAY_SIZE(state->regs.pds_bgnd));
1480bf215546Sopenharmony_ci
1481bf215546Sopenharmony_ci   memset(state->regs.pds_pr_bgnd, 0, sizeof(state->regs.pds_pr_bgnd));
1482bf215546Sopenharmony_ci
1483bf215546Sopenharmony_ci   /* FIXME: Merge geometry and fragment flags into a single flags member? */
1484bf215546Sopenharmony_ci   /* FIXME: move to its own function? */
1485bf215546Sopenharmony_ci   state->flags = 0;
1486bf215546Sopenharmony_ci
1487bf215546Sopenharmony_ci   if (job->depth_addr.addr)
1488bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_FRAG_FLAG_DEPTH_BUFFER_PRESENT;
1489bf215546Sopenharmony_ci
1490bf215546Sopenharmony_ci   if (job->stencil_addr.addr)
1491bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_FRAG_FLAG_STENCIL_BUFFER_PRESENT;
1492bf215546Sopenharmony_ci
1493bf215546Sopenharmony_ci   if (job->disable_compute_overlap)
1494bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_FRAG_FLAG_PREVENT_CDM_OVERLAP;
1495bf215546Sopenharmony_ci
1496bf215546Sopenharmony_ci   if (job->frag_uses_atomic_ops)
1497bf215546Sopenharmony_ci      state->flags |= PVR_WINSYS_FRAG_FLAG_SINGLE_CORE;
1498bf215546Sopenharmony_ci
1499bf215546Sopenharmony_ci   state->zls_stride = job->depth_layer_size;
1500bf215546Sopenharmony_ci   state->sls_stride = job->depth_layer_size;
1501bf215546Sopenharmony_ci}
1502bf215546Sopenharmony_ci
1503bf215546Sopenharmony_cistatic void pvr_render_job_ws_submit_info_init(
1504bf215546Sopenharmony_ci   struct pvr_render_ctx *ctx,
1505bf215546Sopenharmony_ci   struct pvr_render_job *job,
1506bf215546Sopenharmony_ci   const struct pvr_winsys_job_bo *bos,
1507bf215546Sopenharmony_ci   uint32_t bo_count,
1508bf215546Sopenharmony_ci   struct vk_sync **waits,
1509bf215546Sopenharmony_ci   uint32_t wait_count,
1510bf215546Sopenharmony_ci   uint32_t *stage_flags,
1511bf215546Sopenharmony_ci   struct pvr_winsys_render_submit_info *submit_info)
1512bf215546Sopenharmony_ci{
1513bf215546Sopenharmony_ci   memset(submit_info, 0, sizeof(*submit_info));
1514bf215546Sopenharmony_ci
1515bf215546Sopenharmony_ci   submit_info->rt_dataset = job->rt_dataset->ws_rt_dataset;
1516bf215546Sopenharmony_ci   submit_info->rt_data_idx = job->rt_dataset->rt_data_idx;
1517bf215546Sopenharmony_ci
1518bf215546Sopenharmony_ci   submit_info->frame_num = ctx->device->global_queue_present_count;
1519bf215546Sopenharmony_ci   submit_info->job_num = ctx->device->global_queue_job_count;
1520bf215546Sopenharmony_ci
1521bf215546Sopenharmony_ci   submit_info->run_frag = job->run_frag;
1522bf215546Sopenharmony_ci
1523bf215546Sopenharmony_ci   submit_info->bos = bos;
1524bf215546Sopenharmony_ci   submit_info->bo_count = bo_count;
1525bf215546Sopenharmony_ci
1526bf215546Sopenharmony_ci   submit_info->waits = waits;
1527bf215546Sopenharmony_ci   submit_info->wait_count = wait_count;
1528bf215546Sopenharmony_ci   submit_info->stage_flags = stage_flags;
1529bf215546Sopenharmony_ci
1530bf215546Sopenharmony_ci   /* FIXME: add WSI image bos. */
1531bf215546Sopenharmony_ci
1532bf215546Sopenharmony_ci   pvr_render_job_ws_geometry_state_init(ctx, job, &submit_info->geometry);
1533bf215546Sopenharmony_ci   pvr_render_job_ws_fragment_state_init(ctx, job, &submit_info->fragment);
1534bf215546Sopenharmony_ci
1535bf215546Sopenharmony_ci   /* These values are expected to match. */
1536bf215546Sopenharmony_ci   assert(submit_info->geometry.regs.tpu == submit_info->fragment.regs.tpu);
1537bf215546Sopenharmony_ci}
1538bf215546Sopenharmony_ci
1539bf215546Sopenharmony_ciVkResult pvr_render_job_submit(struct pvr_render_ctx *ctx,
1540bf215546Sopenharmony_ci                               struct pvr_render_job *job,
1541bf215546Sopenharmony_ci                               const struct pvr_winsys_job_bo *bos,
1542bf215546Sopenharmony_ci                               uint32_t bo_count,
1543bf215546Sopenharmony_ci                               struct vk_sync **waits,
1544bf215546Sopenharmony_ci                               uint32_t wait_count,
1545bf215546Sopenharmony_ci                               uint32_t *stage_flags,
1546bf215546Sopenharmony_ci                               struct vk_sync *signal_sync_geom,
1547bf215546Sopenharmony_ci                               struct vk_sync *signal_sync_frag)
1548bf215546Sopenharmony_ci{
1549bf215546Sopenharmony_ci   struct pvr_rt_dataset *rt_dataset = job->rt_dataset;
1550bf215546Sopenharmony_ci   struct pvr_winsys_render_submit_info submit_info;
1551bf215546Sopenharmony_ci   struct pvr_device *device = ctx->device;
1552bf215546Sopenharmony_ci   VkResult result;
1553bf215546Sopenharmony_ci
1554bf215546Sopenharmony_ci   pvr_render_job_ws_submit_info_init(ctx,
1555bf215546Sopenharmony_ci                                      job,
1556bf215546Sopenharmony_ci                                      bos,
1557bf215546Sopenharmony_ci                                      bo_count,
1558bf215546Sopenharmony_ci                                      waits,
1559bf215546Sopenharmony_ci                                      wait_count,
1560bf215546Sopenharmony_ci                                      stage_flags,
1561bf215546Sopenharmony_ci                                      &submit_info);
1562bf215546Sopenharmony_ci
1563bf215546Sopenharmony_ci   result = device->ws->ops->render_submit(ctx->ws_ctx,
1564bf215546Sopenharmony_ci                                           &submit_info,
1565bf215546Sopenharmony_ci                                           signal_sync_geom,
1566bf215546Sopenharmony_ci                                           signal_sync_frag);
1567bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
1568bf215546Sopenharmony_ci      return result;
1569bf215546Sopenharmony_ci
1570bf215546Sopenharmony_ci   if (job->run_frag) {
1571bf215546Sopenharmony_ci      /* Move to the next render target data now that a fragment job has been
1572bf215546Sopenharmony_ci       * successfully submitted. This will allow the next geometry job to be
1573bf215546Sopenharmony_ci       * submitted to been run in parallel with it.
1574bf215546Sopenharmony_ci       */
1575bf215546Sopenharmony_ci      rt_dataset->rt_data_idx =
1576bf215546Sopenharmony_ci         (rt_dataset->rt_data_idx + 1) % ARRAY_SIZE(rt_dataset->rt_datas);
1577bf215546Sopenharmony_ci
1578bf215546Sopenharmony_ci      rt_dataset->need_frag = false;
1579bf215546Sopenharmony_ci   } else {
1580bf215546Sopenharmony_ci      rt_dataset->need_frag = true;
1581bf215546Sopenharmony_ci   }
1582bf215546Sopenharmony_ci
1583bf215546Sopenharmony_ci   return VK_SUCCESS;
1584bf215546Sopenharmony_ci}
1585