1 /*
2  * Copyright 2021 Alyssa Rosenzweig
3  * Copyright (C) 2019-2020 Collabora, Ltd.
4  * Copyright 2010 Red Hat Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * on the rights to use, copy, modify, merge, publish, distribute, sub
10  * license, and/or sell copies of the Software, and to permit persons to whom
11  * the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23  * USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include <stdio.h>
26 #include <errno.h>
27 #include "pipe/p_defines.h"
28 #include "pipe/p_state.h"
29 #include "pipe/p_context.h"
30 #include "pipe/p_screen.h"
31 #include "util/u_memory.h"
32 #include "util/u_inlines.h"
33 #include "util/u_transfer.h"
34 #include "gallium/auxiliary/util/u_draw.h"
35 #include "gallium/auxiliary/util/u_helpers.h"
36 #include "gallium/auxiliary/util/u_viewport.h"
37 #include "gallium/auxiliary/util/u_blend.h"
38 #include "gallium/auxiliary/util/u_framebuffer.h"
39 #include "gallium/auxiliary/tgsi/tgsi_from_mesa.h"
40 #include "gallium/auxiliary/nir/tgsi_to_nir.h"
41 #include "compiler/nir/nir.h"
42 #include "asahi/compiler/agx_compile.h"
43 #include "agx_state.h"
44 #include "asahi/lib/agx_pack.h"
45 #include "asahi/lib/agx_formats.h"
46 
47 static struct pipe_stream_output_target *
agx_create_stream_output_target(struct pipe_context * pctx,struct pipe_resource * prsc,unsigned buffer_offset,unsigned buffer_size)48 agx_create_stream_output_target(struct pipe_context *pctx,
49                                 struct pipe_resource *prsc,
50                                 unsigned buffer_offset,
51                                 unsigned buffer_size)
52 {
53    struct pipe_stream_output_target *target;
54 
55    target = &rzalloc(pctx, struct agx_streamout_target)->base;
56 
57    if (!target)
58       return NULL;
59 
60    pipe_reference_init(&target->reference, 1);
61    pipe_resource_reference(&target->buffer, prsc);
62 
63    target->context = pctx;
64    target->buffer_offset = buffer_offset;
65    target->buffer_size = buffer_size;
66 
67    return target;
68 }
69 
70 static void
agx_stream_output_target_destroy(struct pipe_context * pctx,struct pipe_stream_output_target * target)71 agx_stream_output_target_destroy(struct pipe_context *pctx,
72                                  struct pipe_stream_output_target *target)
73 {
74    pipe_resource_reference(&target->buffer, NULL);
75    ralloc_free(target);
76 }
77 
78 static void
agx_set_stream_output_targets(struct pipe_context * pctx,unsigned num_targets,struct pipe_stream_output_target ** targets,const unsigned * offsets)79 agx_set_stream_output_targets(struct pipe_context *pctx,
80                               unsigned num_targets,
81                               struct pipe_stream_output_target **targets,
82                               const unsigned *offsets)
83 {
84    struct agx_context *ctx = agx_context(pctx);
85    struct agx_streamout *so = &ctx->streamout;
86 
87    assert(num_targets <= ARRAY_SIZE(so->targets));
88 
89    for (unsigned i = 0; i < num_targets; i++) {
90       if (offsets[i] != -1)
91          agx_so_target(targets[i])->offset = offsets[i];
92 
93       pipe_so_target_reference(&so->targets[i], targets[i]);
94    }
95 
96    for (unsigned i = 0; i < so->num_targets; i++)
97       pipe_so_target_reference(&so->targets[i], NULL);
98 
99    so->num_targets = num_targets;
100 }
101 
102 static void
agx_set_blend_color(struct pipe_context * pctx,const struct pipe_blend_color * state)103 agx_set_blend_color(struct pipe_context *pctx,
104                     const struct pipe_blend_color *state)
105 {
106    struct agx_context *ctx = agx_context(pctx);
107 
108    if (state)
109       memcpy(&ctx->blend_color, state, sizeof(*state));
110 }
111 
112 static void *
agx_create_blend_state(struct pipe_context * ctx,const struct pipe_blend_state * state)113 agx_create_blend_state(struct pipe_context *ctx,
114                        const struct pipe_blend_state *state)
115 {
116    struct agx_blend *so = CALLOC_STRUCT(agx_blend);
117 
118    assert(!state->alpha_to_coverage);
119    assert(!state->alpha_to_coverage_dither);
120    assert(!state->alpha_to_one);
121    assert(!state->advanced_blend_func);
122 
123    if (state->logicop_enable) {
124       so->logicop_enable = true;
125       so->logicop_func = state->logicop_func;
126       return so;
127    }
128 
129    for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
130       unsigned rti = state->independent_blend_enable ? i : 0;
131       struct pipe_rt_blend_state rt = state->rt[rti];
132 
133       if (!rt.blend_enable) {
134          static const nir_lower_blend_channel replace = {
135             .func = BLEND_FUNC_ADD,
136             .src_factor = BLEND_FACTOR_ZERO,
137             .invert_src_factor = true,
138             .dst_factor = BLEND_FACTOR_ZERO,
139             .invert_dst_factor = false,
140          };
141 
142          so->rt[i].rgb = replace;
143          so->rt[i].alpha = replace;
144       } else {
145          so->rt[i].rgb.func = util_blend_func_to_shader(rt.rgb_func);
146          so->rt[i].rgb.src_factor = util_blend_factor_to_shader(rt.rgb_src_factor);
147          so->rt[i].rgb.invert_src_factor = util_blend_factor_is_inverted(rt.rgb_src_factor);
148          so->rt[i].rgb.dst_factor = util_blend_factor_to_shader(rt.rgb_dst_factor);
149          so->rt[i].rgb.invert_dst_factor = util_blend_factor_is_inverted(rt.rgb_dst_factor);
150 
151          so->rt[i].alpha.func = util_blend_func_to_shader(rt.alpha_func);
152          so->rt[i].alpha.src_factor = util_blend_factor_to_shader(rt.alpha_src_factor);
153          so->rt[i].alpha.invert_src_factor = util_blend_factor_is_inverted(rt.alpha_src_factor);
154          so->rt[i].alpha.dst_factor = util_blend_factor_to_shader(rt.alpha_dst_factor);
155          so->rt[i].alpha.invert_dst_factor = util_blend_factor_is_inverted(rt.alpha_dst_factor);
156 
157 	 so->blend_enable = true;
158       }
159 
160       so->rt[i].colormask = rt.colormask;
161    }
162 
163    return so;
164 }
165 
166 static void
agx_bind_blend_state(struct pipe_context * pctx,void * cso)167 agx_bind_blend_state(struct pipe_context *pctx, void *cso)
168 {
169    struct agx_context *ctx = agx_context(pctx);
170    ctx->blend = cso;
171 }
172 
173 static const enum agx_stencil_op agx_stencil_ops[PIPE_STENCIL_OP_INVERT + 1] = {
174    [PIPE_STENCIL_OP_KEEP] = AGX_STENCIL_OP_KEEP,
175    [PIPE_STENCIL_OP_ZERO] = AGX_STENCIL_OP_ZERO,
176    [PIPE_STENCIL_OP_REPLACE] = AGX_STENCIL_OP_REPLACE,
177    [PIPE_STENCIL_OP_INCR] = AGX_STENCIL_OP_INCR_SAT,
178    [PIPE_STENCIL_OP_DECR] = AGX_STENCIL_OP_DECR_SAT,
179    [PIPE_STENCIL_OP_INCR_WRAP] = AGX_STENCIL_OP_INCR_WRAP,
180    [PIPE_STENCIL_OP_DECR_WRAP] = AGX_STENCIL_OP_DECR_WRAP,
181    [PIPE_STENCIL_OP_INVERT] = AGX_STENCIL_OP_INVERT,
182 };
183 
184 static void
agx_pack_rasterizer_face(struct agx_rasterizer_face_packed * out,struct pipe_stencil_state st,enum agx_zs_func z_func,bool disable_z_write)185 agx_pack_rasterizer_face(struct agx_rasterizer_face_packed *out,
186                          struct pipe_stencil_state st,
187                          enum agx_zs_func z_func,
188                          bool disable_z_write)
189 {
190    agx_pack(out, RASTERIZER_FACE, cfg) {
191       cfg.depth_function = z_func;
192       cfg.disable_depth_write = disable_z_write;
193 
194       if (st.enabled) {
195          cfg.stencil_write_mask = st.writemask;
196          cfg.stencil_read_mask = st.valuemask;
197 
198          cfg.depth_pass   = agx_stencil_ops[st.zpass_op];
199          cfg.depth_fail   = agx_stencil_ops[st.zfail_op];
200          cfg.stencil_fail = agx_stencil_ops[st.fail_op];
201 
202          cfg.stencil_compare = (enum agx_zs_func) st.func;
203       } else {
204          cfg.stencil_write_mask = 0xFF;
205          cfg.stencil_read_mask = 0xFF;
206 
207          cfg.depth_pass = AGX_STENCIL_OP_KEEP;
208          cfg.depth_fail = AGX_STENCIL_OP_KEEP;
209          cfg.stencil_fail = AGX_STENCIL_OP_KEEP;
210 
211          cfg.stencil_compare = AGX_ZS_FUNC_ALWAYS;
212       }
213    }
214 }
215 
216 static void *
agx_create_zsa_state(struct pipe_context * ctx,const struct pipe_depth_stencil_alpha_state * state)217 agx_create_zsa_state(struct pipe_context *ctx,
218                      const struct pipe_depth_stencil_alpha_state *state)
219 {
220    struct agx_zsa *so = CALLOC_STRUCT(agx_zsa);
221    assert(!state->depth_bounds_test && "todo");
222 
223    so->base = *state;
224 
225    /* Z func can be used as-is */
226    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_NEVER    == AGX_ZS_FUNC_NEVER);
227    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_LESS     == AGX_ZS_FUNC_LESS);
228    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_EQUAL    == AGX_ZS_FUNC_EQUAL);
229    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_LEQUAL   == AGX_ZS_FUNC_LEQUAL);
230    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_GREATER  == AGX_ZS_FUNC_GREATER);
231    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_NOTEQUAL == AGX_ZS_FUNC_NOT_EQUAL);
232    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_GEQUAL   == AGX_ZS_FUNC_GEQUAL);
233    STATIC_ASSERT((enum agx_zs_func) PIPE_FUNC_ALWAYS   == AGX_ZS_FUNC_ALWAYS);
234 
235    enum agx_zs_func z_func = state->depth_enabled ?
236                 ((enum agx_zs_func) state->depth_func) : AGX_ZS_FUNC_ALWAYS;
237 
238    agx_pack_rasterizer_face(&so->front,
239          state->stencil[0], z_func, !state->depth_writemask);
240 
241    if (state->stencil[1].enabled) {
242       agx_pack_rasterizer_face(&so->back,
243             state->stencil[1], z_func, !state->depth_writemask);
244    } else {
245       /* One sided stencil */
246       so->back = so->front;
247    }
248 
249    return so;
250 }
251 
252 static void
agx_bind_zsa_state(struct pipe_context * pctx,void * cso)253 agx_bind_zsa_state(struct pipe_context *pctx, void *cso)
254 {
255    struct agx_context *ctx = agx_context(pctx);
256 
257    if (cso)
258       memcpy(&ctx->zs, cso, sizeof(ctx->zs));
259 }
260 
261 static void *
agx_create_rs_state(struct pipe_context * ctx,const struct pipe_rasterizer_state * cso)262 agx_create_rs_state(struct pipe_context *ctx,
263                     const struct pipe_rasterizer_state *cso)
264 {
265    struct agx_rasterizer *so = CALLOC_STRUCT(agx_rasterizer);
266    so->base = *cso;
267 
268    /* Line width is packed in a 4:4 fixed point format */
269    unsigned line_width_fixed = ((unsigned) (cso->line_width * 16.0f)) - 1;
270 
271    /* Clamp to maximum line width */
272    so->line_width = MIN2(line_width_fixed, 0xFF);
273 
274    agx_pack(so->cull, CULL, cfg) {
275       cfg.cull_front = cso->cull_face & PIPE_FACE_FRONT;
276       cfg.cull_back = cso->cull_face & PIPE_FACE_BACK;
277       cfg.front_face_ccw = cso->front_ccw;
278       cfg.depth_clip = cso->depth_clip_near;
279       cfg.depth_clamp = !cso->depth_clip_near;
280    };
281 
282    return so;
283 }
284 
285 static void
agx_bind_rasterizer_state(struct pipe_context * pctx,void * cso)286 agx_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
287 {
288    struct agx_context *ctx = agx_context(pctx);
289    struct agx_rasterizer *so = cso;
290 
291    /* Check if scissor state has changed, since scissor enable is part of the
292     * rasterizer state but everything else needed for scissors is part of
293     * viewport/scissor states */
294    bool scissor_changed = (cso == NULL) || (ctx->rast == NULL) ||
295       (ctx->rast->base.scissor != so->base.scissor);
296 
297    ctx->rast = so;
298 
299    if (scissor_changed)
300       ctx->dirty |= AGX_DIRTY_SCISSOR;
301 }
302 
303 static enum agx_wrap
agx_wrap_from_pipe(enum pipe_tex_wrap in)304 agx_wrap_from_pipe(enum pipe_tex_wrap in)
305 {
306    switch (in) {
307    case PIPE_TEX_WRAP_REPEAT: return AGX_WRAP_REPEAT;
308    case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return AGX_WRAP_CLAMP_TO_EDGE;
309    case PIPE_TEX_WRAP_MIRROR_REPEAT: return AGX_WRAP_MIRRORED_REPEAT;
310    case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return AGX_WRAP_CLAMP_TO_BORDER;
311    default: unreachable("todo: more wrap modes");
312    }
313 }
314 
315 static enum agx_mip_filter
agx_mip_filter_from_pipe(enum pipe_tex_mipfilter in)316 agx_mip_filter_from_pipe(enum pipe_tex_mipfilter in)
317 {
318    switch (in) {
319    case PIPE_TEX_MIPFILTER_NEAREST: return AGX_MIP_FILTER_NEAREST;
320    case PIPE_TEX_MIPFILTER_LINEAR: return AGX_MIP_FILTER_LINEAR;
321    case PIPE_TEX_MIPFILTER_NONE: return AGX_MIP_FILTER_NONE;
322    }
323 
324    unreachable("Invalid mip filter");
325 }
326 
327 static const enum agx_compare_func agx_compare_funcs[PIPE_FUNC_ALWAYS + 1] = {
328    [PIPE_FUNC_NEVER] = AGX_COMPARE_FUNC_NEVER,
329    [PIPE_FUNC_LESS] = AGX_COMPARE_FUNC_LESS,
330    [PIPE_FUNC_EQUAL] = AGX_COMPARE_FUNC_EQUAL,
331    [PIPE_FUNC_LEQUAL] = AGX_COMPARE_FUNC_LEQUAL,
332    [PIPE_FUNC_GREATER] = AGX_COMPARE_FUNC_GREATER,
333    [PIPE_FUNC_NOTEQUAL] = AGX_COMPARE_FUNC_NOT_EQUAL,
334    [PIPE_FUNC_GEQUAL] = AGX_COMPARE_FUNC_GEQUAL,
335    [PIPE_FUNC_ALWAYS] = AGX_COMPARE_FUNC_ALWAYS,
336 };
337 
338 static void *
agx_create_sampler_state(struct pipe_context * pctx,const struct pipe_sampler_state * state)339 agx_create_sampler_state(struct pipe_context *pctx,
340                          const struct pipe_sampler_state *state)
341 {
342    struct agx_device *dev = agx_device(pctx->screen);
343    struct agx_bo *bo = agx_bo_create(dev, AGX_SAMPLER_LENGTH,
344                                      AGX_MEMORY_TYPE_FRAMEBUFFER);
345 
346    assert(state->min_lod == 0 && "todo: lod clamps");
347    assert(state->lod_bias == 0 && "todo: lod bias");
348 
349    agx_pack(bo->ptr.cpu, SAMPLER, cfg) {
350       cfg.magnify_linear = (state->mag_img_filter == PIPE_TEX_FILTER_LINEAR);
351       cfg.minify_linear = (state->min_img_filter == PIPE_TEX_FILTER_LINEAR);
352       cfg.mip_filter = agx_mip_filter_from_pipe(state->min_mip_filter);
353       cfg.wrap_s = agx_wrap_from_pipe(state->wrap_s);
354       cfg.wrap_t = agx_wrap_from_pipe(state->wrap_t);
355       cfg.wrap_r = agx_wrap_from_pipe(state->wrap_r);
356       cfg.pixel_coordinates = !state->normalized_coords;
357       cfg.compare_func = agx_compare_funcs[state->compare_func];
358    }
359 
360    struct agx_sampler_state *so = CALLOC_STRUCT(agx_sampler_state);
361    so->base = *state;
362    so->desc = bo;
363 
364    return so;
365 }
366 
367 static void
agx_delete_sampler_state(struct pipe_context * ctx,void * state)368 agx_delete_sampler_state(struct pipe_context *ctx, void *state)
369 {
370    struct agx_bo *bo = state;
371    agx_bo_unreference(bo);
372 }
373 
374 static void
agx_bind_sampler_states(struct pipe_context * pctx,enum pipe_shader_type shader,unsigned start,unsigned count,void ** states)375 agx_bind_sampler_states(struct pipe_context *pctx,
376                         enum pipe_shader_type shader,
377                         unsigned start, unsigned count,
378                         void **states)
379 {
380    struct agx_context *ctx = agx_context(pctx);
381 
382    ctx->stage[shader].sampler_count = states ? count : 0;
383 
384    memcpy(&ctx->stage[shader].samplers[start], states,
385           sizeof(struct agx_sampler_state *) * count);
386 }
387 
388 /* Channels agree for RGBA but are weird for force 0/1 */
389 
390 static enum agx_channel
agx_channel_from_pipe(enum pipe_swizzle in)391 agx_channel_from_pipe(enum pipe_swizzle in)
392 {
393    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_X == AGX_CHANNEL_R);
394    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Y == AGX_CHANNEL_G);
395    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Z == AGX_CHANNEL_B);
396    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_W == AGX_CHANNEL_A);
397    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_0 & 0x4);
398    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_1 & 0x4);
399    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_NONE & 0x4);
400 
401    if ((in & 0x4) == 0)
402       return (enum agx_channel) in;
403    else if (in == PIPE_SWIZZLE_1)
404       return AGX_CHANNEL_1;
405    else
406       return AGX_CHANNEL_0;
407 }
408 
409 static enum agx_layout
agx_translate_layout(uint64_t modifier)410 agx_translate_layout(uint64_t modifier)
411 {
412    switch (modifier) {
413    case DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER:
414       return AGX_LAYOUT_TILED_64X64;
415    case DRM_FORMAT_MOD_LINEAR:
416       return AGX_LAYOUT_LINEAR;
417    default:
418       unreachable("Invalid modifier");
419    }
420 }
421 
422 static enum agx_texture_dimension
agx_translate_texture_dimension(enum pipe_texture_target dim)423 agx_translate_texture_dimension(enum pipe_texture_target dim)
424 {
425    switch (dim) {
426    case PIPE_TEXTURE_2D: return AGX_TEXTURE_DIMENSION_2D;
427    case PIPE_TEXTURE_CUBE: return AGX_TEXTURE_DIMENSION_CUBE;
428    default: unreachable("Unsupported texture dimension");
429    }
430 }
431 
432 static struct pipe_sampler_view *
agx_create_sampler_view(struct pipe_context * pctx,struct pipe_resource * texture,const struct pipe_sampler_view * state)433 agx_create_sampler_view(struct pipe_context *pctx,
434                         struct pipe_resource *texture,
435                         const struct pipe_sampler_view *state)
436 {
437    struct agx_device *dev = agx_device(pctx->screen);
438    struct agx_resource *rsrc = agx_resource(texture);
439    struct agx_sampler_view *so = CALLOC_STRUCT(agx_sampler_view);
440 
441    if (!so)
442       return NULL;
443 
444    /* We prepare the descriptor at CSO create time */
445    so->desc = agx_bo_create(dev, AGX_TEXTURE_LENGTH,
446                             AGX_MEMORY_TYPE_FRAMEBUFFER);
447 
448    const struct util_format_description *desc =
449       util_format_description(state->format);
450 
451    /* We only have a single swizzle for the user swizzle and the format fixup,
452     * so compose them now. */
453    uint8_t out_swizzle[4];
454    uint8_t view_swizzle[4] = {
455       state->swizzle_r, state->swizzle_g,
456       state->swizzle_b, state->swizzle_a
457    };
458 
459    util_format_compose_swizzles(desc->swizzle, view_swizzle, out_swizzle);
460 
461    unsigned level = state->u.tex.first_level;
462    assert(state->u.tex.first_layer == 0);
463 
464    /* Pack the descriptor into GPU memory */
465    agx_pack(so->desc->ptr.cpu, TEXTURE, cfg) {
466       cfg.dimension = agx_translate_texture_dimension(state->target);
467       cfg.layout = agx_translate_layout(rsrc->modifier);
468       cfg.format = agx_pixel_format[state->format].hw;
469       cfg.swizzle_r = agx_channel_from_pipe(out_swizzle[0]);
470       cfg.swizzle_g = agx_channel_from_pipe(out_swizzle[1]);
471       cfg.swizzle_b = agx_channel_from_pipe(out_swizzle[2]);
472       cfg.swizzle_a = agx_channel_from_pipe(out_swizzle[3]);
473       cfg.width = u_minify(texture->width0, level);
474       cfg.height = u_minify(texture->height0, level);
475       cfg.levels = state->u.tex.last_level - level + 1;
476       cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
477       cfg.address = rsrc->bo->ptr.gpu + rsrc->slices[level].offset;
478       cfg.unk_2 = false;
479 
480       cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?
481          (rsrc->slices[level].line_stride - 16) :
482          AGX_RT_STRIDE_TILED;
483    }
484 
485    /* Initialize base object */
486    so->base = *state;
487    so->base.texture = NULL;
488    pipe_resource_reference(&so->base.texture, texture);
489    pipe_reference_init(&so->base.reference, 1);
490    so->base.context = pctx;
491    return &so->base;
492 }
493 
494 static void
agx_set_sampler_views(struct pipe_context * pctx,enum pipe_shader_type shader,unsigned start,unsigned count,unsigned unbind_num_trailing_slots,bool take_ownership,struct pipe_sampler_view ** views)495 agx_set_sampler_views(struct pipe_context *pctx,
496                       enum pipe_shader_type shader,
497                       unsigned start, unsigned count,
498                       unsigned unbind_num_trailing_slots,
499                       bool take_ownership,
500                       struct pipe_sampler_view **views)
501 {
502    struct agx_context *ctx = agx_context(pctx);
503    unsigned new_nr = 0;
504    unsigned i;
505 
506    assert(start == 0);
507 
508    if (!views)
509       count = 0;
510 
511    for (i = 0; i < count; ++i) {
512       if (views[i])
513          new_nr = i + 1;
514 
515       if (take_ownership) {
516          pipe_sampler_view_reference((struct pipe_sampler_view **)
517                                      &ctx->stage[shader].textures[i], NULL);
518          ctx->stage[shader].textures[i] = (struct agx_sampler_view *)views[i];
519       } else {
520          pipe_sampler_view_reference((struct pipe_sampler_view **)
521                                      &ctx->stage[shader].textures[i], views[i]);
522       }
523    }
524 
525    for (; i < ctx->stage[shader].texture_count; i++) {
526       pipe_sampler_view_reference((struct pipe_sampler_view **)
527                                   &ctx->stage[shader].textures[i], NULL);
528    }
529    ctx->stage[shader].texture_count = new_nr;
530 }
531 
532 static void
agx_sampler_view_destroy(struct pipe_context * ctx,struct pipe_sampler_view * pview)533 agx_sampler_view_destroy(struct pipe_context *ctx,
534                          struct pipe_sampler_view *pview)
535 {
536    struct agx_sampler_view *view = (struct agx_sampler_view *) pview;
537    pipe_resource_reference(&view->base.texture, NULL);
538    agx_bo_unreference(view->desc);
539    FREE(view);
540 }
541 
542 static struct pipe_surface *
agx_create_surface(struct pipe_context * ctx,struct pipe_resource * texture,const struct pipe_surface * surf_tmpl)543 agx_create_surface(struct pipe_context *ctx,
544                    struct pipe_resource *texture,
545                    const struct pipe_surface *surf_tmpl)
546 {
547    struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
548 
549    if (!surface)
550       return NULL;
551    pipe_reference_init(&surface->reference, 1);
552    pipe_resource_reference(&surface->texture, texture);
553    surface->context = ctx;
554    surface->format = surf_tmpl->format;
555    surface->width = texture->width0;
556    surface->height = texture->height0;
557    surface->texture = texture;
558    surface->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
559    surface->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
560    surface->u.tex.level = surf_tmpl->u.tex.level;
561 
562    return surface;
563 }
564 
565 static void
agx_set_clip_state(struct pipe_context * ctx,const struct pipe_clip_state * state)566 agx_set_clip_state(struct pipe_context *ctx,
567                    const struct pipe_clip_state *state)
568 {
569 }
570 
571 static void
agx_set_polygon_stipple(struct pipe_context * ctx,const struct pipe_poly_stipple * state)572 agx_set_polygon_stipple(struct pipe_context *ctx,
573                         const struct pipe_poly_stipple *state)
574 {
575 }
576 
577 static void
agx_set_sample_mask(struct pipe_context * pipe,unsigned sample_mask)578 agx_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)
579 {
580    struct agx_context *ctx = agx_context(pipe);
581    ctx->sample_mask = sample_mask;
582 }
583 
584 static void
agx_set_scissor_states(struct pipe_context * pctx,unsigned start_slot,unsigned num_scissors,const struct pipe_scissor_state * scissor)585 agx_set_scissor_states(struct pipe_context *pctx,
586                        unsigned start_slot,
587                        unsigned num_scissors,
588                        const struct pipe_scissor_state *scissor)
589 {
590    struct agx_context *ctx = agx_context(pctx);
591 
592    assert(start_slot == 0 && "no geometry shaders");
593    assert(num_scissors == 1 && "no geometry shaders");
594 
595    ctx->scissor = *scissor;
596    ctx->dirty |= AGX_DIRTY_SCISSOR;
597 }
598 
599 static void
agx_set_stencil_ref(struct pipe_context * pctx,const struct pipe_stencil_ref state)600 agx_set_stencil_ref(struct pipe_context *pctx,
601                     const struct pipe_stencil_ref state)
602 {
603    struct agx_context *ctx = agx_context(pctx);
604    ctx->stencil_ref = state;
605 }
606 
607 static void
agx_set_viewport_states(struct pipe_context * pctx,unsigned start_slot,unsigned num_viewports,const struct pipe_viewport_state * vp)608 agx_set_viewport_states(struct pipe_context *pctx,
609                         unsigned start_slot,
610                         unsigned num_viewports,
611                         const struct pipe_viewport_state *vp)
612 {
613    struct agx_context *ctx = agx_context(pctx);
614 
615    assert(start_slot == 0 && "no geometry shaders");
616    assert(num_viewports == 1 && "no geometry shaders");
617 
618    ctx->dirty |= AGX_DIRTY_VIEWPORT;
619    ctx->viewport = *vp;
620 }
621 
622 struct agx_viewport_scissor {
623    uint64_t viewport;
624    unsigned scissor;
625 };
626 
627 static struct agx_viewport_scissor
agx_upload_viewport_scissor(struct agx_pool * pool,struct agx_batch * batch,const struct pipe_viewport_state * vp,const struct pipe_scissor_state * ss)628 agx_upload_viewport_scissor(struct agx_pool *pool,
629                             struct agx_batch *batch,
630                             const struct pipe_viewport_state *vp,
631                             const struct pipe_scissor_state *ss)
632 {
633    struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_VIEWPORT_LENGTH, 64);
634 
635    float trans_x = vp->translate[0], trans_y = vp->translate[1];
636    float abs_scale_x = fabsf(vp->scale[0]), abs_scale_y = fabsf(vp->scale[1]);
637 
638    /* Calculate the extent of the viewport. Note if a particular dimension of
639     * the viewport is an odd number of pixels, both the translate and the scale
640     * will have a fractional part of 0.5, so adding and subtracting them yields
641     * an integer. Therefore we don't need to round explicitly */
642    unsigned minx = CLAMP((int) (trans_x - abs_scale_x), 0, batch->width);
643    unsigned miny = CLAMP((int) (trans_y - abs_scale_y), 0, batch->height);
644    unsigned maxx = CLAMP((int) (trans_x + abs_scale_x), 0, batch->width);
645    unsigned maxy = CLAMP((int) (trans_y + abs_scale_y), 0, batch->height);
646 
647    if (ss) {
648       minx = MAX2(ss->minx, minx);
649       miny = MAX2(ss->miny, miny);
650       maxx = MIN2(ss->maxx, maxx);
651       maxy = MIN2(ss->maxy, maxy);
652    }
653 
654    assert(maxx > minx && maxy > miny);
655 
656    float minz, maxz;
657    util_viewport_zmin_zmax(vp, false, &minz, &maxz);
658 
659    agx_pack(T.cpu, VIEWPORT, cfg) {
660       cfg.min_tile_x = minx / 32;
661       cfg.min_tile_y = miny / 32;
662       cfg.max_tile_x = DIV_ROUND_UP(maxx, 32);
663       cfg.max_tile_y = DIV_ROUND_UP(maxy, 32);
664       cfg.clip_tile = true;
665 
666       cfg.translate_x = vp->translate[0];
667       cfg.translate_y = vp->translate[1];
668       cfg.scale_x = vp->scale[0];
669       cfg.scale_y = vp->scale[1];
670 
671       /* Assumes [0, 1] clip coordinates. If half-z is not in use, lower_half_z
672        * is called to ensure this works. */
673       cfg.translate_z = minz;
674       cfg.scale_z = maxz - minz;
675    };
676 
677    /* Allocate a new scissor descriptor */
678    struct agx_scissor_packed *ptr = batch->scissor.bo->ptr.cpu;
679    unsigned index = (batch->scissor.count++);
680 
681    agx_pack(ptr + index, SCISSOR, cfg) {
682       cfg.min_x = minx;
683       cfg.min_y = miny;
684       cfg.min_z = minz;
685       cfg.max_x = maxx;
686       cfg.max_y = maxy;
687       cfg.max_z = maxz;
688    }
689 
690    return (struct agx_viewport_scissor) {
691       .viewport = T.gpu,
692       .scissor = index
693    };
694 }
695 
696 /* A framebuffer state can be reused across batches, so it doesn't make sense
697  * to add surfaces to the BO list here. Instead we added them when flushing.
698  */
699 
700 static void
agx_set_framebuffer_state(struct pipe_context * pctx,const struct pipe_framebuffer_state * state)701 agx_set_framebuffer_state(struct pipe_context *pctx,
702                           const struct pipe_framebuffer_state *state)
703 {
704    struct agx_context *ctx = agx_context(pctx);
705 
706    if (!state)
707       return;
708 
709    /* XXX: eliminate this flush with batch tracking logic */
710    pctx->flush(pctx, NULL, 0);
711 
712    util_copy_framebuffer_state(&ctx->framebuffer, state);
713    ctx->batch->width = state->width;
714    ctx->batch->height = state->height;
715    ctx->batch->nr_cbufs = state->nr_cbufs;
716    ctx->batch->cbufs[0] = state->cbufs[0];
717    ctx->batch->zsbuf = state->zsbuf;
718    ctx->dirty = ~0;
719 
720    for (unsigned i = 0; i < state->nr_cbufs; ++i) {
721       struct pipe_surface *surf = state->cbufs[i];
722       struct agx_resource *tex = agx_resource(surf->texture);
723       const struct util_format_description *desc =
724          util_format_description(surf->format);
725 
726       agx_pack(ctx->render_target[i], RENDER_TARGET, cfg) {
727          cfg.layout = agx_translate_layout(tex->modifier);
728          cfg.format = agx_pixel_format[surf->format].hw;
729          cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);
730          cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);
731          cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);
732          cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);
733          cfg.width = state->width;
734          cfg.height = state->height;
735          cfg.buffer = tex->bo->ptr.gpu;
736 
737          cfg.stride = (tex->modifier == DRM_FORMAT_MOD_LINEAR) ?
738             (tex->slices[0].line_stride - 4) :
739             AGX_RT_STRIDE_TILED;
740       };
741    }
742 }
743 
744 /* Likewise constant buffers, textures, and samplers are handled in a common
745  * per-draw path, with dirty tracking to reduce the costs involved.
746  */
747 
748 static void
agx_set_constant_buffer(struct pipe_context * pctx,enum pipe_shader_type shader,uint index,bool take_ownership,const struct pipe_constant_buffer * cb)749 agx_set_constant_buffer(struct pipe_context *pctx,
750                         enum pipe_shader_type shader, uint index,
751                         bool take_ownership,
752                         const struct pipe_constant_buffer *cb)
753 {
754    struct agx_context *ctx = agx_context(pctx);
755    struct agx_stage *s = &ctx->stage[shader];
756 
757    util_copy_constant_buffer(&s->cb[index], cb, take_ownership);
758 
759    unsigned mask = (1 << index);
760 
761    if (cb)
762       s->cb_mask |= mask;
763    else
764       s->cb_mask &= ~mask;
765 }
766 
767 static void
agx_surface_destroy(struct pipe_context * ctx,struct pipe_surface * surface)768 agx_surface_destroy(struct pipe_context *ctx,
769                     struct pipe_surface *surface)
770 {
771    pipe_resource_reference(&surface->texture, NULL);
772    FREE(surface);
773 }
774 
775 static void
agx_delete_state(struct pipe_context * ctx,void * state)776 agx_delete_state(struct pipe_context *ctx, void *state)
777 {
778    FREE(state);
779 }
780 
781 /* BOs added to the batch in the uniform upload path */
782 
783 static void
agx_set_vertex_buffers(struct pipe_context * pctx,unsigned start_slot,unsigned count,unsigned unbind_num_trailing_slots,bool take_ownership,const struct pipe_vertex_buffer * buffers)784 agx_set_vertex_buffers(struct pipe_context *pctx,
785                        unsigned start_slot, unsigned count,
786                        unsigned unbind_num_trailing_slots,
787                        bool take_ownership,
788                        const struct pipe_vertex_buffer *buffers)
789 {
790    struct agx_context *ctx = agx_context(pctx);
791 
792    util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,
793                                 start_slot, count, unbind_num_trailing_slots, take_ownership);
794 
795    ctx->dirty |= AGX_DIRTY_VERTEX;
796 }
797 
798 static void *
agx_create_vertex_elements(struct pipe_context * ctx,unsigned count,const struct pipe_vertex_element * state)799 agx_create_vertex_elements(struct pipe_context *ctx,
800                            unsigned count,
801                            const struct pipe_vertex_element *state)
802 {
803    assert(count < AGX_MAX_ATTRIBS);
804 
805    struct agx_attribute *attribs = calloc(sizeof(*attribs), AGX_MAX_ATTRIBS);
806    for (unsigned i = 0; i < count; ++i) {
807       const struct pipe_vertex_element ve = state[i];
808 
809       const struct util_format_description *desc =
810          util_format_description(ve.src_format);
811 
812       unsigned chan_size = desc->channel[0].size / 8;
813 
814       assert(chan_size == 1 || chan_size == 2 || chan_size == 4);
815       assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);
816       assert((ve.src_offset & (chan_size - 1)) == 0);
817 
818       attribs[i] = (struct agx_attribute) {
819          .buf = ve.vertex_buffer_index,
820          .src_offset = ve.src_offset / chan_size,
821          .nr_comps_minus_1 = desc->nr_channels - 1,
822          .format = agx_vertex_format[ve.src_format],
823          .divisor = ve.instance_divisor
824       };
825    }
826 
827    return attribs;
828 }
829 
830 static void
agx_bind_vertex_elements_state(struct pipe_context * pctx,void * cso)831 agx_bind_vertex_elements_state(struct pipe_context *pctx, void *cso)
832 {
833    struct agx_context *ctx = agx_context(pctx);
834    ctx->attributes = cso;
835    ctx->dirty |= AGX_DIRTY_VERTEX;
836 }
837 
asahi_shader_key_hash(const void * key)838 static uint32_t asahi_shader_key_hash(const void *key)
839 {
840    return _mesa_hash_data(key, sizeof(struct asahi_shader_key));
841 }
842 
asahi_shader_key_equal(const void * a,const void * b)843 static bool asahi_shader_key_equal(const void *a, const void *b)
844 {
845    return memcmp(a, b, sizeof(struct asahi_shader_key)) == 0;
846 }
847 
848 static void *
agx_create_shader_state(struct pipe_context * pctx,const struct pipe_shader_state * cso)849 agx_create_shader_state(struct pipe_context *pctx,
850                         const struct pipe_shader_state *cso)
851 {
852    struct agx_uncompiled_shader *so = CALLOC_STRUCT(agx_uncompiled_shader);
853 
854    if (!so)
855       return NULL;
856 
857    so->base = *cso;
858 
859    if (cso->type == PIPE_SHADER_IR_NIR) {
860       so->nir = cso->ir.nir;
861    } else {
862       assert(cso->type == PIPE_SHADER_IR_TGSI);
863       so->nir = tgsi_to_nir(cso->tokens, pctx->screen, false);
864    }
865 
866    so->variants = _mesa_hash_table_create(NULL, asahi_shader_key_hash, asahi_shader_key_equal);
867    return so;
868 }
869 
870 static bool
agx_update_shader(struct agx_context * ctx,struct agx_compiled_shader ** out,enum pipe_shader_type stage,struct asahi_shader_key * key)871 agx_update_shader(struct agx_context *ctx, struct agx_compiled_shader **out,
872                   enum pipe_shader_type stage, struct asahi_shader_key *key)
873 {
874    struct agx_uncompiled_shader *so = ctx->stage[stage].shader;
875    assert(so != NULL);
876 
877    struct hash_entry *he = _mesa_hash_table_search(so->variants, key);
878 
879    if (he) {
880       if ((*out) == he->data)
881          return false;
882 
883       *out = he->data;
884       return true;
885    }
886 
887    struct agx_compiled_shader *compiled = CALLOC_STRUCT(agx_compiled_shader);
888    struct util_dynarray binary;
889    util_dynarray_init(&binary, NULL);
890 
891    nir_shader *nir = nir_shader_clone(NULL, so->nir);
892 
893    if (key->blend.blend_enable) {
894       nir_lower_blend_options opts = {
895          .format = { key->rt_formats[0] },
896          .scalar_blend_const = true
897       };
898 
899       memcpy(opts.rt, key->blend.rt, sizeof(opts.rt));
900       NIR_PASS_V(nir, nir_lower_blend, opts);
901    } else if (key->blend.logicop_enable) {
902       nir_lower_blend_options opts = {
903          .format = { key->rt_formats[0] },
904          .logicop_enable = true,
905          .logicop_func = key->blend.logicop_func,
906       };
907 
908       NIR_PASS_V(nir, nir_lower_blend, opts);
909    }
910 
911    if (stage == PIPE_SHADER_FRAGMENT)
912       NIR_PASS_V(nir, nir_lower_fragcolor, key->nr_cbufs);
913 
914    agx_compile_shader_nir(nir, &key->base, &binary, &compiled->info);
915 
916    struct agx_varyings *varyings = &compiled->info.varyings;
917    unsigned packed_varying_sz = (AGX_VARYING_HEADER_LENGTH + varyings->nr_descs * AGX_VARYING_LENGTH);
918    uint8_t *packed_varyings = alloca(packed_varying_sz);
919 
920    agx_pack(packed_varyings, VARYING_HEADER, cfg) {
921       cfg.triangle_slots = cfg.point_slots = varyings->nr_slots;
922    }
923 
924    memcpy(packed_varyings + AGX_VARYING_HEADER_LENGTH, varyings->packed,
925          varyings->nr_descs * AGX_VARYING_LENGTH);
926 
927    if (binary.size) {
928       struct agx_device *dev = agx_device(ctx->base.screen);
929       compiled->bo = agx_bo_create(dev,
930                                    ALIGN_POT(binary.size, 256) + (3 * packed_varying_sz),
931                                    AGX_MEMORY_TYPE_SHADER);
932       memcpy(compiled->bo->ptr.cpu, binary.data, binary.size);
933 
934 
935       /* TODO: Why is the varying descriptor duplicated 3x? */
936       unsigned offs = ALIGN_POT(binary.size, 256);
937       for (unsigned copy = 0; copy < 3; ++copy) {
938          memcpy(((uint8_t *) compiled->bo->ptr.cpu) + offs, packed_varyings, packed_varying_sz);
939          offs += packed_varying_sz;
940       }
941 
942       compiled->varyings = compiled->bo->ptr.gpu + ALIGN_POT(binary.size, 256);
943    }
944 
945    ralloc_free(nir);
946    util_dynarray_fini(&binary);
947 
948    he = _mesa_hash_table_insert(so->variants, key, compiled);
949    *out = he->data;
950    return true;
951 }
952 
953 static bool
agx_update_vs(struct agx_context * ctx)954 agx_update_vs(struct agx_context *ctx)
955 {
956    struct agx_vs_shader_key key = {
957       .num_vbufs = util_last_bit(ctx->vb_mask),
958       .clip_halfz = ctx->rast->base.clip_halfz,
959    };
960 
961    memcpy(key.attributes, ctx->attributes,
962           sizeof(key.attributes[0]) * AGX_MAX_ATTRIBS);
963 
964    u_foreach_bit(i, ctx->vb_mask) {
965       key.vbuf_strides[i] = ctx->vertex_buffers[i].stride;
966    }
967 
968    struct asahi_shader_key akey = {
969       .base.vs = key
970    };
971 
972    return agx_update_shader(ctx, &ctx->vs, PIPE_SHADER_VERTEX, &akey);
973 }
974 
975 static bool
agx_update_fs(struct agx_context * ctx)976 agx_update_fs(struct agx_context *ctx)
977 {
978    struct asahi_shader_key key = {
979       .nr_cbufs = ctx->batch->nr_cbufs,
980    };
981 
982    for (unsigned i = 0; i < key.nr_cbufs; ++i) {
983       struct pipe_surface *surf = ctx->batch->cbufs[i];
984 
985       if (surf) {
986          enum pipe_format fmt = surf->format;
987          key.rt_formats[i] = fmt;
988          key.base.fs.tib_formats[i] = agx_pixel_format[fmt].internal;
989       } else {
990          key.rt_formats[i] = PIPE_FORMAT_NONE;
991       }
992    }
993 
994    memcpy(&key.blend, ctx->blend, sizeof(key.blend));
995 
996    return agx_update_shader(ctx, &ctx->fs, PIPE_SHADER_FRAGMENT, &key);
997 }
998 
999 static void
agx_bind_shader_state(struct pipe_context * pctx,void * cso)1000 agx_bind_shader_state(struct pipe_context *pctx, void *cso)
1001 {
1002    if (!cso)
1003       return;
1004 
1005    struct agx_context *ctx = agx_context(pctx);
1006    struct agx_uncompiled_shader *so = cso;
1007 
1008    enum pipe_shader_type type = pipe_shader_type_from_mesa(so->nir->info.stage);
1009    ctx->stage[type].shader = so;
1010 }
1011 
1012 static void
agx_delete_compiled_shader(struct hash_entry * ent)1013 agx_delete_compiled_shader(struct hash_entry *ent)
1014 {
1015    struct agx_compiled_shader *so = ent->data;
1016    agx_bo_unreference(so->bo);
1017    FREE(so);
1018 }
1019 
1020 static void
agx_delete_shader_state(struct pipe_context * ctx,void * cso)1021 agx_delete_shader_state(struct pipe_context *ctx,
1022                         void *cso)
1023 {
1024    struct agx_uncompiled_shader *so = cso;
1025    _mesa_hash_table_destroy(so->variants, agx_delete_compiled_shader);
1026    free(so);
1027 }
1028 
1029 /* Pipeline consists of a sequence of binding commands followed by a set shader command */
1030 static uint32_t
agx_build_pipeline(struct agx_context * ctx,struct agx_compiled_shader * cs,enum pipe_shader_type stage)1031 agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum pipe_shader_type stage)
1032 {
1033    /* Pipelines must be 64-byte aligned */
1034    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1035                         (16 * AGX_BIND_UNIFORM_LENGTH) + // XXX: correct sizes, break up at compile time
1036                         (ctx->stage[stage].texture_count * AGX_BIND_TEXTURE_LENGTH) +
1037                         (PIPE_MAX_SAMPLERS * AGX_BIND_SAMPLER_LENGTH) +
1038                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1039                         64);
1040 
1041    uint8_t *record = ptr.cpu;
1042 
1043    /* There is a maximum number of half words we may push with a single
1044     * BIND_UNIFORM record, so split up the range to fit. We only need to call
1045     * agx_push_location once, however, which reduces the cost. */
1046    unsigned unif_records = 0;
1047 
1048    for (unsigned i = 0; i < cs->info.push_ranges; ++i) {
1049       struct agx_push push = cs->info.push[i];
1050       uint64_t buffer = agx_push_location(ctx, push, stage);
1051       unsigned halfs_per_record = 14;
1052       unsigned records = DIV_ROUND_UP(push.length, halfs_per_record);
1053 
1054       /* Ensure we don't overflow */
1055       unif_records += records;
1056       assert(unif_records < 16);
1057 
1058       for (unsigned j = 0; j < records; ++j) {
1059          agx_pack(record, BIND_UNIFORM, cfg) {
1060             cfg.start_halfs = push.base + (j * halfs_per_record);
1061             cfg.size_halfs = MIN2(push.length - (j * halfs_per_record), halfs_per_record);
1062             cfg.buffer = buffer + (j * halfs_per_record * 2);
1063          }
1064 
1065          record += AGX_BIND_UNIFORM_LENGTH;
1066       }
1067    }
1068 
1069    for (unsigned i = 0; i < ctx->stage[stage].texture_count; ++i) {
1070       struct agx_sampler_view *tex = ctx->stage[stage].textures[i];
1071       agx_batch_add_bo(ctx->batch, tex->desc);
1072       agx_batch_add_bo(ctx->batch, agx_resource(tex->base.texture)->bo);
1073 
1074 
1075       agx_pack(record, BIND_TEXTURE, cfg) {
1076          cfg.start = i;
1077          cfg.count = 1;
1078          cfg.buffer = tex->desc->ptr.gpu;
1079       }
1080 
1081       record += AGX_BIND_TEXTURE_LENGTH;
1082    }
1083 
1084    for (unsigned i = 0; i < PIPE_MAX_SAMPLERS; ++i) {
1085       struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];
1086 
1087       if (!sampler)
1088          continue;
1089 
1090       struct agx_bo *bo = sampler->desc;
1091       agx_batch_add_bo(ctx->batch, bo);
1092 
1093       agx_pack(record, BIND_SAMPLER, cfg) {
1094          cfg.start = i;
1095          cfg.count = 1;
1096          cfg.buffer = bo->ptr.gpu;
1097       }
1098 
1099       record += AGX_BIND_SAMPLER_LENGTH;
1100    }
1101 
1102    /* TODO: Can we prepack this? */
1103    if (stage == PIPE_SHADER_FRAGMENT) {
1104       agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1105          cfg.code = cs->bo->ptr.gpu;
1106          cfg.register_quadwords = 0;
1107          cfg.unk_3 = 0x8d;
1108          cfg.unk_1 = 0x2010bd;
1109          cfg.unk_2 = 0x0d;
1110          cfg.unk_2b = 1;
1111          cfg.unk_3b = 0x1;
1112          cfg.unk_4 = 0x800;
1113          cfg.preshader_unk = 0xc080;
1114          cfg.spill_size = 0x2;
1115       }
1116 
1117       record += AGX_SET_SHADER_EXTENDED_LENGTH;
1118    } else {
1119       agx_pack(record, SET_SHADER, cfg) {
1120          cfg.code = cs->bo->ptr.gpu;
1121          cfg.register_quadwords = 0;
1122          cfg.unk_2b = cs->info.varyings.nr_slots;
1123          cfg.unk_2 = 0x0d;
1124       }
1125 
1126       record += AGX_SET_SHADER_LENGTH;
1127    }
1128 
1129    /* End pipeline */
1130    memset(record, 0, 8);
1131    assert(ptr.gpu < (1ull << 32));
1132    return ptr.gpu;
1133 }
1134 
1135 /* Internal pipelines (TODO: refactor?) */
1136 uint64_t
agx_build_clear_pipeline(struct agx_context * ctx,uint32_t code,uint64_t clear_buf)1137 agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf)
1138 {
1139    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1140                         (1 * AGX_BIND_UNIFORM_LENGTH) +
1141                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1142                         64);
1143 
1144    uint8_t *record = ptr.cpu;
1145 
1146    agx_pack(record, BIND_UNIFORM, cfg) {
1147       cfg.start_halfs = (6 * 2);
1148       cfg.size_halfs = 4;
1149       cfg.buffer = clear_buf;
1150    }
1151 
1152    record += AGX_BIND_UNIFORM_LENGTH;
1153 
1154    /* TODO: Can we prepack this? */
1155    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1156       cfg.code = code;
1157       cfg.register_quadwords = 1;
1158       cfg.unk_3 = 0x8d;
1159       cfg.unk_2 = 0x0d;
1160       cfg.unk_2b = 4;
1161       cfg.frag_unk = 0x880100;
1162       cfg.preshader_mode = 0; // XXX
1163    }
1164 
1165    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1166 
1167    /* End pipeline */
1168    memset(record, 0, 8);
1169    return ptr.gpu;
1170 }
1171 
1172 uint64_t
agx_build_reload_pipeline(struct agx_context * ctx,uint32_t code,struct pipe_surface * surf)1173 agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf)
1174 {
1175    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1176                         (1 * AGX_BIND_TEXTURE_LENGTH) +
1177                         (1 * AGX_BIND_SAMPLER_LENGTH) +
1178                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1179                         64);
1180 
1181    uint8_t *record = ptr.cpu;
1182    struct agx_ptr sampler = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_SAMPLER_LENGTH, 64);
1183    struct agx_ptr texture = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_TEXTURE_LENGTH, 64);
1184 
1185    agx_pack(sampler.cpu, SAMPLER, cfg) {
1186       cfg.magnify_linear = true;
1187       cfg.minify_linear = false;
1188       cfg.mip_filter = AGX_MIP_FILTER_NONE;
1189       cfg.wrap_s = AGX_WRAP_CLAMP_TO_EDGE;
1190       cfg.wrap_t = AGX_WRAP_CLAMP_TO_EDGE;
1191       cfg.wrap_r = AGX_WRAP_CLAMP_TO_EDGE;
1192       cfg.pixel_coordinates = true;
1193       cfg.compare_func = AGX_COMPARE_FUNC_ALWAYS;
1194       cfg.unk_2 = 0;
1195       cfg.unk_3 = 0;
1196    }
1197 
1198    agx_pack(texture.cpu, TEXTURE, cfg) {
1199       struct agx_resource *rsrc = agx_resource(surf->texture);
1200       const struct util_format_description *desc =
1201          util_format_description(surf->format);
1202 
1203       cfg.layout = agx_translate_layout(rsrc->modifier);
1204       cfg.format = agx_pixel_format[surf->format].hw;
1205       cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);
1206       cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);
1207       cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);
1208       cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);
1209       cfg.width = surf->width;
1210       cfg.height = surf->height;
1211       cfg.levels = 1;
1212       cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
1213       cfg.address = rsrc->bo->ptr.gpu;
1214       cfg.unk_2 = false;
1215 
1216       cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?
1217          (rsrc->slices[0].line_stride - 16) :
1218          AGX_RT_STRIDE_TILED;
1219    }
1220 
1221    agx_pack(record, BIND_TEXTURE, cfg) {
1222       cfg.start = 0;
1223       cfg.count = 1;
1224       cfg.buffer = texture.gpu;
1225    }
1226 
1227    record += AGX_BIND_TEXTURE_LENGTH;
1228 
1229    agx_pack(record, BIND_SAMPLER, cfg) {
1230       cfg.start = 0;
1231       cfg.count = 1;
1232       cfg.buffer = sampler.gpu;
1233    }
1234 
1235    record += AGX_BIND_SAMPLER_LENGTH;
1236 
1237    /* TODO: Can we prepack this? */
1238    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1239       cfg.code = code;
1240       cfg.register_quadwords = 0;
1241       cfg.unk_3 = 0x8d;
1242       cfg.unk_2 = 0x0d;
1243       cfg.unk_2b = 4;
1244       cfg.unk_4 = 0;
1245       cfg.frag_unk = 0x880100;
1246       cfg.preshader_mode = 0; // XXX
1247    }
1248 
1249    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1250 
1251    /* End pipeline */
1252    memset(record, 0, 8);
1253    return ptr.gpu;
1254 }
1255 
1256 uint64_t
agx_build_store_pipeline(struct agx_context * ctx,uint32_t code,uint64_t render_target)1257 agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,
1258                          uint64_t render_target)
1259 {
1260    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1261                         (1 * AGX_BIND_TEXTURE_LENGTH) +
1262                         (1 * AGX_BIND_UNIFORM_LENGTH) +
1263                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1264                         64);
1265 
1266    uint8_t *record = ptr.cpu;
1267 
1268    agx_pack(record, BIND_TEXTURE, cfg) {
1269       cfg.start = 0;
1270       cfg.count = 1;
1271       cfg.buffer = render_target;
1272    }
1273 
1274    record += AGX_BIND_TEXTURE_LENGTH;
1275 
1276    uint32_t unk[] = { 0, ~0 };
1277 
1278    agx_pack(record, BIND_UNIFORM, cfg) {
1279       cfg.start_halfs = 4;
1280       cfg.size_halfs = 4;
1281       cfg.buffer = agx_pool_upload_aligned(&ctx->batch->pool, unk, sizeof(unk), 16);
1282    }
1283 
1284    record += AGX_BIND_UNIFORM_LENGTH;
1285 
1286    /* TODO: Can we prepack this? */
1287    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1288       cfg.code = code;
1289       cfg.register_quadwords = 1;
1290       cfg.unk_2 = 0xd;
1291       cfg.unk_3 = 0x8d;
1292       cfg.frag_unk = 0x880100;
1293       cfg.preshader_mode = 0; // XXX
1294    }
1295 
1296    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1297 
1298    /* End pipeline */
1299    memset(record, 0, 8);
1300    return ptr.gpu;
1301 }
1302 
1303 static uint64_t
demo_launch_fragment(struct agx_context * ctx,struct agx_pool * pool,uint32_t pipeline,uint32_t varyings,unsigned input_count)1304 demo_launch_fragment(struct agx_context *ctx, struct agx_pool *pool, uint32_t pipeline, uint32_t varyings, unsigned input_count)
1305 {
1306    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_BIND_PIPELINE_LENGTH, 64);
1307 
1308    agx_pack(t.cpu, BIND_PIPELINE, cfg) {
1309       cfg.tag = AGX_BIND_PIPELINE_FRAGMENT;
1310       cfg.sampler_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
1311       cfg.texture_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
1312       cfg.input_count = input_count;
1313       cfg.pipeline = pipeline;
1314       cfg.fs_varyings = varyings;
1315    };
1316 
1317    return t.gpu;
1318 }
1319 
1320 static uint64_t
demo_interpolation(struct agx_compiled_shader * fs,struct agx_pool * pool)1321 demo_interpolation(struct agx_compiled_shader *fs, struct agx_pool *pool)
1322 {
1323    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_INTERPOLATION_LENGTH, 64);
1324 
1325    agx_pack(t.cpu, INTERPOLATION, cfg) {
1326       cfg.varying_count = fs->info.varyings.nr_slots;
1327    };
1328 
1329    return t.gpu;
1330 }
1331 
1332 static uint64_t
demo_linkage(struct agx_compiled_shader * vs,struct agx_pool * pool)1333 demo_linkage(struct agx_compiled_shader *vs, struct agx_pool *pool)
1334 {
1335    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_LINKAGE_LENGTH, 64);
1336 
1337    agx_pack(t.cpu, LINKAGE, cfg) {
1338       cfg.varying_count = vs->info.varyings.nr_slots;
1339 
1340       // 0x2 for fragcoordz, 0x1 for varyings at all
1341       cfg.unk_1 = 0x210000 | (vs->info.writes_psiz ? 0x40000 : 0);
1342    };
1343 
1344    return t.gpu;
1345 }
1346 
1347 static uint64_t
demo_rasterizer(struct agx_context * ctx,struct agx_pool * pool,bool is_points)1348 demo_rasterizer(struct agx_context *ctx, struct agx_pool *pool, bool is_points)
1349 {
1350    struct agx_rasterizer *rast = ctx->rast;
1351    struct agx_rasterizer_packed out;
1352 
1353    agx_pack(&out, RASTERIZER, cfg) {
1354       bool back_stencil = ctx->zs.base.stencil[1].enabled;
1355       cfg.front.stencil_reference = ctx->stencil_ref.ref_value[0];
1356       cfg.back.stencil_reference = back_stencil ?
1357          ctx->stencil_ref.ref_value[1] :
1358          cfg.front.stencil_reference;
1359 
1360       cfg.front.line_width = cfg.back.line_width = rast->line_width;
1361       cfg.front.polygon_mode = cfg.back.polygon_mode = AGX_POLYGON_MODE_FILL;
1362 
1363       cfg.unk_fill_lines = is_points; /* XXX: what is this? */
1364 
1365       /* Always enable scissoring so we may scissor to the viewport (TODO:
1366        * optimize this out if the viewport is the default and the app does not
1367        * use the scissor test) */
1368       cfg.scissor_enable = true;
1369    };
1370 
1371    /* Words 2-3: front */
1372    out.opaque[2] |= ctx->zs.front.opaque[0];
1373    out.opaque[3] |= ctx->zs.front.opaque[1];
1374 
1375    /* Words 4-5: back */
1376    out.opaque[4] |= ctx->zs.back.opaque[0];
1377    out.opaque[5] |= ctx->zs.back.opaque[1];
1378 
1379    return agx_pool_upload_aligned(pool, &out, sizeof(out), 64);
1380 }
1381 
1382 static uint64_t
demo_unk11(struct agx_pool * pool,bool prim_lines,bool prim_points,bool reads_tib)1383 demo_unk11(struct agx_pool *pool, bool prim_lines, bool prim_points, bool reads_tib)
1384 {
1385 #define UNK11_FILL_MODE_LINES_1 (1 << 26)
1386 
1387 #define UNK11_FILL_MODE_LINES_2 (0x5004 << 16)
1388 #define UNK11_LINES (0x10000000)
1389 #define UNK11_POINTS (0x40000000)
1390 
1391 #define UNK11_READS_TIB (0x20000000)
1392 
1393    uint32_t unk[] = {
1394       0x200004a,
1395       0x200 | ((prim_lines || prim_points) ? UNK11_FILL_MODE_LINES_1 : 0) | (reads_tib ? UNK11_READS_TIB : 0),
1396       0x7e00000 | (prim_lines ? UNK11_LINES : 0) | (prim_points ? UNK11_POINTS : 0),
1397       0x7e00000 | (prim_lines ? UNK11_LINES : 0) | (prim_points ? UNK11_POINTS : 0),
1398 
1399       0x1ffff
1400    };
1401 
1402    return agx_pool_upload(pool, unk, sizeof(unk));
1403 }
1404 
1405 static uint64_t
demo_unk12(struct agx_pool * pool)1406 demo_unk12(struct agx_pool *pool)
1407 {
1408    uint32_t unk[] = {
1409       0x410000,
1410       0x1e3ce508,
1411       0xa0
1412    };
1413 
1414    return agx_pool_upload(pool, unk, sizeof(unk));
1415 }
1416 
1417 static uint64_t
agx_set_scissor_index(struct agx_pool * pool,unsigned index)1418 agx_set_scissor_index(struct agx_pool *pool, unsigned index)
1419 {
1420    struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_SET_SCISSOR_LENGTH, 64);
1421 
1422    agx_pack(T.cpu, SET_SCISSOR, cfg) {
1423       cfg.index = index;
1424    };
1425 
1426    return T.gpu;
1427 }
1428 
1429 static void
agx_push_record(uint8_t ** out,unsigned size_words,uint64_t ptr)1430 agx_push_record(uint8_t **out, unsigned size_words, uint64_t ptr)
1431 {
1432    assert(ptr < (1ull << 40));
1433    assert(size_words < (1ull << 24));
1434 
1435    uint64_t value = (size_words | (ptr << 24));
1436    memcpy(*out, &value, sizeof(value));
1437    *out += sizeof(value);
1438 }
1439 
1440 static uint8_t *
agx_encode_state(struct agx_context * ctx,uint8_t * out,uint32_t pipeline_vertex,uint32_t pipeline_fragment,uint32_t varyings,bool is_lines,bool is_points)1441 agx_encode_state(struct agx_context *ctx, uint8_t *out,
1442                  uint32_t pipeline_vertex, uint32_t pipeline_fragment, uint32_t varyings,
1443                  bool is_lines, bool is_points)
1444 {
1445    agx_pack(out, BIND_PIPELINE, cfg) {
1446       cfg.tag = AGX_BIND_PIPELINE_VERTEX;
1447       cfg.pipeline = pipeline_vertex;
1448       cfg.vs_output_count_1 = ctx->vs->info.varyings.nr_slots;
1449       cfg.vs_output_count_2 = ctx->vs->info.varyings.nr_slots;
1450       cfg.sampler_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
1451       cfg.texture_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
1452    }
1453 
1454    /* yes, it's really 17 bytes */
1455    out += AGX_BIND_PIPELINE_LENGTH;
1456    *(out++) = 0x0;
1457 
1458    struct agx_pool *pool = &ctx->batch->pool;
1459    struct agx_ptr zero = agx_pool_alloc_aligned(pool, 16, 256);
1460    memset(zero.cpu, 0, 16);
1461 
1462    bool reads_tib = ctx->fs->info.reads_tib;
1463 
1464    agx_push_record(&out, 0, zero.gpu);
1465    agx_push_record(&out, 5, demo_interpolation(ctx->fs, pool));
1466    agx_push_record(&out, 5, demo_launch_fragment(ctx, pool, pipeline_fragment, varyings, ctx->fs->info.varyings.nr_descs));
1467    agx_push_record(&out, 4, demo_linkage(ctx->vs, pool));
1468    agx_push_record(&out, 7, demo_rasterizer(ctx, pool, is_points));
1469    agx_push_record(&out, 5, demo_unk11(pool, is_lines, is_points, reads_tib));
1470 
1471    if (ctx->dirty & (AGX_DIRTY_VIEWPORT | AGX_DIRTY_SCISSOR)) {
1472       struct agx_viewport_scissor vps = agx_upload_viewport_scissor(pool,
1473             ctx->batch, &ctx->viewport,
1474             ctx->rast->base.scissor ? &ctx->scissor : NULL);
1475 
1476       agx_push_record(&out, 10, vps.viewport);
1477       agx_push_record(&out, 2, agx_set_scissor_index(pool, vps.scissor));
1478    }
1479 
1480    agx_push_record(&out, 3, demo_unk12(pool));
1481    agx_push_record(&out, 2, agx_pool_upload(pool, ctx->rast->cull, sizeof(ctx->rast->cull)));
1482 
1483    return (out - 1); // XXX: alignment fixup, or something
1484 }
1485 
1486 static enum agx_primitive
agx_primitive_for_pipe(enum pipe_prim_type mode)1487 agx_primitive_for_pipe(enum pipe_prim_type mode)
1488 {
1489    switch (mode) {
1490    case PIPE_PRIM_POINTS: return AGX_PRIMITIVE_POINTS;
1491    case PIPE_PRIM_LINES: return AGX_PRIMITIVE_LINES;
1492    case PIPE_PRIM_LINE_STRIP: return AGX_PRIMITIVE_LINE_STRIP;
1493    case PIPE_PRIM_LINE_LOOP: return AGX_PRIMITIVE_LINE_LOOP;
1494    case PIPE_PRIM_TRIANGLES: return AGX_PRIMITIVE_TRIANGLES;
1495    case PIPE_PRIM_TRIANGLE_STRIP: return AGX_PRIMITIVE_TRIANGLE_STRIP;
1496    case PIPE_PRIM_TRIANGLE_FAN: return AGX_PRIMITIVE_TRIANGLE_FAN;
1497    case PIPE_PRIM_QUADS: return AGX_PRIMITIVE_QUADS;
1498    case PIPE_PRIM_QUAD_STRIP: return AGX_PRIMITIVE_QUAD_STRIP;
1499    default: unreachable("todo: other primitive types");
1500    }
1501 }
1502 
1503 static uint64_t
agx_index_buffer_ptr(struct agx_batch * batch,const struct pipe_draw_start_count_bias * draw,const struct pipe_draw_info * info)1504 agx_index_buffer_ptr(struct agx_batch *batch,
1505                      const struct pipe_draw_start_count_bias *draw,
1506                      const struct pipe_draw_info *info)
1507 {
1508    off_t offset = draw->start * info->index_size;
1509 
1510    if (!info->has_user_indices) {
1511       struct agx_bo *bo = agx_resource(info->index.resource)->bo;
1512       agx_batch_add_bo(batch, bo);
1513 
1514       return bo->ptr.gpu + offset;
1515    } else {
1516       return agx_pool_upload_aligned(&batch->pool,
1517                                      ((uint8_t *) info->index.user) + offset,
1518                                      draw->count * info->index_size, 64);
1519    }
1520 }
1521 
1522 static bool
agx_scissor_culls_everything(struct agx_context * ctx)1523 agx_scissor_culls_everything(struct agx_context *ctx)
1524 {
1525         const struct pipe_scissor_state ss = ctx->scissor;
1526 
1527         return ctx->rast->base.scissor &&
1528 		((ss.minx == ss.maxx) || (ss.miny == ss.maxy));
1529 }
1530 
1531 static void
agx_draw_vbo(struct pipe_context * pctx,const struct pipe_draw_info * info,unsigned drawid_offset,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draws,unsigned num_draws)1532 agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
1533              unsigned drawid_offset,
1534              const struct pipe_draw_indirect_info *indirect,
1535              const struct pipe_draw_start_count_bias *draws,
1536              unsigned num_draws)
1537 {
1538    if (num_draws > 1) {
1539       util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);
1540       return;
1541    }
1542 
1543    if (info->index_size && draws->index_bias)
1544       unreachable("todo: index bias");
1545 
1546    struct agx_context *ctx = agx_context(pctx);
1547    struct agx_batch *batch = ctx->batch;
1548 
1549    if (agx_scissor_culls_everything(ctx))
1550 	   return;
1551 
1552    /* TODO: masks */
1553    ctx->batch->draw |= ~0;
1554 
1555    /* TODO: Dirty track */
1556    agx_update_vs(ctx);
1557    agx_update_fs(ctx);
1558 
1559    agx_batch_add_bo(batch, ctx->vs->bo);
1560    agx_batch_add_bo(batch, ctx->fs->bo);
1561 
1562    bool is_lines =
1563       (info->mode == PIPE_PRIM_LINES) ||
1564       (info->mode == PIPE_PRIM_LINE_STRIP) ||
1565       (info->mode == PIPE_PRIM_LINE_LOOP);
1566 
1567    uint8_t *out = agx_encode_state(ctx, batch->encoder_current,
1568                                    agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX),
1569                                    agx_build_pipeline(ctx, ctx->fs, PIPE_SHADER_FRAGMENT),
1570                                    ctx->fs->varyings, is_lines, info->mode == PIPE_PRIM_POINTS);
1571 
1572    enum agx_primitive prim = agx_primitive_for_pipe(info->mode);
1573    unsigned idx_size = info->index_size;
1574 
1575    if (idx_size) {
1576       uint64_t ib = agx_index_buffer_ptr(batch, draws, info);
1577 
1578       /* Index sizes are encoded logarithmically */
1579       STATIC_ASSERT(__builtin_ctz(1) == AGX_INDEX_SIZE_U8);
1580       STATIC_ASSERT(__builtin_ctz(2) == AGX_INDEX_SIZE_U16);
1581       STATIC_ASSERT(__builtin_ctz(4) == AGX_INDEX_SIZE_U32);
1582       assert((idx_size == 1) || (idx_size == 2) || (idx_size == 4));
1583 
1584       agx_pack(out, INDEXED_DRAW, cfg) {
1585          cfg.restart_index = info->restart_index;
1586          cfg.unk_2a = (ib >> 32);
1587          cfg.primitive = prim;
1588          cfg.restart_enable = info->primitive_restart;
1589          cfg.index_size = __builtin_ctz(idx_size);
1590          cfg.index_buffer_offset = (ib & BITFIELD_MASK(32));
1591          cfg.index_buffer_size = ALIGN_POT(draws->count * idx_size, 4);
1592          cfg.index_count = draws->count;
1593          cfg.instance_count = info->instance_count;
1594          cfg.base_vertex = draws->index_bias;
1595       };
1596 
1597       out += AGX_INDEXED_DRAW_LENGTH;
1598    } else {
1599       agx_pack(out, DRAW, cfg) {
1600          cfg.primitive = prim;
1601          cfg.vertex_start = draws->start;
1602          cfg.vertex_count = draws->count;
1603          cfg.instance_count = info->instance_count;
1604       };
1605 
1606       out += AGX_DRAW_LENGTH;
1607    }
1608 
1609    batch->encoder_current = out;
1610    ctx->dirty = 0;
1611 }
1612 
1613 void agx_init_state_functions(struct pipe_context *ctx);
1614 
1615 void
agx_init_state_functions(struct pipe_context * ctx)1616 agx_init_state_functions(struct pipe_context *ctx)
1617 {
1618    ctx->create_blend_state = agx_create_blend_state;
1619    ctx->create_depth_stencil_alpha_state = agx_create_zsa_state;
1620    ctx->create_fs_state = agx_create_shader_state;
1621    ctx->create_rasterizer_state = agx_create_rs_state;
1622    ctx->create_sampler_state = agx_create_sampler_state;
1623    ctx->create_sampler_view = agx_create_sampler_view;
1624    ctx->create_surface = agx_create_surface;
1625    ctx->create_vertex_elements_state = agx_create_vertex_elements;
1626    ctx->create_vs_state = agx_create_shader_state;
1627    ctx->bind_blend_state = agx_bind_blend_state;
1628    ctx->bind_depth_stencil_alpha_state = agx_bind_zsa_state;
1629    ctx->bind_sampler_states = agx_bind_sampler_states;
1630    ctx->bind_fs_state = agx_bind_shader_state;
1631    ctx->bind_rasterizer_state = agx_bind_rasterizer_state;
1632    ctx->bind_vertex_elements_state = agx_bind_vertex_elements_state;
1633    ctx->bind_vs_state = agx_bind_shader_state;
1634    ctx->delete_blend_state = agx_delete_state;
1635    ctx->delete_depth_stencil_alpha_state = agx_delete_state;
1636    ctx->delete_fs_state = agx_delete_shader_state;
1637    ctx->delete_rasterizer_state = agx_delete_state;
1638    ctx->delete_sampler_state = agx_delete_sampler_state;
1639    ctx->delete_vertex_elements_state = agx_delete_state;
1640    ctx->delete_vs_state = agx_delete_state;
1641    ctx->set_blend_color = agx_set_blend_color;
1642    ctx->set_clip_state = agx_set_clip_state;
1643    ctx->set_constant_buffer = agx_set_constant_buffer;
1644    ctx->set_sampler_views = agx_set_sampler_views;
1645    ctx->set_framebuffer_state = agx_set_framebuffer_state;
1646    ctx->set_polygon_stipple = agx_set_polygon_stipple;
1647    ctx->set_sample_mask = agx_set_sample_mask;
1648    ctx->set_scissor_states = agx_set_scissor_states;
1649    ctx->set_stencil_ref = agx_set_stencil_ref;
1650    ctx->set_vertex_buffers = agx_set_vertex_buffers;
1651    ctx->set_viewport_states = agx_set_viewport_states;
1652    ctx->sampler_view_destroy = agx_sampler_view_destroy;
1653    ctx->surface_destroy = agx_surface_destroy;
1654    ctx->draw_vbo = agx_draw_vbo;
1655    ctx->create_stream_output_target = agx_create_stream_output_target;
1656    ctx->stream_output_target_destroy = agx_stream_output_target_destroy;
1657    ctx->set_stream_output_targets = agx_set_stream_output_targets;
1658 }
1659