1 /*
2 * Copyright 2022 Alyssa Rosenzweig
3 * SPDX-License-Identifier: MIT
4 */
5
6 #pragma once
7
8 #include "asahi/genxml/agx_pack.h"
9 #include "agx_bo.h"
10
11 /* Opaque structure representing a PPP update */
12 struct agx_ppp_update {
13 uint8_t *head;
14 uint64_t gpu_base;
15 size_t total_size;
16
17 #ifndef NDEBUG
18 uint8_t *cpu_base;
19 #endif
20 };
21
22 ALWAYS_INLINE static size_t
agx_ppp_update_size(struct AGX_PPP_HEADER * present)23 agx_ppp_update_size(struct AGX_PPP_HEADER *present)
24 {
25 size_t size = AGX_PPP_HEADER_LENGTH;
26
27 #define PPP_CASE(x, y) \
28 if (present->x) \
29 size += AGX_##y##_LENGTH;
30 PPP_CASE(fragment_control, FRAGMENT_CONTROL);
31 PPP_CASE(fragment_control_2, FRAGMENT_CONTROL);
32 PPP_CASE(fragment_front_face, FRAGMENT_FACE);
33 PPP_CASE(fragment_front_face_2, FRAGMENT_FACE_2);
34 PPP_CASE(fragment_front_stencil, FRAGMENT_STENCIL);
35 PPP_CASE(fragment_back_face, FRAGMENT_FACE);
36 PPP_CASE(fragment_back_face_2, FRAGMENT_FACE_2);
37 PPP_CASE(fragment_back_stencil, FRAGMENT_STENCIL);
38 PPP_CASE(depth_bias_scissor, DEPTH_BIAS_SCISSOR);
39
40 if (present->region_clip)
41 size += present->viewport_count * AGX_REGION_CLIP_LENGTH;
42
43 if (present->viewport) {
44 size += AGX_VIEWPORT_CONTROL_LENGTH +
45 (present->viewport_count * AGX_VIEWPORT_LENGTH);
46 }
47
48 PPP_CASE(w_clamp, W_CLAMP);
49 PPP_CASE(output_select, OUTPUT_SELECT);
50 PPP_CASE(varying_counts_32, VARYING_COUNTS);
51 PPP_CASE(varying_counts_16, VARYING_COUNTS);
52 PPP_CASE(cull, CULL);
53 PPP_CASE(cull_2, CULL_2);
54
55 if (present->fragment_shader) {
56 size +=
57 AGX_FRAGMENT_SHADER_WORD_0_LENGTH + AGX_FRAGMENT_SHADER_WORD_1_LENGTH +
58 AGX_FRAGMENT_SHADER_WORD_2_LENGTH + AGX_FRAGMENT_SHADER_WORD_3_LENGTH;
59 }
60
61 PPP_CASE(occlusion_query, FRAGMENT_OCCLUSION_QUERY);
62 PPP_CASE(occlusion_query_2, FRAGMENT_OCCLUSION_QUERY_2);
63 PPP_CASE(output_unknown, OUTPUT_UNKNOWN);
64 PPP_CASE(output_size, OUTPUT_SIZE);
65 PPP_CASE(varying_word_2, VARYING_2);
66 #undef PPP_CASE
67
68 assert((size % 4) == 0 && "PPP updates are aligned");
69 return size;
70 }
71
72 static inline bool
agx_ppp_validate(struct agx_ppp_update * ppp,size_t size)73 agx_ppp_validate(struct agx_ppp_update *ppp, size_t size)
74 {
75 #ifndef NDEBUG
76 /* Assert that we don't overflow. Ideally we'd assert that types match too
77 * but that's harder to do at the moment.
78 */
79 assert(((ppp->head - ppp->cpu_base) + size) <= ppp->total_size);
80 #endif
81
82 return true;
83 }
84
85 #define agx_ppp_push(ppp, T, name) \
86 for (bool it = agx_ppp_validate((ppp), AGX_##T##_LENGTH); it; \
87 it = false, (ppp)->head += AGX_##T##_LENGTH) \
88 agx_pack((ppp)->head, T, name)
89
90 #define agx_ppp_push_packed(ppp, src, T) \
91 do { \
92 agx_ppp_validate((ppp), AGX_##T##_LENGTH); \
93 memcpy((ppp)->head, src, AGX_##T##_LENGTH); \
94 (ppp)->head += AGX_##T##_LENGTH; \
95 } while (0)
96
97 #define agx_ppp_push_merged(ppp, T, name, merge) \
98 for (uint8_t _tmp[AGX_##T##_LENGTH], it = 1; it; \
99 it = 0, agx_ppp_push_merged_blobs(ppp, AGX_##T##_LENGTH, \
100 (uint32_t *)_tmp, \
101 (uint32_t *)&merge)) \
102 agx_pack(_tmp, T, name)
103
104 ALWAYS_INLINE static struct agx_ppp_update
agx_new_ppp_update(struct agx_ptr out,size_t size,struct AGX_PPP_HEADER * present)105 agx_new_ppp_update(struct agx_ptr out, size_t size,
106 struct AGX_PPP_HEADER *present)
107 {
108 struct agx_ppp_update ppp = {
109 .head = out.cpu,
110 .gpu_base = out.gpu,
111 .total_size = size,
112 #ifndef NDEBUG
113 .cpu_base = out.cpu,
114 #endif
115 };
116
117 agx_ppp_push(&ppp, PPP_HEADER, cfg) {
118 cfg = *present;
119 }
120
121 return ppp;
122 }
123
124 static inline void
agx_ppp_fini(uint8_t ** out,struct agx_ppp_update * ppp)125 agx_ppp_fini(uint8_t **out, struct agx_ppp_update *ppp)
126 {
127 size_t size = ppp->total_size;
128 assert((size % 4) == 0);
129 size_t size_words = size / 4;
130
131 #ifndef NDEBUG
132 assert(size == (ppp->head - ppp->cpu_base) && "mismatched ppp size");
133 #endif
134
135 assert(ppp->gpu_base < (1ull << 40));
136 assert(size_words < (1ull << 24));
137
138 agx_pack(*out, PPP_STATE, cfg) {
139 cfg.pointer_hi = (ppp->gpu_base >> 32);
140 cfg.pointer_lo = (uint32_t)ppp->gpu_base;
141 cfg.size_words = size_words;
142 };
143
144 *out += AGX_PPP_STATE_LENGTH;
145 }
146
147 static void
agx_ppp_push_merged_blobs(struct agx_ppp_update * ppp,size_t length,void * src1_,void * src2_)148 agx_ppp_push_merged_blobs(struct agx_ppp_update *ppp, size_t length,
149 void *src1_, void *src2_)
150 {
151 assert((length & 3) == 0);
152 assert(((uintptr_t)src1_ & 3) == 0);
153 assert(((uintptr_t)src2_ & 3) == 0);
154
155 uint32_t *dst = (uint32_t *)ppp->head;
156 uint32_t *src1 = (uint32_t *)src1_;
157 uint32_t *src2 = (uint32_t *)src2_;
158
159 for (unsigned i = 0; i < (length / 4); ++i) {
160 dst[i] = src1[i] | src2[i];
161 }
162
163 ppp->head += length;
164 }
165