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