1 /*
2 * Copyright © 2013 Rob Clark <[email protected]>
3 * SPDX-License-Identifier: MIT
4 *
5 * Authors:
6 * Rob Clark <[email protected]>
7 */
8
9 #include "pipe/p_state.h"
10 #include "util/format/u_format.h"
11 #include "util/u_memory.h"
12 #include "util/u_prim.h"
13 #include "util/u_string.h"
14
15 #include "freedreno_resource.h"
16 #include "freedreno_state.h"
17
18 #include "fd3_context.h"
19 #include "fd3_draw.h"
20 #include "fd3_emit.h"
21 #include "fd3_format.h"
22 #include "fd3_program.h"
23 #include "fd3_zsa.h"
24
25 static inline uint32_t
add_sat(uint32_t a,int32_t b)26 add_sat(uint32_t a, int32_t b)
27 {
28 int64_t ret = (uint64_t)a + (int64_t)b;
29 if (ret > ~0U)
30 return ~0U;
31 if (ret < 0)
32 return 0;
33 return (uint32_t)ret;
34 }
35
36 static void
draw_impl(struct fd_context * ctx,struct fd_ringbuffer * ring,struct fd3_emit * emit,unsigned index_offset)37 draw_impl(struct fd_context *ctx, struct fd_ringbuffer *ring,
38 struct fd3_emit *emit, unsigned index_offset) assert_dt
39 {
40 const struct pipe_draw_info *info = emit->info;
41 enum pc_di_primtype primtype = ctx->screen->primtypes[info->mode];
42
43 fd3_emit_state(ctx, ring, emit);
44
45 if (emit->dirty & (FD_DIRTY_VTXBUF | FD_DIRTY_VTXSTATE))
46 fd3_emit_vertex_bufs(ring, emit);
47
48 OUT_PKT0(ring, REG_A3XX_PC_VERTEX_REUSE_BLOCK_CNTL, 1);
49 OUT_RING(ring, 0x0000000b); /* PC_VERTEX_REUSE_BLOCK_CNTL */
50
51 OUT_PKT0(ring, REG_A3XX_VFD_INDEX_MIN, 4);
52 OUT_RING(ring, info->index_bounds_valid
53 ? add_sat(info->min_index,
54 info->index_size ? emit->draw->index_bias : 0)
55 : 0); /* VFD_INDEX_MIN */
56 OUT_RING(ring, info->index_bounds_valid
57 ? add_sat(info->max_index,
58 info->index_size ? emit->draw->index_bias : 0)
59 : ~0); /* VFD_INDEX_MAX */
60 OUT_RING(ring, info->start_instance); /* VFD_INSTANCEID_OFFSET */
61 OUT_RING(ring, info->index_size ? emit->draw->index_bias
62 : emit->draw->start); /* VFD_INDEX_OFFSET */
63
64 OUT_PKT0(ring, REG_A3XX_PC_RESTART_INDEX, 1);
65 OUT_RING(ring, info->primitive_restart ? /* PC_RESTART_INDEX */
66 info->restart_index
67 : 0xffffffff);
68
69 /* points + psize -> spritelist: */
70 if (ctx->rasterizer->point_size_per_vertex &&
71 fd3_emit_get_vp(emit)->writes_psize && (info->mode == MESA_PRIM_POINTS))
72 primtype = DI_PT_POINTLIST_PSIZE;
73
74 fd_draw_emit(ctx->batch, ring, primtype,
75 emit->binning_pass ? IGNORE_VISIBILITY : USE_VISIBILITY, info,
76 emit->draw, index_offset);
77 }
78
79 static bool
fd3_draw_vbo(struct fd_context * ctx,const struct pipe_draw_info * info,unsigned drawid_offset,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draw,unsigned index_offset)80 fd3_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info,
81 unsigned drawid_offset,
82 const struct pipe_draw_indirect_info *indirect,
83 const struct pipe_draw_start_count_bias *draw,
84 unsigned index_offset) in_dt
85 {
86 struct fd3_emit emit = {
87 .debug = &ctx->debug,
88 .vtx = &ctx->vtx,
89 .info = info,
90 .drawid_offset = drawid_offset,
91 .indirect = indirect,
92 .draw = draw,
93 .key = {
94 .vs = ctx->prog.vs,
95 .fs = ctx->prog.fs,
96 },
97 .rasterflat = ctx->rasterizer->flatshade,
98 .sprite_coord_enable = ctx->rasterizer->sprite_coord_enable,
99 .sprite_coord_mode = ctx->rasterizer->sprite_coord_mode,
100 };
101
102 if (info->mode != MESA_PRIM_COUNT && !indirect && !info->primitive_restart &&
103 !u_trim_pipe_prim(info->mode, (unsigned *)&draw->count))
104 return false;
105
106 if (fd3_needs_manual_clipping(ir3_get_shader(ctx->prog.vs), ctx->rasterizer))
107 emit.key.key.ucp_enables = ctx->rasterizer->clip_plane_enable;
108
109 ir3_fixup_shader_state(&ctx->base, &emit.key.key);
110
111 unsigned dirty = ctx->dirty;
112
113 emit.prog = fd3_program_state(
114 ir3_cache_lookup(ctx->shader_cache, &emit.key, &ctx->debug));
115
116 /* bail if compile failed: */
117 if (!emit.prog)
118 return false;
119
120 fd_blend_tracking(ctx);
121
122 const struct ir3_shader_variant *vp = fd3_emit_get_vp(&emit);
123 const struct ir3_shader_variant *fp = fd3_emit_get_fp(&emit);
124
125 ir3_update_max_tf_vtx(ctx, vp);
126
127 /* do regular pass first: */
128
129 if (unlikely(ctx->stats_users > 0)) {
130 ctx->stats.vs_regs += ir3_shader_halfregs(vp);
131 ctx->stats.fs_regs += ir3_shader_halfregs(fp);
132 }
133
134 emit.binning_pass = false;
135 emit.dirty = dirty;
136 draw_impl(ctx, ctx->batch->draw, &emit, index_offset);
137
138 /* and now binning pass: */
139 emit.binning_pass = true;
140 emit.dirty = dirty & ~(FD_DIRTY_BLEND);
141 emit.vs = NULL; /* we changed key so need to refetch vs */
142 emit.fs = NULL;
143 draw_impl(ctx, ctx->batch->binning, &emit, index_offset);
144
145 fd_context_all_clean(ctx);
146
147 ctx->batch->num_vertices += draw->count * info->instance_count;
148
149 return true;
150 }
151
152 static void
fd3_draw_vbos(struct fd_context * ctx,const struct pipe_draw_info * info,unsigned drawid_offset,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draws,unsigned num_draws,unsigned index_offset)153 fd3_draw_vbos(struct fd_context *ctx, const struct pipe_draw_info *info,
154 unsigned drawid_offset,
155 const struct pipe_draw_indirect_info *indirect,
156 const struct pipe_draw_start_count_bias *draws,
157 unsigned num_draws,
158 unsigned index_offset)
159 assert_dt
160 {
161 for (unsigned i = 0; i < num_draws; i++)
162 fd3_draw_vbo(ctx, info, drawid_offset, indirect, &draws[i], index_offset);
163 }
164
165 void
fd3_draw_init(struct pipe_context * pctx)166 fd3_draw_init(struct pipe_context *pctx) disable_thread_safety_analysis
167 {
168 struct fd_context *ctx = fd_context(pctx);
169 ctx->draw_vbos = fd3_draw_vbos;
170 }
171