• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 or depth bias state has changed, since scissor/depth bias
292     * enable is part of the rasterizer state but everything else needed for
293     * scissors and depth bias is part of the scissor/depth bias arrays */
294    bool scissor_zbias_changed = (cso == NULL) || (ctx->rast == NULL) ||
295       (ctx->rast->base.scissor != so->base.scissor) ||
296       (ctx->rast->base.offset_tri != so->base.offset_tri);
297 
298    ctx->rast = so;
299 
300    if (scissor_zbias_changed)
301       ctx->dirty |= AGX_DIRTY_SCISSOR_ZBIAS;
302 }
303 
304 static enum agx_wrap
agx_wrap_from_pipe(enum pipe_tex_wrap in)305 agx_wrap_from_pipe(enum pipe_tex_wrap in)
306 {
307    switch (in) {
308    case PIPE_TEX_WRAP_REPEAT: return AGX_WRAP_REPEAT;
309    case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return AGX_WRAP_CLAMP_TO_EDGE;
310    case PIPE_TEX_WRAP_MIRROR_REPEAT: return AGX_WRAP_MIRRORED_REPEAT;
311    case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return AGX_WRAP_CLAMP_TO_BORDER;
312    default: unreachable("todo: more wrap modes");
313    }
314 }
315 
316 static enum agx_mip_filter
agx_mip_filter_from_pipe(enum pipe_tex_mipfilter in)317 agx_mip_filter_from_pipe(enum pipe_tex_mipfilter in)
318 {
319    switch (in) {
320    case PIPE_TEX_MIPFILTER_NEAREST: return AGX_MIP_FILTER_NEAREST;
321    case PIPE_TEX_MIPFILTER_LINEAR: return AGX_MIP_FILTER_LINEAR;
322    case PIPE_TEX_MIPFILTER_NONE: return AGX_MIP_FILTER_NONE;
323    }
324 
325    unreachable("Invalid mip filter");
326 }
327 
328 static const enum agx_compare_func agx_compare_funcs[PIPE_FUNC_ALWAYS + 1] = {
329    [PIPE_FUNC_NEVER] = AGX_COMPARE_FUNC_NEVER,
330    [PIPE_FUNC_LESS] = AGX_COMPARE_FUNC_LESS,
331    [PIPE_FUNC_EQUAL] = AGX_COMPARE_FUNC_EQUAL,
332    [PIPE_FUNC_LEQUAL] = AGX_COMPARE_FUNC_LEQUAL,
333    [PIPE_FUNC_GREATER] = AGX_COMPARE_FUNC_GREATER,
334    [PIPE_FUNC_NOTEQUAL] = AGX_COMPARE_FUNC_NOT_EQUAL,
335    [PIPE_FUNC_GEQUAL] = AGX_COMPARE_FUNC_GEQUAL,
336    [PIPE_FUNC_ALWAYS] = AGX_COMPARE_FUNC_ALWAYS,
337 };
338 
339 static void *
agx_create_sampler_state(struct pipe_context * pctx,const struct pipe_sampler_state * state)340 agx_create_sampler_state(struct pipe_context *pctx,
341                          const struct pipe_sampler_state *state)
342 {
343    struct agx_device *dev = agx_device(pctx->screen);
344    struct agx_bo *bo = agx_bo_create(dev, AGX_SAMPLER_LENGTH,
345                                      AGX_MEMORY_TYPE_FRAMEBUFFER);
346 
347    assert(state->lod_bias == 0 && "todo: lod bias");
348 
349    agx_pack(bo->ptr.cpu, SAMPLER, cfg) {
350       cfg.minimum_lod = state->min_lod;
351       cfg.maximum_lod = state->max_lod;
352       cfg.magnify_linear = (state->mag_img_filter == PIPE_TEX_FILTER_LINEAR);
353       cfg.minify_linear = (state->min_img_filter == PIPE_TEX_FILTER_LINEAR);
354       cfg.mip_filter = agx_mip_filter_from_pipe(state->min_mip_filter);
355       cfg.wrap_s = agx_wrap_from_pipe(state->wrap_s);
356       cfg.wrap_t = agx_wrap_from_pipe(state->wrap_t);
357       cfg.wrap_r = agx_wrap_from_pipe(state->wrap_r);
358       cfg.pixel_coordinates = !state->normalized_coords;
359       cfg.compare_func = agx_compare_funcs[state->compare_func];
360    }
361 
362    struct agx_sampler_state *so = CALLOC_STRUCT(agx_sampler_state);
363    so->base = *state;
364    so->desc = bo;
365 
366    return so;
367 }
368 
369 static void
agx_delete_sampler_state(struct pipe_context * ctx,void * state)370 agx_delete_sampler_state(struct pipe_context *ctx, void *state)
371 {
372    struct agx_sampler_state *so = state;
373    agx_bo_unreference(so->desc);
374 }
375 
376 static void
agx_bind_sampler_states(struct pipe_context * pctx,enum pipe_shader_type shader,unsigned start,unsigned count,void ** states)377 agx_bind_sampler_states(struct pipe_context *pctx,
378                         enum pipe_shader_type shader,
379                         unsigned start, unsigned count,
380                         void **states)
381 {
382    struct agx_context *ctx = agx_context(pctx);
383 
384    ctx->stage[shader].sampler_count = states ? count : 0;
385 
386    memcpy(&ctx->stage[shader].samplers[start], states,
387           sizeof(struct agx_sampler_state *) * count);
388 }
389 
390 /* Channels agree for RGBA but are weird for force 0/1 */
391 
392 static enum agx_channel
agx_channel_from_pipe(enum pipe_swizzle in)393 agx_channel_from_pipe(enum pipe_swizzle in)
394 {
395    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_X == AGX_CHANNEL_R);
396    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Y == AGX_CHANNEL_G);
397    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_Z == AGX_CHANNEL_B);
398    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_W == AGX_CHANNEL_A);
399    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_0 & 0x4);
400    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_1 & 0x4);
401    STATIC_ASSERT((enum agx_channel) PIPE_SWIZZLE_NONE & 0x4);
402 
403    if ((in & 0x4) == 0)
404       return (enum agx_channel) in;
405    else if (in == PIPE_SWIZZLE_1)
406       return AGX_CHANNEL_1;
407    else
408       return AGX_CHANNEL_0;
409 }
410 
411 static enum agx_layout
agx_translate_layout(uint64_t modifier)412 agx_translate_layout(uint64_t modifier)
413 {
414    switch (modifier) {
415    case DRM_FORMAT_MOD_APPLE_64X64_MORTON_ORDER:
416       return AGX_LAYOUT_TILED_64X64;
417    case DRM_FORMAT_MOD_LINEAR:
418       return AGX_LAYOUT_LINEAR;
419    default:
420       unreachable("Invalid modifier");
421    }
422 }
423 
424 static enum agx_texture_dimension
agx_translate_texture_dimension(enum pipe_texture_target dim)425 agx_translate_texture_dimension(enum pipe_texture_target dim)
426 {
427    switch (dim) {
428    case PIPE_TEXTURE_RECT:
429    case PIPE_TEXTURE_2D: return AGX_TEXTURE_DIMENSION_2D;
430    case PIPE_TEXTURE_2D_ARRAY: return AGX_TEXTURE_DIMENSION_2D_ARRAY;
431    case PIPE_TEXTURE_3D: return AGX_TEXTURE_DIMENSION_3D;
432    case PIPE_TEXTURE_CUBE: return AGX_TEXTURE_DIMENSION_CUBE;
433    default: unreachable("Unsupported texture dimension");
434    }
435 }
436 
437 static struct pipe_sampler_view *
agx_create_sampler_view(struct pipe_context * pctx,struct pipe_resource * texture,const struct pipe_sampler_view * state)438 agx_create_sampler_view(struct pipe_context *pctx,
439                         struct pipe_resource *texture,
440                         const struct pipe_sampler_view *state)
441 {
442    struct agx_device *dev = agx_device(pctx->screen);
443    struct agx_resource *rsrc = agx_resource(texture);
444    struct agx_sampler_view *so = CALLOC_STRUCT(agx_sampler_view);
445 
446    if (!so)
447       return NULL;
448 
449    /* We prepare the descriptor at CSO create time */
450    so->desc = agx_bo_create(dev, AGX_TEXTURE_LENGTH,
451                             AGX_MEMORY_TYPE_FRAMEBUFFER);
452 
453    const struct util_format_description *desc =
454       util_format_description(state->format);
455 
456    /* We only have a single swizzle for the user swizzle and the format fixup,
457     * so compose them now. */
458    uint8_t out_swizzle[4];
459    uint8_t view_swizzle[4] = {
460       state->swizzle_r, state->swizzle_g,
461       state->swizzle_b, state->swizzle_a
462    };
463 
464    util_format_compose_swizzles(desc->swizzle, view_swizzle, out_swizzle);
465 
466    unsigned level = state->u.tex.first_level;
467    assert(state->u.tex.first_layer == 0);
468 
469    /* Must tile array textures */
470    assert((rsrc->modifier != DRM_FORMAT_MOD_LINEAR) ||
471           (state->u.tex.last_layer == state->u.tex.first_layer));
472 
473    /* Pack the descriptor into GPU memory */
474    agx_pack(so->desc->ptr.cpu, TEXTURE, cfg) {
475       cfg.dimension = agx_translate_texture_dimension(state->target);
476       cfg.layout = agx_translate_layout(rsrc->modifier);
477       cfg.format = agx_pixel_format[state->format].hw;
478       cfg.swizzle_r = agx_channel_from_pipe(out_swizzle[0]);
479       cfg.swizzle_g = agx_channel_from_pipe(out_swizzle[1]);
480       cfg.swizzle_b = agx_channel_from_pipe(out_swizzle[2]);
481       cfg.swizzle_a = agx_channel_from_pipe(out_swizzle[3]);
482       cfg.width = u_minify(texture->width0, level);
483       cfg.height = u_minify(texture->height0, level);
484       cfg.levels = state->u.tex.last_level - level + 1;
485       cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
486       cfg.address = agx_map_texture_gpu(rsrc, level, state->u.tex.first_layer);
487       cfg.unk_mipmapped = rsrc->mipmapped;
488       cfg.unk_2 = false;
489 
490       if (state->target == PIPE_TEXTURE_3D)
491          cfg.depth = u_minify(texture->depth0, level);
492       else
493          cfg.depth = state->u.tex.last_layer - state->u.tex.first_layer + 1;
494 
495       cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?
496          (rsrc->slices[level].line_stride - 16) :
497          AGX_RT_STRIDE_TILED;
498    }
499 
500    /* Initialize base object */
501    so->base = *state;
502    so->base.texture = NULL;
503    pipe_resource_reference(&so->base.texture, texture);
504    pipe_reference_init(&so->base.reference, 1);
505    so->base.context = pctx;
506    return &so->base;
507 }
508 
509 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)510 agx_set_sampler_views(struct pipe_context *pctx,
511                       enum pipe_shader_type shader,
512                       unsigned start, unsigned count,
513                       unsigned unbind_num_trailing_slots,
514                       bool take_ownership,
515                       struct pipe_sampler_view **views)
516 {
517    struct agx_context *ctx = agx_context(pctx);
518    unsigned new_nr = 0;
519    unsigned i;
520 
521    assert(start == 0);
522 
523    if (!views)
524       count = 0;
525 
526    for (i = 0; i < count; ++i) {
527       if (views[i])
528          new_nr = i + 1;
529 
530       if (take_ownership) {
531          pipe_sampler_view_reference((struct pipe_sampler_view **)
532                                      &ctx->stage[shader].textures[i], NULL);
533          ctx->stage[shader].textures[i] = (struct agx_sampler_view *)views[i];
534       } else {
535          pipe_sampler_view_reference((struct pipe_sampler_view **)
536                                      &ctx->stage[shader].textures[i], views[i]);
537       }
538    }
539 
540    for (; i < ctx->stage[shader].texture_count; i++) {
541       pipe_sampler_view_reference((struct pipe_sampler_view **)
542                                   &ctx->stage[shader].textures[i], NULL);
543    }
544    ctx->stage[shader].texture_count = new_nr;
545 }
546 
547 static void
agx_sampler_view_destroy(struct pipe_context * ctx,struct pipe_sampler_view * pview)548 agx_sampler_view_destroy(struct pipe_context *ctx,
549                          struct pipe_sampler_view *pview)
550 {
551    struct agx_sampler_view *view = (struct agx_sampler_view *) pview;
552    pipe_resource_reference(&view->base.texture, NULL);
553    agx_bo_unreference(view->desc);
554    FREE(view);
555 }
556 
557 static struct pipe_surface *
agx_create_surface(struct pipe_context * ctx,struct pipe_resource * texture,const struct pipe_surface * surf_tmpl)558 agx_create_surface(struct pipe_context *ctx,
559                    struct pipe_resource *texture,
560                    const struct pipe_surface *surf_tmpl)
561 {
562    struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
563 
564    if (!surface)
565       return NULL;
566    pipe_reference_init(&surface->reference, 1);
567    pipe_resource_reference(&surface->texture, texture);
568    surface->context = ctx;
569    surface->format = surf_tmpl->format;
570    surface->width = texture->width0;
571    surface->height = texture->height0;
572    surface->texture = texture;
573    surface->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
574    surface->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
575    surface->u.tex.level = surf_tmpl->u.tex.level;
576 
577    return surface;
578 }
579 
580 static void
agx_set_clip_state(struct pipe_context * ctx,const struct pipe_clip_state * state)581 agx_set_clip_state(struct pipe_context *ctx,
582                    const struct pipe_clip_state *state)
583 {
584 }
585 
586 static void
agx_set_polygon_stipple(struct pipe_context * ctx,const struct pipe_poly_stipple * state)587 agx_set_polygon_stipple(struct pipe_context *ctx,
588                         const struct pipe_poly_stipple *state)
589 {
590 }
591 
592 static void
agx_set_sample_mask(struct pipe_context * pipe,unsigned sample_mask)593 agx_set_sample_mask(struct pipe_context *pipe, unsigned sample_mask)
594 {
595    struct agx_context *ctx = agx_context(pipe);
596    ctx->sample_mask = sample_mask;
597 }
598 
599 static void
agx_set_scissor_states(struct pipe_context * pctx,unsigned start_slot,unsigned num_scissors,const struct pipe_scissor_state * scissor)600 agx_set_scissor_states(struct pipe_context *pctx,
601                        unsigned start_slot,
602                        unsigned num_scissors,
603                        const struct pipe_scissor_state *scissor)
604 {
605    struct agx_context *ctx = agx_context(pctx);
606 
607    assert(start_slot == 0 && "no geometry shaders");
608    assert(num_scissors == 1 && "no geometry shaders");
609 
610    ctx->scissor = *scissor;
611    ctx->dirty |= AGX_DIRTY_SCISSOR_ZBIAS;
612 }
613 
614 static void
agx_set_stencil_ref(struct pipe_context * pctx,const struct pipe_stencil_ref state)615 agx_set_stencil_ref(struct pipe_context *pctx,
616                     const struct pipe_stencil_ref state)
617 {
618    struct agx_context *ctx = agx_context(pctx);
619    ctx->stencil_ref = state;
620 }
621 
622 static void
agx_set_viewport_states(struct pipe_context * pctx,unsigned start_slot,unsigned num_viewports,const struct pipe_viewport_state * vp)623 agx_set_viewport_states(struct pipe_context *pctx,
624                         unsigned start_slot,
625                         unsigned num_viewports,
626                         const struct pipe_viewport_state *vp)
627 {
628    struct agx_context *ctx = agx_context(pctx);
629 
630    assert(start_slot == 0 && "no geometry shaders");
631    assert(num_viewports == 1 && "no geometry shaders");
632 
633    ctx->dirty |= AGX_DIRTY_VIEWPORT;
634    ctx->viewport = *vp;
635 }
636 
637 struct agx_viewport_scissor {
638    uint64_t viewport;
639    unsigned scissor;
640 };
641 
642 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)643 agx_upload_viewport_scissor(struct agx_pool *pool,
644                             struct agx_batch *batch,
645                             const struct pipe_viewport_state *vp,
646                             const struct pipe_scissor_state *ss)
647 {
648    struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_VIEWPORT_LENGTH, 64);
649 
650    float trans_x = vp->translate[0], trans_y = vp->translate[1];
651    float abs_scale_x = fabsf(vp->scale[0]), abs_scale_y = fabsf(vp->scale[1]);
652 
653    /* Calculate the extent of the viewport. Note if a particular dimension of
654     * the viewport is an odd number of pixels, both the translate and the scale
655     * will have a fractional part of 0.5, so adding and subtracting them yields
656     * an integer. Therefore we don't need to round explicitly */
657    unsigned minx = CLAMP((int) (trans_x - abs_scale_x), 0, batch->width);
658    unsigned miny = CLAMP((int) (trans_y - abs_scale_y), 0, batch->height);
659    unsigned maxx = CLAMP((int) (trans_x + abs_scale_x), 0, batch->width);
660    unsigned maxy = CLAMP((int) (trans_y + abs_scale_y), 0, batch->height);
661 
662    if (ss) {
663       minx = MAX2(ss->minx, minx);
664       miny = MAX2(ss->miny, miny);
665       maxx = MIN2(ss->maxx, maxx);
666       maxy = MIN2(ss->maxy, maxy);
667    }
668 
669    assert(maxx > minx && maxy > miny);
670 
671    float minz, maxz;
672    util_viewport_zmin_zmax(vp, false, &minz, &maxz);
673 
674    agx_pack(T.cpu, VIEWPORT, cfg) {
675       cfg.min_tile_x = minx / 32;
676       cfg.min_tile_y = miny / 32;
677       cfg.max_tile_x = DIV_ROUND_UP(maxx, 32);
678       cfg.max_tile_y = DIV_ROUND_UP(maxy, 32);
679       cfg.clip_tile = true;
680 
681       cfg.translate_x = vp->translate[0];
682       cfg.translate_y = vp->translate[1];
683       cfg.scale_x = vp->scale[0];
684       cfg.scale_y = vp->scale[1];
685 
686       /* Assumes [0, 1] clip coordinates. If half-z is not in use, lower_half_z
687        * is called to ensure this works. */
688       cfg.translate_z = minz;
689       cfg.scale_z = maxz - minz;
690    };
691 
692    /* Allocate a new scissor descriptor */
693    struct agx_scissor_packed *ptr = batch->scissor.bo->ptr.cpu;
694    unsigned index = (batch->scissor.count++);
695 
696    agx_pack(ptr + index, SCISSOR, cfg) {
697       cfg.min_x = minx;
698       cfg.min_y = miny;
699       cfg.min_z = minz;
700       cfg.max_x = maxx;
701       cfg.max_y = maxy;
702       cfg.max_z = maxz;
703    }
704 
705    return (struct agx_viewport_scissor) {
706       .viewport = T.gpu,
707       .scissor = index
708    };
709 }
710 
711 static uint16_t
agx_upload_depth_bias(struct agx_batch * batch,const struct pipe_rasterizer_state * rast)712 agx_upload_depth_bias(struct agx_batch *batch,
713                       const struct pipe_rasterizer_state *rast)
714 {
715    struct agx_depth_bias_packed *ptr = batch->depth_bias.bo->ptr.cpu;
716    unsigned index = (batch->depth_bias.count++);
717 
718    agx_pack(ptr + index, DEPTH_BIAS, cfg) {
719       cfg.depth_bias    = rast->offset_units;
720       cfg.slope_scale   = rast->offset_scale;
721       cfg.clamp         = rast->offset_clamp;
722    }
723 
724    return index;
725 }
726 
727 /* A framebuffer state can be reused across batches, so it doesn't make sense
728  * to add surfaces to the BO list here. Instead we added them when flushing.
729  */
730 
731 static void
agx_set_framebuffer_state(struct pipe_context * pctx,const struct pipe_framebuffer_state * state)732 agx_set_framebuffer_state(struct pipe_context *pctx,
733                           const struct pipe_framebuffer_state *state)
734 {
735    struct agx_context *ctx = agx_context(pctx);
736 
737    if (!state)
738       return;
739 
740    /* XXX: eliminate this flush with batch tracking logic */
741    pctx->flush(pctx, NULL, 0);
742 
743    util_copy_framebuffer_state(&ctx->framebuffer, state);
744    ctx->batch->width = state->width;
745    ctx->batch->height = state->height;
746    ctx->batch->nr_cbufs = state->nr_cbufs;
747    ctx->batch->cbufs[0] = state->cbufs[0];
748    ctx->batch->zsbuf = state->zsbuf;
749    ctx->dirty = ~0;
750 
751    for (unsigned i = 0; i < state->nr_cbufs; ++i) {
752       struct pipe_surface *surf = state->cbufs[i];
753       struct agx_resource *tex = agx_resource(surf->texture);
754       const struct util_format_description *desc =
755          util_format_description(surf->format);
756       unsigned level = surf->u.tex.level;
757       unsigned layer = surf->u.tex.first_layer;
758 
759       assert(surf->u.tex.last_layer == layer);
760 
761       agx_pack(ctx->render_target[i], RENDER_TARGET, cfg) {
762          cfg.layout = agx_translate_layout(tex->modifier);
763          cfg.format = agx_pixel_format[surf->format].hw;
764          cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);
765          cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);
766          cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);
767          cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);
768          cfg.width = state->width;
769          cfg.height = state->height;
770          cfg.level = surf->u.tex.level;
771          cfg.buffer = agx_map_texture_gpu(tex, 0, layer);
772 
773          if (tex->mipmapped)
774             cfg.unk_55 = 0x8;
775 
776          cfg.stride = (tex->modifier == DRM_FORMAT_MOD_LINEAR) ?
777             (tex->slices[level].line_stride - 4) :
778             tex->mipmapped ? AGX_RT_STRIDE_TILED_MIPMAPPED :
779             AGX_RT_STRIDE_TILED;
780       };
781    }
782 }
783 
784 /* Likewise constant buffers, textures, and samplers are handled in a common
785  * per-draw path, with dirty tracking to reduce the costs involved.
786  */
787 
788 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)789 agx_set_constant_buffer(struct pipe_context *pctx,
790                         enum pipe_shader_type shader, uint index,
791                         bool take_ownership,
792                         const struct pipe_constant_buffer *cb)
793 {
794    struct agx_context *ctx = agx_context(pctx);
795    struct agx_stage *s = &ctx->stage[shader];
796 
797    util_copy_constant_buffer(&s->cb[index], cb, take_ownership);
798 
799    unsigned mask = (1 << index);
800 
801    if (cb)
802       s->cb_mask |= mask;
803    else
804       s->cb_mask &= ~mask;
805 }
806 
807 static void
agx_surface_destroy(struct pipe_context * ctx,struct pipe_surface * surface)808 agx_surface_destroy(struct pipe_context *ctx,
809                     struct pipe_surface *surface)
810 {
811    pipe_resource_reference(&surface->texture, NULL);
812    FREE(surface);
813 }
814 
815 static void
agx_delete_state(struct pipe_context * ctx,void * state)816 agx_delete_state(struct pipe_context *ctx, void *state)
817 {
818    FREE(state);
819 }
820 
821 /* BOs added to the batch in the uniform upload path */
822 
823 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)824 agx_set_vertex_buffers(struct pipe_context *pctx,
825                        unsigned start_slot, unsigned count,
826                        unsigned unbind_num_trailing_slots,
827                        bool take_ownership,
828                        const struct pipe_vertex_buffer *buffers)
829 {
830    struct agx_context *ctx = agx_context(pctx);
831 
832    util_set_vertex_buffers_mask(ctx->vertex_buffers, &ctx->vb_mask, buffers,
833                                 start_slot, count, unbind_num_trailing_slots, take_ownership);
834 
835    ctx->dirty |= AGX_DIRTY_VERTEX;
836 }
837 
838 static void *
agx_create_vertex_elements(struct pipe_context * ctx,unsigned count,const struct pipe_vertex_element * state)839 agx_create_vertex_elements(struct pipe_context *ctx,
840                            unsigned count,
841                            const struct pipe_vertex_element *state)
842 {
843    assert(count < AGX_MAX_ATTRIBS);
844 
845    struct agx_attribute *attribs = calloc(sizeof(*attribs), AGX_MAX_ATTRIBS);
846    for (unsigned i = 0; i < count; ++i) {
847       const struct pipe_vertex_element ve = state[i];
848 
849       const struct util_format_description *desc =
850          util_format_description(ve.src_format);
851 
852       unsigned chan_size = desc->channel[0].size / 8;
853 
854       assert(chan_size == 1 || chan_size == 2 || chan_size == 4);
855       assert(desc->nr_channels >= 1 && desc->nr_channels <= 4);
856       assert((ve.src_offset & (chan_size - 1)) == 0);
857 
858       attribs[i] = (struct agx_attribute) {
859          .buf = ve.vertex_buffer_index,
860          .src_offset = ve.src_offset / chan_size,
861          .nr_comps_minus_1 = desc->nr_channels - 1,
862          .format = agx_vertex_format[ve.src_format],
863          .divisor = ve.instance_divisor
864       };
865    }
866 
867    return attribs;
868 }
869 
870 static void
agx_bind_vertex_elements_state(struct pipe_context * pctx,void * cso)871 agx_bind_vertex_elements_state(struct pipe_context *pctx, void *cso)
872 {
873    struct agx_context *ctx = agx_context(pctx);
874    ctx->attributes = cso;
875    ctx->dirty |= AGX_DIRTY_VERTEX;
876 }
877 
asahi_shader_key_hash(const void * key)878 static uint32_t asahi_shader_key_hash(const void *key)
879 {
880    return _mesa_hash_data(key, sizeof(struct asahi_shader_key));
881 }
882 
asahi_shader_key_equal(const void * a,const void * b)883 static bool asahi_shader_key_equal(const void *a, const void *b)
884 {
885    return memcmp(a, b, sizeof(struct asahi_shader_key)) == 0;
886 }
887 
888 static void *
agx_create_shader_state(struct pipe_context * pctx,const struct pipe_shader_state * cso)889 agx_create_shader_state(struct pipe_context *pctx,
890                         const struct pipe_shader_state *cso)
891 {
892    struct agx_uncompiled_shader *so = CALLOC_STRUCT(agx_uncompiled_shader);
893 
894    if (!so)
895       return NULL;
896 
897    so->base = *cso;
898 
899    if (cso->type == PIPE_SHADER_IR_NIR) {
900       so->nir = cso->ir.nir;
901    } else {
902       assert(cso->type == PIPE_SHADER_IR_TGSI);
903       so->nir = tgsi_to_nir(cso->tokens, pctx->screen, false);
904    }
905 
906    so->variants = _mesa_hash_table_create(NULL, asahi_shader_key_hash, asahi_shader_key_equal);
907    return so;
908 }
909 
910 /* Does not take ownership of key. Clones if necessary. */
911 static bool
agx_update_shader(struct agx_context * ctx,struct agx_compiled_shader ** out,enum pipe_shader_type stage,struct asahi_shader_key * key)912 agx_update_shader(struct agx_context *ctx, struct agx_compiled_shader **out,
913                   enum pipe_shader_type stage, struct asahi_shader_key *key)
914 {
915    struct agx_uncompiled_shader *so = ctx->stage[stage].shader;
916    assert(so != NULL);
917 
918    struct hash_entry *he = _mesa_hash_table_search(so->variants, key);
919 
920    if (he) {
921       if ((*out) == he->data)
922          return false;
923 
924       *out = he->data;
925       return true;
926    }
927 
928    struct agx_compiled_shader *compiled = CALLOC_STRUCT(agx_compiled_shader);
929    struct util_dynarray binary;
930    util_dynarray_init(&binary, NULL);
931 
932    nir_shader *nir = nir_shader_clone(NULL, so->nir);
933 
934    if (stage == PIPE_SHADER_FRAGMENT) {
935       nir_lower_blend_options opts = {
936          .format = { key->rt_formats[0] },
937          .scalar_blend_const = true,
938          .logicop_enable = key->blend.logicop_enable,
939          .logicop_func = key->blend.logicop_func,
940       };
941 
942       memcpy(opts.rt, key->blend.rt, sizeof(opts.rt));
943       NIR_PASS_V(nir, nir_lower_blend, &opts);
944 
945       NIR_PASS_V(nir, nir_lower_fragcolor, key->nr_cbufs);
946    }
947 
948    agx_compile_shader_nir(nir, &key->base, &binary, &compiled->info);
949 
950    struct agx_varyings *varyings = &compiled->info.varyings;
951    unsigned packed_varying_sz = (AGX_VARYING_HEADER_LENGTH + varyings->nr_descs * AGX_VARYING_LENGTH);
952    uint8_t *packed_varyings = alloca(packed_varying_sz);
953 
954    agx_pack(packed_varyings, VARYING_HEADER, cfg) {
955       cfg.triangle_slots = cfg.point_slots = varyings->nr_slots;
956    }
957 
958    memcpy(packed_varyings + AGX_VARYING_HEADER_LENGTH, varyings->packed,
959          varyings->nr_descs * AGX_VARYING_LENGTH);
960 
961    if (binary.size) {
962       struct agx_device *dev = agx_device(ctx->base.screen);
963       compiled->bo = agx_bo_create(dev,
964                                    ALIGN_POT(binary.size, 256) + (3 * packed_varying_sz),
965                                    AGX_MEMORY_TYPE_SHADER);
966       memcpy(compiled->bo->ptr.cpu, binary.data, binary.size);
967 
968 
969       /* TODO: Why is the varying descriptor duplicated 3x? */
970       unsigned offs = ALIGN_POT(binary.size, 256);
971       for (unsigned copy = 0; copy < 3; ++copy) {
972          memcpy(((uint8_t *) compiled->bo->ptr.cpu) + offs, packed_varyings, packed_varying_sz);
973          offs += packed_varying_sz;
974       }
975 
976       compiled->varyings = compiled->bo->ptr.gpu + ALIGN_POT(binary.size, 256);
977    }
978 
979    ralloc_free(nir);
980    util_dynarray_fini(&binary);
981 
982    /* key may be destroyed after we return, so clone it before using it as a
983     * hash table key. The clone is logically owned by the hash table.
984     */
985    struct asahi_shader_key *cloned_key = ralloc(so->variants, struct asahi_shader_key);
986    memcpy(cloned_key, key, sizeof(struct asahi_shader_key));
987 
988    he = _mesa_hash_table_insert(so->variants, cloned_key, compiled);
989    *out = he->data;
990    return true;
991 }
992 
993 static bool
agx_update_vs(struct agx_context * ctx)994 agx_update_vs(struct agx_context *ctx)
995 {
996    struct agx_vs_shader_key key = {
997       .num_vbufs = util_last_bit(ctx->vb_mask),
998       .clip_halfz = ctx->rast->base.clip_halfz,
999    };
1000 
1001    memcpy(key.attributes, ctx->attributes,
1002           sizeof(key.attributes[0]) * AGX_MAX_ATTRIBS);
1003 
1004    u_foreach_bit(i, ctx->vb_mask) {
1005       key.vbuf_strides[i] = ctx->vertex_buffers[i].stride;
1006    }
1007 
1008    struct asahi_shader_key akey = {
1009       .base.vs = key
1010    };
1011 
1012    return agx_update_shader(ctx, &ctx->vs, PIPE_SHADER_VERTEX, &akey);
1013 }
1014 
1015 static bool
agx_update_fs(struct agx_context * ctx)1016 agx_update_fs(struct agx_context *ctx)
1017 {
1018    struct asahi_shader_key key = {
1019       .nr_cbufs = ctx->batch->nr_cbufs,
1020    };
1021 
1022    for (unsigned i = 0; i < key.nr_cbufs; ++i) {
1023       struct pipe_surface *surf = ctx->batch->cbufs[i];
1024 
1025       if (surf) {
1026          enum pipe_format fmt = surf->format;
1027          key.rt_formats[i] = fmt;
1028          key.base.fs.tib_formats[i] = agx_pixel_format[fmt].internal;
1029       } else {
1030          key.rt_formats[i] = PIPE_FORMAT_NONE;
1031       }
1032    }
1033 
1034    memcpy(&key.blend, ctx->blend, sizeof(key.blend));
1035 
1036    return agx_update_shader(ctx, &ctx->fs, PIPE_SHADER_FRAGMENT, &key);
1037 }
1038 
1039 static void
agx_bind_shader_state(struct pipe_context * pctx,void * cso)1040 agx_bind_shader_state(struct pipe_context *pctx, void *cso)
1041 {
1042    if (!cso)
1043       return;
1044 
1045    struct agx_context *ctx = agx_context(pctx);
1046    struct agx_uncompiled_shader *so = cso;
1047 
1048    enum pipe_shader_type type = pipe_shader_type_from_mesa(so->nir->info.stage);
1049    ctx->stage[type].shader = so;
1050 }
1051 
1052 static void
agx_delete_compiled_shader(struct hash_entry * ent)1053 agx_delete_compiled_shader(struct hash_entry *ent)
1054 {
1055    struct agx_compiled_shader *so = ent->data;
1056    agx_bo_unreference(so->bo);
1057    FREE(so);
1058 }
1059 
1060 static void
agx_delete_shader_state(struct pipe_context * ctx,void * cso)1061 agx_delete_shader_state(struct pipe_context *ctx,
1062                         void *cso)
1063 {
1064    struct agx_uncompiled_shader *so = cso;
1065    _mesa_hash_table_destroy(so->variants, agx_delete_compiled_shader);
1066    free(so);
1067 }
1068 
1069 /* Pipeline consists of a sequence of binding commands followed by a set shader command */
1070 static uint32_t
agx_build_pipeline(struct agx_context * ctx,struct agx_compiled_shader * cs,enum pipe_shader_type stage)1071 agx_build_pipeline(struct agx_context *ctx, struct agx_compiled_shader *cs, enum pipe_shader_type stage)
1072 {
1073    /* Pipelines must be 64-byte aligned */
1074    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1075                         (16 * AGX_BIND_UNIFORM_LENGTH) + // XXX: correct sizes, break up at compile time
1076                         (ctx->stage[stage].texture_count * AGX_BIND_TEXTURE_LENGTH) +
1077                         (PIPE_MAX_SAMPLERS * AGX_BIND_SAMPLER_LENGTH) +
1078                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1079                         64);
1080 
1081    uint8_t *record = ptr.cpu;
1082 
1083    /* There is a maximum number of half words we may push with a single
1084     * BIND_UNIFORM record, so split up the range to fit. We only need to call
1085     * agx_push_location once, however, which reduces the cost. */
1086    unsigned unif_records = 0;
1087 
1088    for (unsigned i = 0; i < cs->info.push_ranges; ++i) {
1089       struct agx_push push = cs->info.push[i];
1090       uint64_t buffer = agx_push_location(ctx, push, stage);
1091       unsigned halfs_per_record = 14;
1092       unsigned records = DIV_ROUND_UP(push.length, halfs_per_record);
1093 
1094       /* Ensure we don't overflow */
1095       unif_records += records;
1096       assert(unif_records < 16);
1097 
1098       for (unsigned j = 0; j < records; ++j) {
1099          agx_pack(record, BIND_UNIFORM, cfg) {
1100             cfg.start_halfs = push.base + (j * halfs_per_record);
1101             cfg.size_halfs = MIN2(push.length - (j * halfs_per_record), halfs_per_record);
1102             cfg.buffer = buffer + (j * halfs_per_record * 2);
1103          }
1104 
1105          record += AGX_BIND_UNIFORM_LENGTH;
1106       }
1107    }
1108 
1109    for (unsigned i = 0; i < ctx->stage[stage].texture_count; ++i) {
1110       struct agx_sampler_view *tex = ctx->stage[stage].textures[i];
1111       agx_batch_add_bo(ctx->batch, tex->desc);
1112       agx_batch_add_bo(ctx->batch, agx_resource(tex->base.texture)->bo);
1113 
1114 
1115       agx_pack(record, BIND_TEXTURE, cfg) {
1116          cfg.start = i;
1117          cfg.count = 1;
1118          cfg.buffer = tex->desc->ptr.gpu;
1119       }
1120 
1121       record += AGX_BIND_TEXTURE_LENGTH;
1122    }
1123 
1124    for (unsigned i = 0; i < PIPE_MAX_SAMPLERS; ++i) {
1125       struct agx_sampler_state *sampler = ctx->stage[stage].samplers[i];
1126 
1127       if (!sampler)
1128          continue;
1129 
1130       struct agx_bo *bo = sampler->desc;
1131       agx_batch_add_bo(ctx->batch, bo);
1132 
1133       agx_pack(record, BIND_SAMPLER, cfg) {
1134          cfg.start = i;
1135          cfg.count = 1;
1136          cfg.buffer = bo->ptr.gpu;
1137       }
1138 
1139       record += AGX_BIND_SAMPLER_LENGTH;
1140    }
1141 
1142    /* TODO: Can we prepack this? */
1143    if (stage == PIPE_SHADER_FRAGMENT) {
1144       bool writes_sample_mask = ctx->fs->info.writes_sample_mask;
1145 
1146       agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1147          cfg.code = cs->bo->ptr.gpu;
1148          cfg.register_quadwords = 0;
1149          cfg.unk_3 = 0x8d;
1150          cfg.unk_1 = 0x2010bd;
1151          cfg.unk_2 = 0x0d;
1152          cfg.unk_2b = writes_sample_mask ? 5 : 1;
1153          cfg.fragment_parameters.early_z_testing = !writes_sample_mask;
1154          cfg.unk_3b = 0x1;
1155          cfg.unk_4 = 0x800;
1156          cfg.preshader_unk = 0xc080;
1157          cfg.spill_size = 0x2;
1158       }
1159 
1160       record += AGX_SET_SHADER_EXTENDED_LENGTH;
1161    } else {
1162       agx_pack(record, SET_SHADER, cfg) {
1163          cfg.code = cs->bo->ptr.gpu;
1164          cfg.register_quadwords = 0;
1165          cfg.unk_2b = cs->info.varyings.nr_slots;
1166          cfg.unk_2 = 0x0d;
1167       }
1168 
1169       record += AGX_SET_SHADER_LENGTH;
1170    }
1171 
1172    /* End pipeline */
1173    memset(record, 0, 8);
1174    assert(ptr.gpu < (1ull << 32));
1175    return ptr.gpu;
1176 }
1177 
1178 /* Internal pipelines (TODO: refactor?) */
1179 uint64_t
agx_build_clear_pipeline(struct agx_context * ctx,uint32_t code,uint64_t clear_buf)1180 agx_build_clear_pipeline(struct agx_context *ctx, uint32_t code, uint64_t clear_buf)
1181 {
1182    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1183                         (1 * AGX_BIND_UNIFORM_LENGTH) +
1184                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1185                         64);
1186 
1187    uint8_t *record = ptr.cpu;
1188 
1189    agx_pack(record, BIND_UNIFORM, cfg) {
1190       cfg.start_halfs = (6 * 2);
1191       cfg.size_halfs = 4;
1192       cfg.buffer = clear_buf;
1193    }
1194 
1195    record += AGX_BIND_UNIFORM_LENGTH;
1196 
1197    /* TODO: Can we prepack this? */
1198    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1199       cfg.code = code;
1200       cfg.register_quadwords = 1;
1201       cfg.unk_3 = 0x8d;
1202       cfg.unk_2 = 0x0d;
1203       cfg.unk_2b = 4;
1204       cfg.fragment_parameters.unk_1 = 0x880100;
1205       cfg.fragment_parameters.early_z_testing = false;
1206       cfg.fragment_parameters.unk_2 = false;
1207       cfg.fragment_parameters.unk_3 = 0;
1208       cfg.preshader_mode = 0; // XXX
1209    }
1210 
1211    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1212 
1213    /* End pipeline */
1214    memset(record, 0, 8);
1215    return ptr.gpu;
1216 }
1217 
1218 uint64_t
agx_build_reload_pipeline(struct agx_context * ctx,uint32_t code,struct pipe_surface * surf)1219 agx_build_reload_pipeline(struct agx_context *ctx, uint32_t code, struct pipe_surface *surf)
1220 {
1221    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1222                         (1 * AGX_BIND_TEXTURE_LENGTH) +
1223                         (1 * AGX_BIND_SAMPLER_LENGTH) +
1224                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1225                         64);
1226 
1227    uint8_t *record = ptr.cpu;
1228    struct agx_ptr sampler = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_SAMPLER_LENGTH, 64);
1229    struct agx_ptr texture = agx_pool_alloc_aligned(&ctx->batch->pool, AGX_TEXTURE_LENGTH, 64);
1230 
1231    agx_pack(sampler.cpu, SAMPLER, cfg) {
1232       cfg.magnify_linear = true;
1233       cfg.minify_linear = false;
1234       cfg.mip_filter = AGX_MIP_FILTER_NONE;
1235       cfg.wrap_s = AGX_WRAP_CLAMP_TO_EDGE;
1236       cfg.wrap_t = AGX_WRAP_CLAMP_TO_EDGE;
1237       cfg.wrap_r = AGX_WRAP_CLAMP_TO_EDGE;
1238       cfg.pixel_coordinates = true;
1239       cfg.compare_func = AGX_COMPARE_FUNC_ALWAYS;
1240       cfg.unk_3 = 0;
1241    }
1242 
1243    agx_pack(texture.cpu, TEXTURE, cfg) {
1244       struct agx_resource *rsrc = agx_resource(surf->texture);
1245       unsigned level = surf->u.tex.level;
1246       unsigned layer = surf->u.tex.first_layer;
1247       const struct util_format_description *desc =
1248          util_format_description(surf->format);
1249 
1250       /* To reduce shader variants, we always use a non-mipmapped 2D texture.
1251        * For reloads of arrays, cube maps, etc -- we only logically reload a
1252        * single 2D image. This does mean we need to be careful about
1253        * width/height and address.
1254        */
1255       cfg.dimension = AGX_TEXTURE_DIMENSION_2D;
1256 
1257       cfg.layout = agx_translate_layout(rsrc->modifier);
1258       cfg.format = agx_pixel_format[surf->format].hw;
1259       cfg.swizzle_r = agx_channel_from_pipe(desc->swizzle[0]);
1260       cfg.swizzle_g = agx_channel_from_pipe(desc->swizzle[1]);
1261       cfg.swizzle_b = agx_channel_from_pipe(desc->swizzle[2]);
1262       cfg.swizzle_a = agx_channel_from_pipe(desc->swizzle[3]);
1263       cfg.width = u_minify(surf->width, level);
1264       cfg.height = u_minify(surf->height, level);
1265       cfg.levels = 1;
1266       cfg.srgb = (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB);
1267       cfg.address = agx_map_texture_gpu(rsrc, level, layer);
1268 
1269       cfg.stride = (rsrc->modifier == DRM_FORMAT_MOD_LINEAR) ?
1270          (rsrc->slices[level].line_stride - 16) :
1271          AGX_RT_STRIDE_TILED;
1272    }
1273 
1274    agx_pack(record, BIND_TEXTURE, cfg) {
1275       cfg.start = 0;
1276       cfg.count = 1;
1277       cfg.buffer = texture.gpu;
1278    }
1279 
1280    record += AGX_BIND_TEXTURE_LENGTH;
1281 
1282    agx_pack(record, BIND_SAMPLER, cfg) {
1283       cfg.start = 0;
1284       cfg.count = 1;
1285       cfg.buffer = sampler.gpu;
1286    }
1287 
1288    record += AGX_BIND_SAMPLER_LENGTH;
1289 
1290    /* TODO: Can we prepack this? */
1291    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1292       cfg.code = code;
1293       cfg.register_quadwords = 0;
1294       cfg.unk_3 = 0x8d;
1295       cfg.unk_2 = 0x0d;
1296       cfg.unk_2b = 4;
1297       cfg.unk_4 = 0;
1298       cfg.fragment_parameters.unk_1 = 0x880100;
1299       cfg.fragment_parameters.early_z_testing = false;
1300       cfg.fragment_parameters.unk_2 = false;
1301       cfg.fragment_parameters.unk_3 = 0;
1302       cfg.preshader_mode = 0; // XXX
1303    }
1304 
1305    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1306 
1307    /* End pipeline */
1308    memset(record, 0, 8);
1309    return ptr.gpu;
1310 }
1311 
1312 uint64_t
agx_build_store_pipeline(struct agx_context * ctx,uint32_t code,uint64_t render_target)1313 agx_build_store_pipeline(struct agx_context *ctx, uint32_t code,
1314                          uint64_t render_target)
1315 {
1316    struct agx_ptr ptr = agx_pool_alloc_aligned(&ctx->batch->pipeline_pool,
1317                         (1 * AGX_BIND_TEXTURE_LENGTH) +
1318                         (1 * AGX_BIND_UNIFORM_LENGTH) +
1319                         AGX_SET_SHADER_EXTENDED_LENGTH + 8,
1320                         64);
1321 
1322    uint8_t *record = ptr.cpu;
1323 
1324    agx_pack(record, BIND_TEXTURE, cfg) {
1325       cfg.start = 0;
1326       cfg.count = 1;
1327       cfg.buffer = render_target;
1328    }
1329 
1330    record += AGX_BIND_TEXTURE_LENGTH;
1331 
1332    uint32_t unk[] = { 0, ~0 };
1333 
1334    agx_pack(record, BIND_UNIFORM, cfg) {
1335       cfg.start_halfs = 4;
1336       cfg.size_halfs = 4;
1337       cfg.buffer = agx_pool_upload_aligned(&ctx->batch->pool, unk, sizeof(unk), 16);
1338    }
1339 
1340    record += AGX_BIND_UNIFORM_LENGTH;
1341 
1342    /* TODO: Can we prepack this? */
1343    agx_pack(record, SET_SHADER_EXTENDED, cfg) {
1344       cfg.code = code;
1345       cfg.register_quadwords = 1;
1346       cfg.unk_2 = 0xd;
1347       cfg.unk_3 = 0x8d;
1348       cfg.fragment_parameters.unk_1 = 0x880100;
1349       cfg.fragment_parameters.early_z_testing = false;
1350       cfg.fragment_parameters.unk_2 = false;
1351       cfg.fragment_parameters.unk_3 = 0;
1352       cfg.preshader_mode = 0; // XXX
1353    }
1354 
1355    record += AGX_SET_SHADER_EXTENDED_LENGTH;
1356 
1357    /* End pipeline */
1358    memset(record, 0, 8);
1359    return ptr.gpu;
1360 }
1361 
1362 static uint64_t
demo_launch_fragment(struct agx_context * ctx,struct agx_pool * pool,uint32_t pipeline,uint32_t varyings,unsigned input_count)1363 demo_launch_fragment(struct agx_context *ctx, struct agx_pool *pool, uint32_t pipeline, uint32_t varyings, unsigned input_count)
1364 {
1365    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_BIND_PIPELINE_LENGTH, 64);
1366 
1367    agx_pack(t.cpu, BIND_PIPELINE, cfg) {
1368       cfg.tag = AGX_BIND_PIPELINE_FRAGMENT;
1369       cfg.sampler_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
1370       cfg.texture_count = ctx->stage[PIPE_SHADER_FRAGMENT].texture_count;
1371       cfg.input_count = input_count;
1372       cfg.pipeline = pipeline;
1373       cfg.fs_varyings = varyings;
1374    };
1375 
1376    return t.gpu;
1377 }
1378 
1379 static uint64_t
demo_interpolation(struct agx_compiled_shader * fs,struct agx_pool * pool)1380 demo_interpolation(struct agx_compiled_shader *fs, struct agx_pool *pool)
1381 {
1382    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_INTERPOLATION_LENGTH, 64);
1383 
1384    agx_pack(t.cpu, INTERPOLATION, cfg) {
1385       cfg.varying_count = fs->info.varyings.nr_slots;
1386    };
1387 
1388    return t.gpu;
1389 }
1390 
1391 static uint64_t
demo_linkage(struct agx_compiled_shader * vs,struct agx_pool * pool)1392 demo_linkage(struct agx_compiled_shader *vs, struct agx_pool *pool)
1393 {
1394    struct agx_ptr t = agx_pool_alloc_aligned(pool, AGX_LINKAGE_LENGTH, 64);
1395 
1396    agx_pack(t.cpu, LINKAGE, cfg) {
1397       cfg.varying_count = vs->info.varyings.nr_slots;
1398 
1399       // 0x2 for fragcoordz, 0x1 for varyings at all
1400       cfg.unk_1 = 0x210000 | (vs->info.writes_psiz ? 0x40000 : 0);
1401    };
1402 
1403    return t.gpu;
1404 }
1405 
1406 static uint64_t
demo_rasterizer(struct agx_context * ctx,struct agx_pool * pool,bool is_points)1407 demo_rasterizer(struct agx_context *ctx, struct agx_pool *pool, bool is_points)
1408 {
1409    struct agx_rasterizer *rast = ctx->rast;
1410    struct agx_rasterizer_packed out;
1411 
1412    agx_pack(&out, RASTERIZER, cfg) {
1413       bool back_stencil = ctx->zs.base.stencil[1].enabled;
1414       cfg.front.stencil_reference = ctx->stencil_ref.ref_value[0];
1415       cfg.back.stencil_reference = back_stencil ?
1416          ctx->stencil_ref.ref_value[1] :
1417          cfg.front.stencil_reference;
1418 
1419       cfg.front.line_width = cfg.back.line_width = rast->line_width;
1420       cfg.front.polygon_mode = cfg.back.polygon_mode = AGX_POLYGON_MODE_FILL;
1421 
1422       cfg.unk_fill_lines = is_points; /* XXX: what is this? */
1423 
1424       /* Always enable scissoring so we may scissor to the viewport (TODO:
1425        * optimize this out if the viewport is the default and the app does not
1426        * use the scissor test) */
1427       cfg.scissor_enable = true;
1428 
1429       cfg.depth_bias_enable = rast->base.offset_tri;
1430    };
1431 
1432    /* Words 2-3: front */
1433    out.opaque[2] |= ctx->zs.front.opaque[0];
1434    out.opaque[3] |= ctx->zs.front.opaque[1];
1435 
1436    /* Words 4-5: back */
1437    out.opaque[4] |= ctx->zs.back.opaque[0];
1438    out.opaque[5] |= ctx->zs.back.opaque[1];
1439 
1440    return agx_pool_upload_aligned(pool, &out, sizeof(out), 64);
1441 }
1442 
1443 static uint64_t
demo_unk11(struct agx_pool * pool,bool prim_lines,bool prim_points,bool reads_tib,bool sample_mask_from_shader)1444 demo_unk11(struct agx_pool *pool, bool prim_lines, bool prim_points, bool reads_tib, bool sample_mask_from_shader)
1445 {
1446    struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_UNKNOWN_4A_LENGTH, 64);
1447 
1448    agx_pack(T.cpu, UNKNOWN_4A, cfg) {
1449       cfg.lines_or_points = (prim_lines || prim_points);
1450       cfg.reads_tilebuffer = reads_tib;
1451       cfg.sample_mask_from_shader = sample_mask_from_shader;
1452 
1453       cfg.front.lines = cfg.back.lines = prim_lines;
1454       cfg.front.points = cfg.back.points = prim_points;
1455    };
1456 
1457    return T.gpu;
1458 }
1459 
1460 static uint64_t
demo_unk12(struct agx_pool * pool)1461 demo_unk12(struct agx_pool *pool)
1462 {
1463    uint32_t unk[] = {
1464       0x410000,
1465       0x1e3ce508,
1466       0xa0
1467    };
1468 
1469    return agx_pool_upload(pool, unk, sizeof(unk));
1470 }
1471 
1472 static uint64_t
agx_set_index(struct agx_pool * pool,uint16_t scissor,uint16_t zbias)1473 agx_set_index(struct agx_pool *pool, uint16_t scissor, uint16_t zbias)
1474 {
1475    struct agx_ptr T = agx_pool_alloc_aligned(pool, AGX_SET_INDEX_LENGTH, 64);
1476 
1477    agx_pack(T.cpu, SET_INDEX, cfg) {
1478       cfg.scissor = scissor;
1479       cfg.depth_bias = zbias;
1480    };
1481 
1482    return T.gpu;
1483 }
1484 
1485 static void
agx_push_record(uint8_t ** out,unsigned size_words,uint64_t ptr)1486 agx_push_record(uint8_t **out, unsigned size_words, uint64_t ptr)
1487 {
1488    assert(ptr < (1ull << 40));
1489    assert(size_words < (1ull << 24));
1490 
1491    agx_pack(*out, RECORD, cfg) {
1492       cfg.pointer_hi = (ptr >> 32);
1493       cfg.pointer_lo = (uint32_t) ptr;
1494       cfg.size_words = size_words;
1495    };
1496 
1497    *out += AGX_RECORD_LENGTH;
1498 }
1499 
1500 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)1501 agx_encode_state(struct agx_context *ctx, uint8_t *out,
1502                  uint32_t pipeline_vertex, uint32_t pipeline_fragment, uint32_t varyings,
1503                  bool is_lines, bool is_points)
1504 {
1505    agx_pack(out, BIND_PIPELINE, cfg) {
1506       cfg.tag = AGX_BIND_PIPELINE_VERTEX;
1507       cfg.pipeline = pipeline_vertex;
1508       cfg.vs_output_count_1 = ctx->vs->info.varyings.nr_slots;
1509       cfg.vs_output_count_2 = ctx->vs->info.varyings.nr_slots;
1510       cfg.sampler_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
1511       cfg.texture_count = ctx->stage[PIPE_SHADER_VERTEX].texture_count;
1512    }
1513 
1514    out += AGX_BIND_PIPELINE_LENGTH;
1515 
1516    struct agx_pool *pool = &ctx->batch->pool;
1517    bool reads_tib = ctx->fs->info.reads_tib;
1518    bool sample_mask_from_shader = ctx->fs->info.writes_sample_mask;
1519 
1520    agx_push_record(&out, 5, demo_interpolation(ctx->fs, pool));
1521    agx_push_record(&out, 5, demo_launch_fragment(ctx, pool, pipeline_fragment, varyings, ctx->fs->info.varyings.nr_descs));
1522    agx_push_record(&out, 4, demo_linkage(ctx->vs, pool));
1523    agx_push_record(&out, 7, demo_rasterizer(ctx, pool, is_points));
1524    agx_push_record(&out, 5, demo_unk11(pool, is_lines, is_points, reads_tib, sample_mask_from_shader));
1525 
1526    unsigned zbias = 0;
1527 
1528    if (ctx->rast->base.offset_tri) {
1529       zbias = agx_upload_depth_bias(ctx->batch, &ctx->rast->base);
1530       ctx->dirty |= AGX_DIRTY_SCISSOR_ZBIAS;
1531    }
1532 
1533    if (ctx->dirty & (AGX_DIRTY_VIEWPORT | AGX_DIRTY_SCISSOR_ZBIAS)) {
1534       struct agx_viewport_scissor vps = agx_upload_viewport_scissor(pool,
1535             ctx->batch, &ctx->viewport,
1536             ctx->rast->base.scissor ? &ctx->scissor : NULL);
1537 
1538       agx_push_record(&out, 10, vps.viewport);
1539       agx_push_record(&out, 2, agx_set_index(pool, vps.scissor, zbias));
1540    }
1541 
1542    agx_push_record(&out, 3, demo_unk12(pool));
1543    agx_push_record(&out, 2, agx_pool_upload(pool, ctx->rast->cull, sizeof(ctx->rast->cull)));
1544 
1545    return out;
1546 }
1547 
1548 static enum agx_primitive
agx_primitive_for_pipe(enum pipe_prim_type mode)1549 agx_primitive_for_pipe(enum pipe_prim_type mode)
1550 {
1551    switch (mode) {
1552    case PIPE_PRIM_POINTS: return AGX_PRIMITIVE_POINTS;
1553    case PIPE_PRIM_LINES: return AGX_PRIMITIVE_LINES;
1554    case PIPE_PRIM_LINE_STRIP: return AGX_PRIMITIVE_LINE_STRIP;
1555    case PIPE_PRIM_LINE_LOOP: return AGX_PRIMITIVE_LINE_LOOP;
1556    case PIPE_PRIM_TRIANGLES: return AGX_PRIMITIVE_TRIANGLES;
1557    case PIPE_PRIM_TRIANGLE_STRIP: return AGX_PRIMITIVE_TRIANGLE_STRIP;
1558    case PIPE_PRIM_TRIANGLE_FAN: return AGX_PRIMITIVE_TRIANGLE_FAN;
1559    case PIPE_PRIM_QUADS: return AGX_PRIMITIVE_QUADS;
1560    case PIPE_PRIM_QUAD_STRIP: return AGX_PRIMITIVE_QUAD_STRIP;
1561    default: unreachable("todo: other primitive types");
1562    }
1563 }
1564 
1565 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)1566 agx_index_buffer_ptr(struct agx_batch *batch,
1567                      const struct pipe_draw_start_count_bias *draw,
1568                      const struct pipe_draw_info *info)
1569 {
1570    off_t offset = draw->start * info->index_size;
1571 
1572    if (!info->has_user_indices) {
1573       struct agx_bo *bo = agx_resource(info->index.resource)->bo;
1574       agx_batch_add_bo(batch, bo);
1575 
1576       return bo->ptr.gpu + offset;
1577    } else {
1578       return agx_pool_upload_aligned(&batch->pool,
1579                                      ((uint8_t *) info->index.user) + offset,
1580                                      draw->count * info->index_size, 64);
1581    }
1582 }
1583 
1584 static bool
agx_scissor_culls_everything(struct agx_context * ctx)1585 agx_scissor_culls_everything(struct agx_context *ctx)
1586 {
1587         const struct pipe_scissor_state ss = ctx->scissor;
1588 
1589         return ctx->rast->base.scissor &&
1590 		((ss.minx == ss.maxx) || (ss.miny == ss.maxy));
1591 }
1592 
1593 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)1594 agx_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info,
1595              unsigned drawid_offset,
1596              const struct pipe_draw_indirect_info *indirect,
1597              const struct pipe_draw_start_count_bias *draws,
1598              unsigned num_draws)
1599 {
1600    if (num_draws > 1) {
1601       util_draw_multi(pctx, info, drawid_offset, indirect, draws, num_draws);
1602       return;
1603    }
1604 
1605    if (info->index_size && draws->index_bias)
1606       unreachable("todo: index bias");
1607 
1608    struct agx_context *ctx = agx_context(pctx);
1609    struct agx_batch *batch = ctx->batch;
1610 
1611    if (agx_scissor_culls_everything(ctx))
1612 	   return;
1613 
1614    /* TODO: masks */
1615    ctx->batch->draw |= ~0;
1616 
1617    /* TODO: Dirty track */
1618    agx_update_vs(ctx);
1619    agx_update_fs(ctx);
1620 
1621    agx_batch_add_bo(batch, ctx->vs->bo);
1622    agx_batch_add_bo(batch, ctx->fs->bo);
1623 
1624    bool is_lines =
1625       (info->mode == PIPE_PRIM_LINES) ||
1626       (info->mode == PIPE_PRIM_LINE_STRIP) ||
1627       (info->mode == PIPE_PRIM_LINE_LOOP);
1628 
1629    ptrdiff_t encoder_use = batch->encoder_current - (uint8_t *) batch->encoder->ptr.cpu;
1630    assert((encoder_use + 1024) < batch->encoder->size && "todo: how to expand encoder?");
1631 
1632    uint8_t *out = agx_encode_state(ctx, batch->encoder_current,
1633                                    agx_build_pipeline(ctx, ctx->vs, PIPE_SHADER_VERTEX),
1634                                    agx_build_pipeline(ctx, ctx->fs, PIPE_SHADER_FRAGMENT),
1635                                    ctx->fs->varyings, is_lines, info->mode == PIPE_PRIM_POINTS);
1636 
1637    enum agx_primitive prim = agx_primitive_for_pipe(info->mode);
1638    unsigned idx_size = info->index_size;
1639 
1640    if (idx_size) {
1641       uint64_t ib = agx_index_buffer_ptr(batch, draws, info);
1642 
1643       /* Index sizes are encoded logarithmically */
1644       STATIC_ASSERT(__builtin_ctz(1) == AGX_INDEX_SIZE_U8);
1645       STATIC_ASSERT(__builtin_ctz(2) == AGX_INDEX_SIZE_U16);
1646       STATIC_ASSERT(__builtin_ctz(4) == AGX_INDEX_SIZE_U32);
1647       assert((idx_size == 1) || (idx_size == 2) || (idx_size == 4));
1648 
1649       agx_pack(out, INDEXED_DRAW, cfg) {
1650          cfg.restart_index = info->restart_index;
1651          cfg.unk_2a = (ib >> 32);
1652          cfg.primitive = prim;
1653          cfg.restart_enable = info->primitive_restart;
1654          cfg.index_size = __builtin_ctz(idx_size);
1655          cfg.index_buffer_offset = (ib & BITFIELD_MASK(32));
1656          cfg.index_buffer_size = ALIGN_POT(draws->count * idx_size, 4);
1657          cfg.index_count = draws->count;
1658          cfg.instance_count = info->instance_count;
1659          cfg.base_vertex = draws->index_bias;
1660       };
1661 
1662       out += AGX_INDEXED_DRAW_LENGTH;
1663    } else {
1664       agx_pack(out, DRAW, cfg) {
1665          cfg.primitive = prim;
1666          cfg.vertex_start = draws->start;
1667          cfg.vertex_count = draws->count;
1668          cfg.instance_count = info->instance_count;
1669       };
1670 
1671       out += AGX_DRAW_LENGTH;
1672    }
1673 
1674    batch->encoder_current = out;
1675    ctx->dirty = 0;
1676 }
1677 
1678 void agx_init_state_functions(struct pipe_context *ctx);
1679 
1680 void
agx_init_state_functions(struct pipe_context * ctx)1681 agx_init_state_functions(struct pipe_context *ctx)
1682 {
1683    ctx->create_blend_state = agx_create_blend_state;
1684    ctx->create_depth_stencil_alpha_state = agx_create_zsa_state;
1685    ctx->create_fs_state = agx_create_shader_state;
1686    ctx->create_rasterizer_state = agx_create_rs_state;
1687    ctx->create_sampler_state = agx_create_sampler_state;
1688    ctx->create_sampler_view = agx_create_sampler_view;
1689    ctx->create_surface = agx_create_surface;
1690    ctx->create_vertex_elements_state = agx_create_vertex_elements;
1691    ctx->create_vs_state = agx_create_shader_state;
1692    ctx->bind_blend_state = agx_bind_blend_state;
1693    ctx->bind_depth_stencil_alpha_state = agx_bind_zsa_state;
1694    ctx->bind_sampler_states = agx_bind_sampler_states;
1695    ctx->bind_fs_state = agx_bind_shader_state;
1696    ctx->bind_rasterizer_state = agx_bind_rasterizer_state;
1697    ctx->bind_vertex_elements_state = agx_bind_vertex_elements_state;
1698    ctx->bind_vs_state = agx_bind_shader_state;
1699    ctx->delete_blend_state = agx_delete_state;
1700    ctx->delete_depth_stencil_alpha_state = agx_delete_state;
1701    ctx->delete_fs_state = agx_delete_shader_state;
1702    ctx->delete_rasterizer_state = agx_delete_state;
1703    ctx->delete_sampler_state = agx_delete_sampler_state;
1704    ctx->delete_vertex_elements_state = agx_delete_state;
1705    ctx->delete_vs_state = agx_delete_state;
1706    ctx->set_blend_color = agx_set_blend_color;
1707    ctx->set_clip_state = agx_set_clip_state;
1708    ctx->set_constant_buffer = agx_set_constant_buffer;
1709    ctx->set_sampler_views = agx_set_sampler_views;
1710    ctx->set_framebuffer_state = agx_set_framebuffer_state;
1711    ctx->set_polygon_stipple = agx_set_polygon_stipple;
1712    ctx->set_sample_mask = agx_set_sample_mask;
1713    ctx->set_scissor_states = agx_set_scissor_states;
1714    ctx->set_stencil_ref = agx_set_stencil_ref;
1715    ctx->set_vertex_buffers = agx_set_vertex_buffers;
1716    ctx->set_viewport_states = agx_set_viewport_states;
1717    ctx->sampler_view_destroy = agx_sampler_view_destroy;
1718    ctx->surface_destroy = agx_surface_destroy;
1719    ctx->draw_vbo = agx_draw_vbo;
1720    ctx->create_stream_output_target = agx_create_stream_output_target;
1721    ctx->stream_output_target_destroy = agx_stream_output_target_destroy;
1722    ctx->set_stream_output_targets = agx_set_stream_output_targets;
1723 }
1724