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