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