1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2019 Google LLC 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci */ 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_ci#ifndef TU_CS_H 7bf215546Sopenharmony_ci#define TU_CS_H 8bf215546Sopenharmony_ci 9bf215546Sopenharmony_ci#include "tu_common.h" 10bf215546Sopenharmony_ci 11bf215546Sopenharmony_ci#include "freedreno_pm4.h" 12bf215546Sopenharmony_ci 13bf215546Sopenharmony_ci#include "tu_drm.h" 14bf215546Sopenharmony_ci 15bf215546Sopenharmony_ci/* For breadcrumbs we may open a network socket based on the envvar, 16bf215546Sopenharmony_ci * it's not something that should be enabled by default. 17bf215546Sopenharmony_ci */ 18bf215546Sopenharmony_ci#define TU_BREADCRUMBS_ENABLED 0 19bf215546Sopenharmony_ci 20bf215546Sopenharmony_cienum tu_cs_mode 21bf215546Sopenharmony_ci{ 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci /* 24bf215546Sopenharmony_ci * A command stream in TU_CS_MODE_GROW mode grows automatically whenever it 25bf215546Sopenharmony_ci * is full. tu_cs_begin must be called before command packet emission and 26bf215546Sopenharmony_ci * tu_cs_end must be called after. 27bf215546Sopenharmony_ci * 28bf215546Sopenharmony_ci * This mode may create multiple entries internally. The entries must be 29bf215546Sopenharmony_ci * submitted together. 30bf215546Sopenharmony_ci */ 31bf215546Sopenharmony_ci TU_CS_MODE_GROW, 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci /* 34bf215546Sopenharmony_ci * A command stream in TU_CS_MODE_EXTERNAL mode wraps an external, 35bf215546Sopenharmony_ci * fixed-size buffer. tu_cs_begin and tu_cs_end are optional and have no 36bf215546Sopenharmony_ci * effect on it. 37bf215546Sopenharmony_ci * 38bf215546Sopenharmony_ci * This mode does not create any entry or any BO. 39bf215546Sopenharmony_ci */ 40bf215546Sopenharmony_ci TU_CS_MODE_EXTERNAL, 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci /* 43bf215546Sopenharmony_ci * A command stream in TU_CS_MODE_SUB_STREAM mode does not support direct 44bf215546Sopenharmony_ci * command packet emission. tu_cs_begin_sub_stream must be called to get a 45bf215546Sopenharmony_ci * sub-stream to emit comamnd packets to. When done with the sub-stream, 46bf215546Sopenharmony_ci * tu_cs_end_sub_stream must be called. 47bf215546Sopenharmony_ci * 48bf215546Sopenharmony_ci * This mode does not create any entry internally. 49bf215546Sopenharmony_ci */ 50bf215546Sopenharmony_ci TU_CS_MODE_SUB_STREAM, 51bf215546Sopenharmony_ci}; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_cistruct tu_cs_entry 54bf215546Sopenharmony_ci{ 55bf215546Sopenharmony_ci /* No ownership */ 56bf215546Sopenharmony_ci const struct tu_bo *bo; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci uint32_t size; 59bf215546Sopenharmony_ci uint32_t offset; 60bf215546Sopenharmony_ci}; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistruct tu_cs_memory { 63bf215546Sopenharmony_ci uint32_t *map; 64bf215546Sopenharmony_ci uint64_t iova; 65bf215546Sopenharmony_ci}; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_cistruct tu_draw_state { 68bf215546Sopenharmony_ci uint64_t iova : 48; 69bf215546Sopenharmony_ci uint32_t size : 16; 70bf215546Sopenharmony_ci}; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci#define TU_COND_EXEC_STACK_SIZE 4 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cistruct tu_cs 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci uint32_t *start; 77bf215546Sopenharmony_ci uint32_t *cur; 78bf215546Sopenharmony_ci uint32_t *reserved_end; 79bf215546Sopenharmony_ci uint32_t *end; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci struct tu_device *device; 82bf215546Sopenharmony_ci enum tu_cs_mode mode; 83bf215546Sopenharmony_ci uint32_t next_bo_size; 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci struct tu_cs_entry *entries; 86bf215546Sopenharmony_ci uint32_t entry_count; 87bf215546Sopenharmony_ci uint32_t entry_capacity; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci struct tu_bo **bos; 90bf215546Sopenharmony_ci uint32_t bo_count; 91bf215546Sopenharmony_ci uint32_t bo_capacity; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci /* Optional BO that this CS is sub-allocated from for TU_CS_MODE_SUB_STREAM */ 94bf215546Sopenharmony_ci struct tu_bo *refcount_bo; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci /* state for cond_exec_start/cond_exec_end */ 97bf215546Sopenharmony_ci uint32_t cond_stack_depth; 98bf215546Sopenharmony_ci uint32_t cond_flags[TU_COND_EXEC_STACK_SIZE]; 99bf215546Sopenharmony_ci uint32_t *cond_dwords[TU_COND_EXEC_STACK_SIZE]; 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci uint32_t breadcrumb_emit_after; 102bf215546Sopenharmony_ci}; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_civoid 105bf215546Sopenharmony_citu_breadcrumbs_init(struct tu_device *device); 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_civoid 108bf215546Sopenharmony_citu_breadcrumbs_finish(struct tu_device *device); 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_civoid 111bf215546Sopenharmony_citu_cs_init(struct tu_cs *cs, 112bf215546Sopenharmony_ci struct tu_device *device, 113bf215546Sopenharmony_ci enum tu_cs_mode mode, 114bf215546Sopenharmony_ci uint32_t initial_size); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_civoid 117bf215546Sopenharmony_citu_cs_init_external(struct tu_cs *cs, struct tu_device *device, 118bf215546Sopenharmony_ci uint32_t *start, uint32_t *end); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_civoid 121bf215546Sopenharmony_citu_cs_init_suballoc(struct tu_cs *cs, struct tu_device *device, 122bf215546Sopenharmony_ci struct tu_suballoc_bo *bo); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_civoid 125bf215546Sopenharmony_citu_cs_finish(struct tu_cs *cs); 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_civoid 128bf215546Sopenharmony_citu_cs_begin(struct tu_cs *cs); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_civoid 131bf215546Sopenharmony_citu_cs_end(struct tu_cs *cs); 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ciVkResult 134bf215546Sopenharmony_citu_cs_begin_sub_stream(struct tu_cs *cs, uint32_t size, struct tu_cs *sub_cs); 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ciVkResult 137bf215546Sopenharmony_citu_cs_alloc(struct tu_cs *cs, 138bf215546Sopenharmony_ci uint32_t count, 139bf215546Sopenharmony_ci uint32_t size, 140bf215546Sopenharmony_ci struct tu_cs_memory *memory); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_cistruct tu_cs_entry 143bf215546Sopenharmony_citu_cs_end_sub_stream(struct tu_cs *cs, struct tu_cs *sub_cs); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic inline struct tu_draw_state 146bf215546Sopenharmony_citu_cs_end_draw_state(struct tu_cs *cs, struct tu_cs *sub_cs) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci struct tu_cs_entry entry = tu_cs_end_sub_stream(cs, sub_cs); 149bf215546Sopenharmony_ci return (struct tu_draw_state) { 150bf215546Sopenharmony_ci .iova = entry.bo->iova + entry.offset, 151bf215546Sopenharmony_ci .size = entry.size / sizeof(uint32_t), 152bf215546Sopenharmony_ci }; 153bf215546Sopenharmony_ci} 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ciVkResult 156bf215546Sopenharmony_citu_cs_reserve_space(struct tu_cs *cs, uint32_t reserved_size); 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_cistatic inline struct tu_draw_state 159bf215546Sopenharmony_citu_cs_draw_state(struct tu_cs *sub_cs, struct tu_cs *cs, uint32_t size) 160bf215546Sopenharmony_ci{ 161bf215546Sopenharmony_ci struct tu_cs_memory memory; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /* TODO: clean this up */ 164bf215546Sopenharmony_ci tu_cs_alloc(sub_cs, size, 1, &memory); 165bf215546Sopenharmony_ci tu_cs_init_external(cs, sub_cs->device, memory.map, memory.map + size); 166bf215546Sopenharmony_ci tu_cs_begin(cs); 167bf215546Sopenharmony_ci tu_cs_reserve_space(cs, size); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci return (struct tu_draw_state) { 170bf215546Sopenharmony_ci .iova = memory.iova, 171bf215546Sopenharmony_ci .size = size, 172bf215546Sopenharmony_ci }; 173bf215546Sopenharmony_ci} 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_civoid 176bf215546Sopenharmony_citu_cs_reset(struct tu_cs *cs); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ciVkResult 179bf215546Sopenharmony_citu_cs_add_entries(struct tu_cs *cs, struct tu_cs *target); 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci/** 182bf215546Sopenharmony_ci * Get the size of the command packets emitted since the last call to 183bf215546Sopenharmony_ci * tu_cs_add_entry. 184bf215546Sopenharmony_ci */ 185bf215546Sopenharmony_cistatic inline uint32_t 186bf215546Sopenharmony_citu_cs_get_size(const struct tu_cs *cs) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci return cs->cur - cs->start; 189bf215546Sopenharmony_ci} 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci/** 192bf215546Sopenharmony_ci * Return true if there is no command packet emitted since the last call to 193bf215546Sopenharmony_ci * tu_cs_add_entry. 194bf215546Sopenharmony_ci */ 195bf215546Sopenharmony_cistatic inline uint32_t 196bf215546Sopenharmony_citu_cs_is_empty(const struct tu_cs *cs) 197bf215546Sopenharmony_ci{ 198bf215546Sopenharmony_ci return tu_cs_get_size(cs) == 0; 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci/** 202bf215546Sopenharmony_ci * Discard all entries. This allows \a cs to be reused while keeping the 203bf215546Sopenharmony_ci * existing BOs and command packets intact. 204bf215546Sopenharmony_ci */ 205bf215546Sopenharmony_cistatic inline void 206bf215546Sopenharmony_citu_cs_discard_entries(struct tu_cs *cs) 207bf215546Sopenharmony_ci{ 208bf215546Sopenharmony_ci assert(cs->mode == TU_CS_MODE_GROW); 209bf215546Sopenharmony_ci cs->entry_count = 0; 210bf215546Sopenharmony_ci} 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci/** 213bf215546Sopenharmony_ci * Get the size needed for tu_cs_emit_call. 214bf215546Sopenharmony_ci */ 215bf215546Sopenharmony_cistatic inline uint32_t 216bf215546Sopenharmony_citu_cs_get_call_size(const struct tu_cs *cs) 217bf215546Sopenharmony_ci{ 218bf215546Sopenharmony_ci assert(cs->mode == TU_CS_MODE_GROW); 219bf215546Sopenharmony_ci /* each CP_INDIRECT_BUFFER needs 4 dwords */ 220bf215546Sopenharmony_ci return cs->entry_count * 4; 221bf215546Sopenharmony_ci} 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci/** 224bf215546Sopenharmony_ci * Assert that we did not exceed the reserved space. 225bf215546Sopenharmony_ci */ 226bf215546Sopenharmony_cistatic inline void 227bf215546Sopenharmony_citu_cs_sanity_check(const struct tu_cs *cs) 228bf215546Sopenharmony_ci{ 229bf215546Sopenharmony_ci assert(cs->start <= cs->cur); 230bf215546Sopenharmony_ci assert(cs->cur <= cs->reserved_end); 231bf215546Sopenharmony_ci assert(cs->reserved_end <= cs->end); 232bf215546Sopenharmony_ci} 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_civoid 235bf215546Sopenharmony_citu_cs_emit_sync_breadcrumb(struct tu_cs *cs, uint8_t opcode, uint16_t cnt); 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci/** 238bf215546Sopenharmony_ci * Emit a uint32_t value into a command stream, without boundary checking. 239bf215546Sopenharmony_ci */ 240bf215546Sopenharmony_cistatic inline void 241bf215546Sopenharmony_citu_cs_emit(struct tu_cs *cs, uint32_t value) 242bf215546Sopenharmony_ci{ 243bf215546Sopenharmony_ci assert(cs->cur < cs->reserved_end); 244bf215546Sopenharmony_ci *cs->cur = value; 245bf215546Sopenharmony_ci ++cs->cur; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci#if TU_BREADCRUMBS_ENABLED 248bf215546Sopenharmony_ci cs->breadcrumb_emit_after--; 249bf215546Sopenharmony_ci if (cs->breadcrumb_emit_after == 0) 250bf215546Sopenharmony_ci tu_cs_emit_sync_breadcrumb(cs, -1, 0); 251bf215546Sopenharmony_ci#endif 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci/** 255bf215546Sopenharmony_ci * Emit an array of uint32_t into a command stream, without boundary checking. 256bf215546Sopenharmony_ci */ 257bf215546Sopenharmony_cistatic inline void 258bf215546Sopenharmony_citu_cs_emit_array(struct tu_cs *cs, const uint32_t *values, uint32_t length) 259bf215546Sopenharmony_ci{ 260bf215546Sopenharmony_ci assert(cs->cur + length <= cs->reserved_end); 261bf215546Sopenharmony_ci memcpy(cs->cur, values, sizeof(uint32_t) * length); 262bf215546Sopenharmony_ci cs->cur += length; 263bf215546Sopenharmony_ci} 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci/** 266bf215546Sopenharmony_ci * Get the size of the remaining space in the current BO. 267bf215546Sopenharmony_ci */ 268bf215546Sopenharmony_cistatic inline uint32_t 269bf215546Sopenharmony_citu_cs_get_space(const struct tu_cs *cs) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci return cs->end - cs->cur; 272bf215546Sopenharmony_ci} 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_cistatic inline void 275bf215546Sopenharmony_citu_cs_reserve(struct tu_cs *cs, uint32_t reserved_size) 276bf215546Sopenharmony_ci{ 277bf215546Sopenharmony_ci if (cs->mode != TU_CS_MODE_GROW) { 278bf215546Sopenharmony_ci assert(tu_cs_get_space(cs) >= reserved_size); 279bf215546Sopenharmony_ci assert(cs->reserved_end == cs->end); 280bf215546Sopenharmony_ci return; 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci if (tu_cs_get_space(cs) >= reserved_size && 284bf215546Sopenharmony_ci cs->entry_count < cs->entry_capacity) { 285bf215546Sopenharmony_ci cs->reserved_end = cs->cur + reserved_size; 286bf215546Sopenharmony_ci return; 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci ASSERTED VkResult result = tu_cs_reserve_space(cs, reserved_size); 290bf215546Sopenharmony_ci /* TODO: set this error in tu_cs and use it */ 291bf215546Sopenharmony_ci assert(result == VK_SUCCESS); 292bf215546Sopenharmony_ci} 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci/** 295bf215546Sopenharmony_ci * Emit a type-4 command packet header into a command stream. 296bf215546Sopenharmony_ci */ 297bf215546Sopenharmony_cistatic inline void 298bf215546Sopenharmony_citu_cs_emit_pkt4(struct tu_cs *cs, uint16_t regindx, uint16_t cnt) 299bf215546Sopenharmony_ci{ 300bf215546Sopenharmony_ci tu_cs_reserve(cs, cnt + 1); 301bf215546Sopenharmony_ci tu_cs_emit(cs, pm4_pkt4_hdr(regindx, cnt)); 302bf215546Sopenharmony_ci} 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci/** 305bf215546Sopenharmony_ci * Emit a type-7 command packet header into a command stream. 306bf215546Sopenharmony_ci */ 307bf215546Sopenharmony_cistatic inline void 308bf215546Sopenharmony_citu_cs_emit_pkt7(struct tu_cs *cs, uint8_t opcode, uint16_t cnt) 309bf215546Sopenharmony_ci{ 310bf215546Sopenharmony_ci#if TU_BREADCRUMBS_ENABLED 311bf215546Sopenharmony_ci tu_cs_emit_sync_breadcrumb(cs, opcode, cnt + 1); 312bf215546Sopenharmony_ci#endif 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci tu_cs_reserve(cs, cnt + 1); 315bf215546Sopenharmony_ci tu_cs_emit(cs, pm4_pkt7_hdr(opcode, cnt)); 316bf215546Sopenharmony_ci} 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_cistatic inline void 319bf215546Sopenharmony_citu_cs_emit_wfi(struct tu_cs *cs) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci tu_cs_emit_pkt7(cs, CP_WAIT_FOR_IDLE, 0); 322bf215546Sopenharmony_ci} 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_cistatic inline void 325bf215546Sopenharmony_citu_cs_emit_qw(struct tu_cs *cs, uint64_t value) 326bf215546Sopenharmony_ci{ 327bf215546Sopenharmony_ci tu_cs_emit(cs, (uint32_t) value); 328bf215546Sopenharmony_ci tu_cs_emit(cs, (uint32_t) (value >> 32)); 329bf215546Sopenharmony_ci} 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_cistatic inline void 332bf215546Sopenharmony_citu_cs_emit_write_reg(struct tu_cs *cs, uint16_t reg, uint32_t value) 333bf215546Sopenharmony_ci{ 334bf215546Sopenharmony_ci tu_cs_emit_pkt4(cs, reg, 1); 335bf215546Sopenharmony_ci tu_cs_emit(cs, value); 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci/** 339bf215546Sopenharmony_ci * Emit a CP_INDIRECT_BUFFER command packet. 340bf215546Sopenharmony_ci */ 341bf215546Sopenharmony_cistatic inline void 342bf215546Sopenharmony_citu_cs_emit_ib(struct tu_cs *cs, const struct tu_cs_entry *entry) 343bf215546Sopenharmony_ci{ 344bf215546Sopenharmony_ci assert(entry->bo); 345bf215546Sopenharmony_ci assert(entry->size && entry->offset + entry->size <= entry->bo->size); 346bf215546Sopenharmony_ci assert(entry->size % sizeof(uint32_t) == 0); 347bf215546Sopenharmony_ci assert(entry->offset % sizeof(uint32_t) == 0); 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_ci tu_cs_emit_pkt7(cs, CP_INDIRECT_BUFFER, 3); 350bf215546Sopenharmony_ci tu_cs_emit_qw(cs, entry->bo->iova + entry->offset); 351bf215546Sopenharmony_ci tu_cs_emit(cs, entry->size / sizeof(uint32_t)); 352bf215546Sopenharmony_ci} 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci/* for compute which isn't using SET_DRAW_STATE */ 355bf215546Sopenharmony_cistatic inline void 356bf215546Sopenharmony_citu_cs_emit_state_ib(struct tu_cs *cs, struct tu_draw_state state) 357bf215546Sopenharmony_ci{ 358bf215546Sopenharmony_ci if (state.size) { 359bf215546Sopenharmony_ci tu_cs_emit_pkt7(cs, CP_INDIRECT_BUFFER, 3); 360bf215546Sopenharmony_ci tu_cs_emit_qw(cs, state.iova); 361bf215546Sopenharmony_ci tu_cs_emit(cs, state.size); 362bf215546Sopenharmony_ci } 363bf215546Sopenharmony_ci} 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_ci/** 366bf215546Sopenharmony_ci * Emit a CP_INDIRECT_BUFFER command packet for each entry in the target 367bf215546Sopenharmony_ci * command stream. 368bf215546Sopenharmony_ci */ 369bf215546Sopenharmony_cistatic inline void 370bf215546Sopenharmony_citu_cs_emit_call(struct tu_cs *cs, const struct tu_cs *target) 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci assert(target->mode == TU_CS_MODE_GROW); 373bf215546Sopenharmony_ci for (uint32_t i = 0; i < target->entry_count; i++) 374bf215546Sopenharmony_ci tu_cs_emit_ib(cs, target->entries + i); 375bf215546Sopenharmony_ci} 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci/* Helpers for bracketing a large sequence of commands of unknown size inside 378bf215546Sopenharmony_ci * a CP_COND_REG_EXEC packet. 379bf215546Sopenharmony_ci */ 380bf215546Sopenharmony_cistatic inline void 381bf215546Sopenharmony_citu_cond_exec_start(struct tu_cs *cs, uint32_t cond_flags) 382bf215546Sopenharmony_ci{ 383bf215546Sopenharmony_ci assert(cs->mode == TU_CS_MODE_GROW); 384bf215546Sopenharmony_ci assert(cs->cond_stack_depth < TU_COND_EXEC_STACK_SIZE); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci tu_cs_emit_pkt7(cs, CP_COND_REG_EXEC, 2); 387bf215546Sopenharmony_ci tu_cs_emit(cs, cond_flags); 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci cs->cond_flags[cs->cond_stack_depth] = cond_flags; 390bf215546Sopenharmony_ci cs->cond_dwords[cs->cond_stack_depth] = cs->cur; 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci /* Emit dummy DWORD field here */ 393bf215546Sopenharmony_ci tu_cs_emit(cs, CP_COND_REG_EXEC_1_DWORDS(0)); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci cs->cond_stack_depth++; 396bf215546Sopenharmony_ci} 397bf215546Sopenharmony_ci#define CP_COND_EXEC_0_RENDER_MODE_GMEM \ 398bf215546Sopenharmony_ci (CP_COND_REG_EXEC_0_MODE(RENDER_MODE) | CP_COND_REG_EXEC_0_GMEM) 399bf215546Sopenharmony_ci#define CP_COND_EXEC_0_RENDER_MODE_SYSMEM \ 400bf215546Sopenharmony_ci (CP_COND_REG_EXEC_0_MODE(RENDER_MODE) | CP_COND_REG_EXEC_0_SYSMEM) 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_cistatic inline void 403bf215546Sopenharmony_citu_cond_exec_end(struct tu_cs *cs) 404bf215546Sopenharmony_ci{ 405bf215546Sopenharmony_ci assert(cs->cond_stack_depth > 0); 406bf215546Sopenharmony_ci cs->cond_stack_depth--; 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci cs->cond_flags[cs->cond_stack_depth] = 0; 409bf215546Sopenharmony_ci /* Subtract one here to account for the DWORD field itself. */ 410bf215546Sopenharmony_ci *cs->cond_dwords[cs->cond_stack_depth] = 411bf215546Sopenharmony_ci cs->cur - cs->cond_dwords[cs->cond_stack_depth] - 1; 412bf215546Sopenharmony_ci} 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ci/* Temporary struct for tracking a register state to be written, used by 415bf215546Sopenharmony_ci * a6xx-pack.h and tu_cs_emit_regs() 416bf215546Sopenharmony_ci */ 417bf215546Sopenharmony_cistruct tu_reg_value { 418bf215546Sopenharmony_ci uint32_t reg; 419bf215546Sopenharmony_ci uint64_t value; 420bf215546Sopenharmony_ci bool is_address; 421bf215546Sopenharmony_ci struct tu_bo *bo; 422bf215546Sopenharmony_ci bool bo_write; 423bf215546Sopenharmony_ci uint32_t bo_offset; 424bf215546Sopenharmony_ci uint32_t bo_shift; 425bf215546Sopenharmony_ci}; 426bf215546Sopenharmony_ci 427bf215546Sopenharmony_ci#define fd_reg_pair tu_reg_value 428bf215546Sopenharmony_ci#define __bo_type struct tu_bo * 429bf215546Sopenharmony_ci 430bf215546Sopenharmony_ci#include "a6xx-pack.xml.h" 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci#define __assert_eq(a, b) \ 433bf215546Sopenharmony_ci do { \ 434bf215546Sopenharmony_ci if ((a) != (b)) { \ 435bf215546Sopenharmony_ci fprintf(stderr, "assert failed: " #a " (0x%x) != " #b " (0x%x)\n", a, b); \ 436bf215546Sopenharmony_ci assert((a) == (b)); \ 437bf215546Sopenharmony_ci } \ 438bf215546Sopenharmony_ci } while (0) 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci#define __ONE_REG(i, regs) \ 441bf215546Sopenharmony_ci do { \ 442bf215546Sopenharmony_ci if (i < ARRAY_SIZE(regs) && regs[i].reg > 0) { \ 443bf215546Sopenharmony_ci __assert_eq(regs[0].reg + i, regs[i].reg); \ 444bf215546Sopenharmony_ci if (regs[i].bo) { \ 445bf215546Sopenharmony_ci uint64_t v = regs[i].bo->iova + regs[i].bo_offset; \ 446bf215546Sopenharmony_ci v >>= regs[i].bo_shift; \ 447bf215546Sopenharmony_ci v |= regs[i].value; \ 448bf215546Sopenharmony_ci \ 449bf215546Sopenharmony_ci *p++ = v; \ 450bf215546Sopenharmony_ci *p++ = v >> 32; \ 451bf215546Sopenharmony_ci } else { \ 452bf215546Sopenharmony_ci *p++ = regs[i].value; \ 453bf215546Sopenharmony_ci if (regs[i].is_address) \ 454bf215546Sopenharmony_ci *p++ = regs[i].value >> 32; \ 455bf215546Sopenharmony_ci } \ 456bf215546Sopenharmony_ci } \ 457bf215546Sopenharmony_ci } while (0) 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci/* Emits a sequence of register writes in order using a pkt4. This will check 460bf215546Sopenharmony_ci * (at runtime on a !NDEBUG build) that the registers were actually set up in 461bf215546Sopenharmony_ci * order in the code. 462bf215546Sopenharmony_ci * 463bf215546Sopenharmony_ci * Note that references to buffers aren't automatically added to the CS, 464bf215546Sopenharmony_ci * unlike in freedreno. We are clever in various places to avoid duplicating 465bf215546Sopenharmony_ci * the reference add work. 466bf215546Sopenharmony_ci * 467bf215546Sopenharmony_ci * Also, 64-bit address registers don't have a way (currently) to set a 64-bit 468bf215546Sopenharmony_ci * address without having a reference to a BO, since the .dword field in the 469bf215546Sopenharmony_ci * register's struct is only 32-bit wide. We should fix this in the pack 470bf215546Sopenharmony_ci * codegen later. 471bf215546Sopenharmony_ci */ 472bf215546Sopenharmony_ci#define tu_cs_emit_regs(cs, ...) do { \ 473bf215546Sopenharmony_ci const struct fd_reg_pair regs[] = { __VA_ARGS__ }; \ 474bf215546Sopenharmony_ci unsigned count = ARRAY_SIZE(regs); \ 475bf215546Sopenharmony_ci \ 476bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(regs) > 0); \ 477bf215546Sopenharmony_ci STATIC_ASSERT(ARRAY_SIZE(regs) <= 16); \ 478bf215546Sopenharmony_ci \ 479bf215546Sopenharmony_ci tu_cs_emit_pkt4((cs), regs[0].reg, count); \ 480bf215546Sopenharmony_ci uint32_t *p = (cs)->cur; \ 481bf215546Sopenharmony_ci __ONE_REG( 0, regs); \ 482bf215546Sopenharmony_ci __ONE_REG( 1, regs); \ 483bf215546Sopenharmony_ci __ONE_REG( 2, regs); \ 484bf215546Sopenharmony_ci __ONE_REG( 3, regs); \ 485bf215546Sopenharmony_ci __ONE_REG( 4, regs); \ 486bf215546Sopenharmony_ci __ONE_REG( 5, regs); \ 487bf215546Sopenharmony_ci __ONE_REG( 6, regs); \ 488bf215546Sopenharmony_ci __ONE_REG( 7, regs); \ 489bf215546Sopenharmony_ci __ONE_REG( 8, regs); \ 490bf215546Sopenharmony_ci __ONE_REG( 9, regs); \ 491bf215546Sopenharmony_ci __ONE_REG(10, regs); \ 492bf215546Sopenharmony_ci __ONE_REG(11, regs); \ 493bf215546Sopenharmony_ci __ONE_REG(12, regs); \ 494bf215546Sopenharmony_ci __ONE_REG(13, regs); \ 495bf215546Sopenharmony_ci __ONE_REG(14, regs); \ 496bf215546Sopenharmony_ci __ONE_REG(15, regs); \ 497bf215546Sopenharmony_ci (cs)->cur = p; \ 498bf215546Sopenharmony_ci } while (0) 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci#endif /* TU_CS_H */ 501