panfrost: Assign indices at draw-time
[mesa.git] / src / gallium / drivers / panfrost / pan_varyings.c
1 /*
2 * Copyright (C) 2018-2019 Alyssa Rosenzweig
3 * Copyright (C) 2019 Collabora, Ltd.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 */
25
26 #include "pan_context.h"
27
28 static mali_ptr
29 panfrost_emit_varyings(
30 struct panfrost_context *ctx,
31 union mali_attr *slot,
32 unsigned stride,
33 unsigned count)
34 {
35 /* Fill out the descriptor */
36 slot->stride = stride;
37 slot->size = stride * count;
38 slot->shift = slot->extra_flags = 0;
39
40 struct panfrost_transfer transfer =
41 panfrost_allocate_transient(ctx, slot->size);
42
43 slot->elements = transfer.gpu | MALI_ATTR_LINEAR;
44
45 return transfer.gpu;
46 }
47
48 static void
49 panfrost_emit_point_coord(union mali_attr *slot)
50 {
51 slot->elements = MALI_VARYING_POINT_COORD | MALI_ATTR_LINEAR;
52 slot->stride = slot->size = slot->shift = slot->extra_flags = 0;
53 }
54
55 static void
56 panfrost_emit_front_face(union mali_attr *slot)
57 {
58 slot->elements = MALI_VARYING_FRONT_FACING | MALI_ATTR_INTERNAL;
59 }
60
61 /* Given a shader and buffer indices, link varying metadata together */
62
63 static void
64 panfrost_emit_varying_meta(
65 void *outptr, struct panfrost_shader_state *ss,
66 signed general, signed gl_Position,
67 signed gl_PointSize, signed gl_PointCoord,
68 signed gl_FrontFacing)
69 {
70 struct mali_attr_meta *out = (struct mali_attr_meta *) outptr;
71
72 for (unsigned i = 0; i < ss->tripipe->varying_count; ++i) {
73 gl_varying_slot location = ss->varyings_loc[i];
74 int index = -1;
75
76 switch (location) {
77 case VARYING_SLOT_POS:
78 index = gl_Position;
79 break;
80 case VARYING_SLOT_PSIZ:
81 index = gl_PointSize;
82 break;
83 case VARYING_SLOT_PNTC:
84 index = gl_PointCoord;
85 break;
86 case VARYING_SLOT_FACE:
87 index = gl_FrontFacing;
88 break;
89 default:
90 index = general;
91 break;
92 }
93
94 assert(index >= 0);
95 out[i].index = index;
96 }
97 }
98
99 void
100 panfrost_emit_varying_descriptor(
101 struct panfrost_context *ctx,
102 unsigned vertex_count)
103 {
104 /* Load the shaders */
105
106 struct panfrost_shader_state *vs = &ctx->shader[PIPE_SHADER_VERTEX]->variants[ctx->shader[PIPE_SHADER_VERTEX]->active_variant];
107 struct panfrost_shader_state *fs = &ctx->shader[PIPE_SHADER_FRAGMENT]->variants[ctx->shader[PIPE_SHADER_FRAGMENT]->active_variant];
108 unsigned int num_gen_varyings = 0;
109
110 /* Allocate the varying descriptor */
111
112 size_t vs_size = sizeof(struct mali_attr_meta) * vs->tripipe->varying_count;
113 size_t fs_size = sizeof(struct mali_attr_meta) * fs->tripipe->varying_count;
114
115 struct panfrost_transfer trans = panfrost_allocate_transient(ctx,
116 vs_size + fs_size);
117
118 /*
119 * Assign ->src_offset now that we know about all the general purpose
120 * varyings that will be used by the fragment and vertex shaders.
121 */
122 for (unsigned i = 0; i < vs->tripipe->varying_count; i++) {
123 /*
124 * General purpose varyings have ->index set to 0, skip other
125 * entries.
126 */
127 if (vs->varyings[i].index)
128 continue;
129
130 vs->varyings[i].src_offset = 16 * (num_gen_varyings++);
131 }
132
133 for (unsigned i = 0; i < fs->tripipe->varying_count; i++) {
134 unsigned j;
135
136 /* If we have a point sprite replacement, handle that here. We
137 * have to translate location first. TODO: Flip y in shader.
138 * We're already keying ... just time crunch .. */
139
140 unsigned loc = fs->varyings_loc[i];
141 unsigned pnt_loc =
142 (loc >= VARYING_SLOT_VAR0) ? (loc - VARYING_SLOT_VAR0) :
143 (loc == VARYING_SLOT_PNTC) ? 8 :
144 ~0;
145
146 if (~pnt_loc && fs->point_sprite_mask & (1 << pnt_loc)) {
147 /* gl_PointCoord index by convention */
148 fs->varyings[i].index = 3;
149 fs->reads_point_coord = true;
150
151 /* Swizzle out the z/w to 0/1 */
152 fs->varyings[i].format = MALI_RG16F;
153 fs->varyings[i].swizzle =
154 panfrost_get_default_swizzle(2);
155
156 continue;
157 }
158
159 if (fs->varyings[i].index)
160 continue;
161
162 /*
163 * Re-use the VS general purpose varying pos if it exists,
164 * create a new one otherwise.
165 */
166 for (j = 0; j < vs->tripipe->varying_count; j++) {
167 if (fs->varyings_loc[i] == vs->varyings_loc[j])
168 break;
169 }
170
171 if (j < vs->tripipe->varying_count)
172 fs->varyings[i].src_offset = vs->varyings[j].src_offset;
173 else
174 fs->varyings[i].src_offset = 16 * (num_gen_varyings++);
175 }
176
177 memcpy(trans.cpu, vs->varyings, vs_size);
178 memcpy(trans.cpu + vs_size, fs->varyings, fs_size);
179
180 /* Buffer indices must be in this order per our convention */
181 union mali_attr varyings[PIPE_MAX_ATTRIBS];
182 unsigned idx = 0;
183
184 signed general = idx++;
185 signed gl_Position = idx++;
186 signed gl_PointSize = (vs->writes_point_size || fs->reads_point_coord || fs->reads_face) ? (idx++) : -1;
187 signed gl_PointCoord = (fs->reads_point_coord || fs->reads_face) ? (idx++) : -1;
188 signed gl_FrontFacing = (fs->reads_face) ? (idx++) : -1;
189
190 panfrost_emit_varyings(ctx, &varyings[general], num_gen_varyings * 16,
191 vertex_count);
192
193 /* fp32 vec4 gl_Position */
194 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.position_varying =
195 panfrost_emit_varyings(ctx, &varyings[gl_Position],
196 sizeof(float) * 4, vertex_count);
197
198
199 if (vs->writes_point_size || fs->reads_point_coord) {
200 /* fp16 vec1 gl_PointSize */
201 ctx->payloads[PIPE_SHADER_FRAGMENT].primitive_size.pointer =
202 panfrost_emit_varyings(ctx, &varyings[gl_PointSize],
203 2, vertex_count);
204 } else if (fs->reads_face) {
205 /* Dummy to advance index */
206 ++idx;
207 }
208
209 if (fs->reads_point_coord) {
210 /* Special descriptor */
211 panfrost_emit_point_coord(&varyings[gl_PointCoord]);
212 } else if (fs->reads_face) {
213 ++idx;
214 }
215
216 if (fs->reads_face) {
217 panfrost_emit_front_face(&varyings[gl_FrontFacing]);
218 }
219
220 /* Let's go ahead and link varying meta to the buffer in question, now
221 * that that information is available */
222
223 panfrost_emit_varying_meta(trans.cpu, vs,
224 general, gl_Position, gl_PointSize,
225 gl_PointCoord, gl_FrontFacing);
226
227 panfrost_emit_varying_meta(trans.cpu + vs_size, fs,
228 general, gl_Position, gl_PointSize,
229 gl_PointCoord, gl_FrontFacing);
230
231 mali_ptr varyings_p = panfrost_upload_transient(ctx, &varyings, idx * sizeof(union mali_attr));
232 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varyings = varyings_p;
233 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varyings = varyings_p;
234
235 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varying_meta = trans.gpu;
236 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varying_meta = trans.gpu + vs_size;
237 }