panfrost: Assign varying buffers dynamically
[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 bool
64 is_special_varying(gl_varying_slot loc)
65 {
66 switch (loc) {
67 case VARYING_SLOT_POS:
68 case VARYING_SLOT_PSIZ:
69 case VARYING_SLOT_PNTC:
70 case VARYING_SLOT_FACE:
71 return true;
72 default:
73 return false;
74 }
75 }
76
77 static void
78 panfrost_emit_varying_meta(
79 void *outptr, struct panfrost_shader_state *ss,
80 signed general, signed gl_Position,
81 signed gl_PointSize, signed gl_PointCoord,
82 signed gl_FrontFacing)
83 {
84 struct mali_attr_meta *out = (struct mali_attr_meta *) outptr;
85
86 for (unsigned i = 0; i < ss->tripipe->varying_count; ++i) {
87 gl_varying_slot location = ss->varyings_loc[i];
88 int index = -1;
89
90 switch (location) {
91 case VARYING_SLOT_POS:
92 index = gl_Position;
93 break;
94 case VARYING_SLOT_PSIZ:
95 index = gl_PointSize;
96 break;
97 case VARYING_SLOT_PNTC:
98 index = gl_PointCoord;
99 break;
100 case VARYING_SLOT_FACE:
101 index = gl_FrontFacing;
102 break;
103 default:
104 index = general;
105 break;
106 }
107
108 assert(index >= 0);
109 out[i].index = index;
110 }
111 }
112
113 void
114 panfrost_emit_varying_descriptor(
115 struct panfrost_context *ctx,
116 unsigned vertex_count)
117 {
118 /* Load the shaders */
119
120 struct panfrost_shader_state *vs = &ctx->shader[PIPE_SHADER_VERTEX]->variants[ctx->shader[PIPE_SHADER_VERTEX]->active_variant];
121 struct panfrost_shader_state *fs = &ctx->shader[PIPE_SHADER_FRAGMENT]->variants[ctx->shader[PIPE_SHADER_FRAGMENT]->active_variant];
122 unsigned int num_gen_varyings = 0;
123
124 /* Allocate the varying descriptor */
125
126 size_t vs_size = sizeof(struct mali_attr_meta) * vs->tripipe->varying_count;
127 size_t fs_size = sizeof(struct mali_attr_meta) * fs->tripipe->varying_count;
128
129 struct panfrost_transfer trans = panfrost_allocate_transient(ctx,
130 vs_size + fs_size);
131
132 for (unsigned i = 0; i < vs->tripipe->varying_count; i++) {
133 if (!is_special_varying(vs->varyings_loc[i]))
134 vs->varyings[i].src_offset = 16 * (num_gen_varyings++);
135 }
136
137 for (unsigned i = 0; i < fs->tripipe->varying_count; i++) {
138 unsigned j;
139
140 /* If we have a point sprite replacement, handle that here. We
141 * have to translate location first. TODO: Flip y in shader.
142 * We're already keying ... just time crunch .. */
143
144 unsigned loc = fs->varyings_loc[i];
145 unsigned pnt_loc =
146 (loc >= VARYING_SLOT_VAR0) ? (loc - VARYING_SLOT_VAR0) :
147 (loc == VARYING_SLOT_PNTC) ? 8 :
148 ~0;
149
150 if (~pnt_loc && fs->point_sprite_mask & (1 << pnt_loc)) {
151 /* gl_PointCoord index by convention */
152 fs->varyings[i].index = 3;
153 fs->reads_point_coord = true;
154
155 /* Swizzle out the z/w to 0/1 */
156 fs->varyings[i].format = MALI_RG16F;
157 fs->varyings[i].swizzle =
158 panfrost_get_default_swizzle(2);
159
160 continue;
161 }
162
163 if (fs->varyings[i].index)
164 continue;
165
166 /*
167 * Re-use the VS general purpose varying pos if it exists,
168 * create a new one otherwise.
169 */
170 for (j = 0; j < vs->tripipe->varying_count; j++) {
171 if (fs->varyings_loc[i] == vs->varyings_loc[j])
172 break;
173 }
174
175 if (j < vs->tripipe->varying_count)
176 fs->varyings[i].src_offset = vs->varyings[j].src_offset;
177 else
178 fs->varyings[i].src_offset = 16 * (num_gen_varyings++);
179 }
180
181 memcpy(trans.cpu, vs->varyings, vs_size);
182 memcpy(trans.cpu + vs_size, fs->varyings, fs_size);
183
184 union mali_attr varyings[PIPE_MAX_ATTRIBS];
185
186 unsigned idx = 0;
187 signed general = idx++;
188 signed gl_Position = idx++;
189 signed gl_PointSize = vs->writes_point_size ? (idx++) : -1;
190 signed gl_PointCoord = fs->reads_point_coord ? (idx++) : -1;
191 signed gl_FrontFacing = fs->reads_face ? (idx++) : -1;
192
193 panfrost_emit_varyings(ctx, &varyings[general], num_gen_varyings * 16,
194 vertex_count);
195
196 /* fp32 vec4 gl_Position */
197 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.position_varying =
198 panfrost_emit_varyings(ctx, &varyings[gl_Position],
199 sizeof(float) * 4, vertex_count);
200
201
202 if (vs->writes_point_size)
203 ctx->payloads[PIPE_SHADER_FRAGMENT].primitive_size.pointer =
204 panfrost_emit_varyings(ctx, &varyings[gl_PointSize],
205 2, vertex_count);
206
207 if (fs->reads_point_coord)
208 panfrost_emit_point_coord(&varyings[gl_PointCoord]);
209
210 if (fs->reads_face)
211 panfrost_emit_front_face(&varyings[gl_FrontFacing]);
212
213 /* Let's go ahead and link varying meta to the buffer in question, now
214 * that that information is available */
215
216 panfrost_emit_varying_meta(trans.cpu, vs,
217 general, gl_Position, gl_PointSize,
218 gl_PointCoord, gl_FrontFacing);
219
220 panfrost_emit_varying_meta(trans.cpu + vs_size, fs,
221 general, gl_Position, gl_PointSize,
222 gl_PointCoord, gl_FrontFacing);
223
224 mali_ptr varyings_p = panfrost_upload_transient(ctx, &varyings, idx * sizeof(union mali_attr));
225 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varyings = varyings_p;
226 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varyings = varyings_p;
227
228 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varying_meta = trans.gpu;
229 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varying_meta = trans.gpu + vs_size;
230 }