1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2021 Alyssa Rosenzweig 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is 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 NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci# 24bf215546Sopenharmony_ci#include <stdint.h> 25bf215546Sopenharmony_ci#include "agx_state.h" 26bf215546Sopenharmony_ci#include "magic.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci/* The structures managed in this file appear to be software defined (either in 29bf215546Sopenharmony_ci * the macOS kernel driver or in the AGX firmware) */ 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci/* Odd pattern */ 32bf215546Sopenharmony_cistatic uint64_t 33bf215546Sopenharmony_cidemo_unk6(struct agx_pool *pool) 34bf215546Sopenharmony_ci{ 35bf215546Sopenharmony_ci struct agx_ptr ptr = agx_pool_alloc_aligned(pool, 0x4000 * sizeof(uint64_t), 64); 36bf215546Sopenharmony_ci uint64_t *buf = ptr.cpu; 37bf215546Sopenharmony_ci memset(buf, 0, sizeof(*buf)); 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci for (unsigned i = 1; i < 0x3ff; ++i) 40bf215546Sopenharmony_ci buf[i] = (i + 1); 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci return ptr.gpu; 43bf215546Sopenharmony_ci} 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cistatic uint64_t 46bf215546Sopenharmony_cidemo_zero(struct agx_pool *pool, unsigned count) 47bf215546Sopenharmony_ci{ 48bf215546Sopenharmony_ci struct agx_ptr ptr = agx_pool_alloc_aligned(pool, count, 64); 49bf215546Sopenharmony_ci memset(ptr.cpu, 0, count); 50bf215546Sopenharmony_ci return ptr.gpu; 51bf215546Sopenharmony_ci} 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_cistatic size_t 54bf215546Sopenharmony_ciasahi_size_resource(struct pipe_resource *prsrc, unsigned level) 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci struct agx_resource *rsrc = agx_resource(prsrc); 57bf215546Sopenharmony_ci size_t size = rsrc->slices[level].size; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci if (rsrc->separate_stencil) 60bf215546Sopenharmony_ci size += asahi_size_resource(&rsrc->separate_stencil->base, level); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci return size; 63bf215546Sopenharmony_ci} 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistatic size_t 66bf215546Sopenharmony_ciasahi_size_surface(struct pipe_surface *surf) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci return asahi_size_resource(surf->texture, surf->u.tex.level); 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic size_t 72bf215546Sopenharmony_ciasahi_size_attachments(struct pipe_framebuffer_state *framebuffer) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci size_t sum = 0; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci for (unsigned i = 0; i < framebuffer->nr_cbufs; ++i) 77bf215546Sopenharmony_ci sum += asahi_size_surface(framebuffer->cbufs[i]); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci if (framebuffer->zsbuf) 80bf215546Sopenharmony_ci sum += asahi_size_surface(framebuffer->zsbuf); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci return sum; 83bf215546Sopenharmony_ci} 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_cistatic enum agx_iogpu_attachment_type 86bf215546Sopenharmony_ciasahi_classify_attachment(enum pipe_format format) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci const struct util_format_description *desc = util_format_description(format); 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci if (util_format_has_depth(desc)) 91bf215546Sopenharmony_ci return AGX_IOGPU_ATTACHMENT_TYPE_DEPTH; 92bf215546Sopenharmony_ci else if (util_format_has_stencil(desc)) 93bf215546Sopenharmony_ci return AGX_IOGPU_ATTACHMENT_TYPE_STENCIL; 94bf215546Sopenharmony_ci else 95bf215546Sopenharmony_ci return AGX_IOGPU_ATTACHMENT_TYPE_COLOUR; 96bf215546Sopenharmony_ci} 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic uint64_t 99bf215546Sopenharmony_ciagx_map_surface_resource(struct pipe_surface *surf, struct agx_resource *rsrc) 100bf215546Sopenharmony_ci{ 101bf215546Sopenharmony_ci return agx_map_texture_gpu(rsrc, surf->u.tex.level, surf->u.tex.first_layer); 102bf215546Sopenharmony_ci} 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_cistatic uint64_t 105bf215546Sopenharmony_ciagx_map_surface(struct pipe_surface *surf) 106bf215546Sopenharmony_ci{ 107bf215546Sopenharmony_ci return agx_map_surface_resource(surf, agx_resource(surf->texture)); 108bf215546Sopenharmony_ci} 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_cistatic void 111bf215546Sopenharmony_ciasahi_pack_iogpu_attachment(void *out, struct agx_resource *rsrc, 112bf215546Sopenharmony_ci struct pipe_surface *surf, 113bf215546Sopenharmony_ci unsigned total_size) 114bf215546Sopenharmony_ci{ 115bf215546Sopenharmony_ci /* We don't support layered rendering yet */ 116bf215546Sopenharmony_ci assert(surf->u.tex.first_layer == surf->u.tex.last_layer); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci agx_pack(out, IOGPU_ATTACHMENT, cfg) { 119bf215546Sopenharmony_ci cfg.type = asahi_classify_attachment(rsrc->base.format); 120bf215546Sopenharmony_ci cfg.address = agx_map_surface_resource(surf, rsrc); 121bf215546Sopenharmony_ci cfg.size = rsrc->slices[surf->u.tex.level].size; 122bf215546Sopenharmony_ci cfg.percent = (100 * cfg.size) / total_size; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci} 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_cistatic unsigned 127bf215546Sopenharmony_ciasahi_pack_iogpu_attachments(void *out, struct pipe_framebuffer_state *framebuffer) 128bf215546Sopenharmony_ci{ 129bf215546Sopenharmony_ci unsigned total_attachment_size = asahi_size_attachments(framebuffer); 130bf215546Sopenharmony_ci struct agx_iogpu_attachment_packed *attachments = out; 131bf215546Sopenharmony_ci unsigned nr = 0; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci for (unsigned i = 0; i < framebuffer->nr_cbufs; ++i) { 134bf215546Sopenharmony_ci asahi_pack_iogpu_attachment(attachments + (nr++), 135bf215546Sopenharmony_ci agx_resource(framebuffer->cbufs[i]->texture), 136bf215546Sopenharmony_ci framebuffer->cbufs[i], 137bf215546Sopenharmony_ci total_attachment_size); 138bf215546Sopenharmony_ci } 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci if (framebuffer->zsbuf) { 141bf215546Sopenharmony_ci struct agx_resource *rsrc = agx_resource(framebuffer->zsbuf->texture); 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci asahi_pack_iogpu_attachment(attachments + (nr++), 144bf215546Sopenharmony_ci rsrc, framebuffer->zsbuf, 145bf215546Sopenharmony_ci total_attachment_size); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (rsrc->separate_stencil) { 148bf215546Sopenharmony_ci asahi_pack_iogpu_attachment(attachments + (nr++), 149bf215546Sopenharmony_ci rsrc->separate_stencil, 150bf215546Sopenharmony_ci framebuffer->zsbuf, 151bf215546Sopenharmony_ci total_attachment_size); 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci return nr; 156bf215546Sopenharmony_ci} 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ciunsigned 159bf215546Sopenharmony_cidemo_cmdbuf(uint64_t *buf, size_t size, 160bf215546Sopenharmony_ci struct agx_pool *pool, 161bf215546Sopenharmony_ci struct pipe_framebuffer_state *framebuffer, 162bf215546Sopenharmony_ci uint64_t encoder_ptr, 163bf215546Sopenharmony_ci uint64_t encoder_id, 164bf215546Sopenharmony_ci uint64_t scissor_ptr, 165bf215546Sopenharmony_ci uint64_t depth_bias_ptr, 166bf215546Sopenharmony_ci uint32_t pipeline_clear, 167bf215546Sopenharmony_ci uint32_t pipeline_load, 168bf215546Sopenharmony_ci uint32_t pipeline_store, 169bf215546Sopenharmony_ci bool clear_pipeline_textures, 170bf215546Sopenharmony_ci double clear_depth, 171bf215546Sopenharmony_ci unsigned clear_stencil) 172bf215546Sopenharmony_ci{ 173bf215546Sopenharmony_ci uint32_t *map = (uint32_t *) buf; 174bf215546Sopenharmony_ci memset(map, 0, 518 * 4); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci uint64_t deflake_buffer = demo_zero(pool, 0x7e0); 177bf215546Sopenharmony_ci uint64_t deflake_1 = deflake_buffer + 0x2a0; 178bf215546Sopenharmony_ci uint64_t deflake_2 = deflake_buffer + 0x20; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci uint64_t unk_buffer_2 = demo_zero(pool, 0x8000); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci uint64_t depth_buffer = 0; 183bf215546Sopenharmony_ci uint64_t stencil_buffer = 0; 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci agx_pack(map + 160, IOGPU_INTERNAL_PIPELINES, cfg) { 186bf215546Sopenharmony_ci cfg.clear_pipeline_bind = 0xffff8002 | (clear_pipeline_textures ? 0x210 : 0); 187bf215546Sopenharmony_ci cfg.clear_pipeline = pipeline_clear; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci /* store pipeline used when entire frame completes */ 190bf215546Sopenharmony_ci cfg.store_pipeline_bind = 0x12; 191bf215546Sopenharmony_ci cfg.store_pipeline = pipeline_store; 192bf215546Sopenharmony_ci cfg.scissor_array = scissor_ptr; 193bf215546Sopenharmony_ci cfg.depth_bias_array = depth_bias_ptr; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci if (framebuffer->zsbuf) { 196bf215546Sopenharmony_ci struct pipe_surface *zsbuf = framebuffer->zsbuf; 197bf215546Sopenharmony_ci const struct util_format_description *desc = 198bf215546Sopenharmony_ci util_format_description(zsbuf->texture->format); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci // note: setting 0x4 bit here breaks partial render with depth 201bf215546Sopenharmony_ci cfg.depth_flags = 0x80000; // no compression, clear 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci cfg.depth_width = framebuffer->width; 204bf215546Sopenharmony_ci cfg.depth_height = framebuffer->height; 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci if (util_format_has_depth(desc)) { 207bf215546Sopenharmony_ci depth_buffer = agx_map_surface(zsbuf); 208bf215546Sopenharmony_ci } else { 209bf215546Sopenharmony_ci stencil_buffer = agx_map_surface(zsbuf); 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (agx_resource(zsbuf->texture)->separate_stencil) { 213bf215546Sopenharmony_ci stencil_buffer = agx_map_surface_resource(zsbuf, 214bf215546Sopenharmony_ci agx_resource(zsbuf->texture)->separate_stencil); 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci cfg.stencil_buffer = stencil_buffer; 218bf215546Sopenharmony_ci cfg.stencil_buffer_2 = stencil_buffer; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci cfg.depth_buffer = depth_buffer; 221bf215546Sopenharmony_ci cfg.depth_buffer_if_clearing = depth_buffer; 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci } 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci agx_pack(map + 228, IOGPU_AUX_FRAMEBUFFER, cfg) { 226bf215546Sopenharmony_ci cfg.width = framebuffer->width; 227bf215546Sopenharmony_ci cfg.height = framebuffer->height; 228bf215546Sopenharmony_ci cfg.pointer = unk_buffer_2; 229bf215546Sopenharmony_ci } 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci agx_pack(map + 292, IOGPU_CLEAR_Z_S, cfg) { 232bf215546Sopenharmony_ci cfg.set_when_reloading_z_1 = clear_pipeline_textures; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci cfg.depth_clear_value = fui(clear_depth); 235bf215546Sopenharmony_ci cfg.stencil_clear_value = clear_stencil; 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci cfg.partial_reload_pipeline_bind = 0xffff8212; 238bf215546Sopenharmony_ci cfg.partial_reload_pipeline = pipeline_load; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci cfg.partial_store_pipeline_bind = 0x12; 241bf215546Sopenharmony_ci cfg.partial_store_pipeline = pipeline_store; 242bf215546Sopenharmony_ci } 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci agx_pack(map + 356, IOGPU_MISC, cfg) { 245bf215546Sopenharmony_ci cfg.depth_buffer = depth_buffer; 246bf215546Sopenharmony_ci cfg.stencil_buffer = stencil_buffer; 247bf215546Sopenharmony_ci cfg.encoder_id = encoder_id; 248bf215546Sopenharmony_ci cfg.unknown_buffer = demo_unk6(pool); 249bf215546Sopenharmony_ci cfg.width = framebuffer->width; 250bf215546Sopenharmony_ci cfg.height = framebuffer->height; 251bf215546Sopenharmony_ci cfg.unk_80 = clear_pipeline_textures ? 0x0 : 0x1; 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci unsigned offset_unk = (484 * 4); 255bf215546Sopenharmony_ci unsigned offset_attachments = (496 * 4); 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci unsigned nr_attachments = 258bf215546Sopenharmony_ci asahi_pack_iogpu_attachments(map + (offset_attachments / 4) + 4, 259bf215546Sopenharmony_ci framebuffer); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci map[(offset_attachments / 4) + 3] = nr_attachments; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci unsigned total_size = offset_attachments + (AGX_IOGPU_ATTACHMENT_LENGTH * nr_attachments) + 16; 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci agx_pack(map, IOGPU_HEADER, cfg) { 266bf215546Sopenharmony_ci cfg.total_size = total_size; 267bf215546Sopenharmony_ci cfg.attachment_offset = offset_attachments; 268bf215546Sopenharmony_ci cfg.attachment_length = nr_attachments * AGX_IOGPU_ATTACHMENT_LENGTH; 269bf215546Sopenharmony_ci cfg.unknown_offset = offset_unk; 270bf215546Sopenharmony_ci cfg.encoder = encoder_ptr; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci cfg.deflake_1 = deflake_1; 273bf215546Sopenharmony_ci cfg.deflake_2 = deflake_2; 274bf215546Sopenharmony_ci cfg.deflake_3 = deflake_buffer; 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci return total_size; 278bf215546Sopenharmony_ci} 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_cistatic struct agx_map_header 281bf215546Sopenharmony_cidemo_map_header(uint64_t cmdbuf_id, uint64_t encoder_id, unsigned cmdbuf_size, unsigned count) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci /* Structure: header followed by resource groups. For now, we use a single 284bf215546Sopenharmony_ci * resource group for every resource. This could be optimized. 285bf215546Sopenharmony_ci */ 286bf215546Sopenharmony_ci unsigned length = sizeof(struct agx_map_header); 287bf215546Sopenharmony_ci length += count * sizeof(struct agx_map_entry); 288bf215546Sopenharmony_ci assert(length < 0x10000); 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci return (struct agx_map_header) { 291bf215546Sopenharmony_ci .cmdbuf_id = cmdbuf_id, 292bf215546Sopenharmony_ci .segment_count = 1, 293bf215546Sopenharmony_ci .length = length, 294bf215546Sopenharmony_ci .encoder_id = encoder_id, 295bf215546Sopenharmony_ci .kernel_commands_start_offset = 0, 296bf215546Sopenharmony_ci .kernel_commands_end_offset = cmdbuf_size, 297bf215546Sopenharmony_ci .total_resources = count, 298bf215546Sopenharmony_ci .resource_group_count = count, 299bf215546Sopenharmony_ci .unk = 0x8000, 300bf215546Sopenharmony_ci }; 301bf215546Sopenharmony_ci} 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_civoid 304bf215546Sopenharmony_cidemo_mem_map(void *map, size_t size, unsigned *handles, unsigned count, 305bf215546Sopenharmony_ci uint64_t cmdbuf_id, uint64_t encoder_id, unsigned cmdbuf_size) 306bf215546Sopenharmony_ci{ 307bf215546Sopenharmony_ci struct agx_map_header *header = map; 308bf215546Sopenharmony_ci struct agx_map_entry *entries = (struct agx_map_entry *) (((uint8_t *) map) + sizeof(*header)); 309bf215546Sopenharmony_ci struct agx_map_entry *end = (struct agx_map_entry *) (((uint8_t *) map) + size); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci /* Header precedes the entry */ 312bf215546Sopenharmony_ci *header = demo_map_header(cmdbuf_id, encoder_id, cmdbuf_size, count); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci /* Add an entry for each BO mapped */ 315bf215546Sopenharmony_ci for (unsigned i = 0; i < count; ++i) { 316bf215546Sopenharmony_ci assert((entries + i) < end); 317bf215546Sopenharmony_ci entries[i] = (struct agx_map_entry) { 318bf215546Sopenharmony_ci .resource_id = { handles[i] }, 319bf215546Sopenharmony_ci .resource_unk = { 0x20 }, 320bf215546Sopenharmony_ci .resource_flags = { 0x1 }, 321bf215546Sopenharmony_ci .resource_count = 1 322bf215546Sopenharmony_ci }; 323bf215546Sopenharmony_ci } 324bf215546Sopenharmony_ci} 325