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