• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "pool.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    PPP_CASE(fragment_shader, FRAGMENT_SHADER);
55    PPP_CASE(occlusion_query, FRAGMENT_OCCLUSION_QUERY);
56    PPP_CASE(occlusion_query_2, FRAGMENT_OCCLUSION_QUERY_2);
57    PPP_CASE(output_unknown, OUTPUT_UNKNOWN);
58    PPP_CASE(output_size, OUTPUT_SIZE);
59    PPP_CASE(varying_word_2, VARYING_2);
60 #undef PPP_CASE
61 
62    assert((size % 4) == 0 && "PPP updates are aligned");
63    return size;
64 }
65 
66 static inline bool
agx_ppp_validate(struct agx_ppp_update * ppp,size_t size)67 agx_ppp_validate(struct agx_ppp_update *ppp, size_t size)
68 {
69 #ifndef NDEBUG
70    /* Assert that we don't overflow. Ideally we'd assert that types match too
71     * but that's harder to do at the moment.
72     */
73    assert(((ppp->head - ppp->cpu_base) + size) <= ppp->total_size);
74 #endif
75 
76    return true;
77 }
78 
79 #define agx_ppp_push(ppp, T, name)                                             \
80    for (bool it = agx_ppp_validate((ppp), AGX_##T##_LENGTH); it;               \
81         it = false, (ppp)->head += AGX_##T##_LENGTH)                           \
82       agx_pack((ppp)->head, T, name)
83 
84 #define agx_ppp_push_packed(ppp, src, T)                                       \
85    do {                                                                        \
86       agx_ppp_validate((ppp), AGX_##T##_LENGTH);                               \
87       memcpy((ppp)->head, src, AGX_##T##_LENGTH);                              \
88       (ppp)->head += AGX_##T##_LENGTH;                                         \
89    } while (0)
90 
91 ALWAYS_INLINE static struct agx_ppp_update
agx_new_ppp_update(struct agx_pool * pool,struct AGX_PPP_HEADER present)92 agx_new_ppp_update(struct agx_pool *pool, struct AGX_PPP_HEADER present)
93 {
94    size_t size = agx_ppp_update_size(&present);
95    struct agx_ptr T = agx_pool_alloc_aligned(pool, size, 64);
96 
97    struct agx_ppp_update ppp = {
98       .gpu_base = T.gpu,
99       .head = T.cpu,
100       .total_size = size,
101 #ifndef NDEBUG
102       .cpu_base = T.cpu,
103 #endif
104    };
105 
106    agx_ppp_push(&ppp, PPP_HEADER, cfg) {
107       cfg = present;
108    }
109 
110    return ppp;
111 }
112 
113 static inline void
agx_ppp_fini(uint8_t ** out,struct agx_ppp_update * ppp)114 agx_ppp_fini(uint8_t **out, struct agx_ppp_update *ppp)
115 {
116    size_t size = ppp->total_size;
117    assert((size % 4) == 0);
118    size_t size_words = size / 4;
119 
120 #ifndef NDEBUG
121    assert(size == (ppp->head - ppp->cpu_base) && "mismatched ppp size");
122 #endif
123 
124    assert(ppp->gpu_base < (1ull << 40));
125    assert(size_words < (1ull << 24));
126 
127    agx_pack(*out, PPP_STATE, cfg) {
128       cfg.pointer_hi = (ppp->gpu_base >> 32);
129       cfg.pointer_lo = (uint32_t)ppp->gpu_base;
130       cfg.size_words = size_words;
131    };
132 
133    *out += AGX_PPP_STATE_LENGTH;
134 }
135