panfrost: Break out pan_varyings.c
[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 void
62 panfrost_emit_varying_descriptor(
63 struct panfrost_context *ctx,
64 unsigned vertex_count)
65 {
66 /* Load the shaders */
67
68 struct panfrost_shader_state *vs = &ctx->shader[PIPE_SHADER_VERTEX]->variants[ctx->shader[PIPE_SHADER_VERTEX]->active_variant];
69 struct panfrost_shader_state *fs = &ctx->shader[PIPE_SHADER_FRAGMENT]->variants[ctx->shader[PIPE_SHADER_FRAGMENT]->active_variant];
70 unsigned int num_gen_varyings = 0;
71
72 /* Allocate the varying descriptor */
73
74 size_t vs_size = sizeof(struct mali_attr_meta) * vs->tripipe->varying_count;
75 size_t fs_size = sizeof(struct mali_attr_meta) * fs->tripipe->varying_count;
76
77 struct panfrost_transfer trans = panfrost_allocate_transient(ctx,
78 vs_size + fs_size);
79
80 /*
81 * Assign ->src_offset now that we know about all the general purpose
82 * varyings that will be used by the fragment and vertex shaders.
83 */
84 for (unsigned i = 0; i < vs->tripipe->varying_count; i++) {
85 /*
86 * General purpose varyings have ->index set to 0, skip other
87 * entries.
88 */
89 if (vs->varyings[i].index)
90 continue;
91
92 vs->varyings[i].src_offset = 16 * (num_gen_varyings++);
93 }
94
95 for (unsigned i = 0; i < fs->tripipe->varying_count; i++) {
96 unsigned j;
97
98 /* If we have a point sprite replacement, handle that here. We
99 * have to translate location first. TODO: Flip y in shader.
100 * We're already keying ... just time crunch .. */
101
102 unsigned loc = fs->varyings_loc[i];
103 unsigned pnt_loc =
104 (loc >= VARYING_SLOT_VAR0) ? (loc - VARYING_SLOT_VAR0) :
105 (loc == VARYING_SLOT_PNTC) ? 8 :
106 ~0;
107
108 if (~pnt_loc && fs->point_sprite_mask & (1 << pnt_loc)) {
109 /* gl_PointCoord index by convention */
110 fs->varyings[i].index = 3;
111 fs->reads_point_coord = true;
112
113 /* Swizzle out the z/w to 0/1 */
114 fs->varyings[i].format = MALI_RG16F;
115 fs->varyings[i].swizzle =
116 panfrost_get_default_swizzle(2);
117
118 continue;
119 }
120
121 if (fs->varyings[i].index)
122 continue;
123
124 /*
125 * Re-use the VS general purpose varying pos if it exists,
126 * create a new one otherwise.
127 */
128 for (j = 0; j < vs->tripipe->varying_count; j++) {
129 if (fs->varyings_loc[i] == vs->varyings_loc[j])
130 break;
131 }
132
133 if (j < vs->tripipe->varying_count)
134 fs->varyings[i].src_offset = vs->varyings[j].src_offset;
135 else
136 fs->varyings[i].src_offset = 16 * (num_gen_varyings++);
137 }
138
139 memcpy(trans.cpu, vs->varyings, vs_size);
140 memcpy(trans.cpu + vs_size, fs->varyings, fs_size);
141
142 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varying_meta = trans.gpu;
143 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varying_meta = trans.gpu + vs_size;
144
145 /* Buffer indices must be in this order per our convention */
146 union mali_attr varyings[PIPE_MAX_ATTRIBS];
147 unsigned idx = 0;
148
149 panfrost_emit_varyings(ctx, &varyings[idx++], num_gen_varyings * 16,
150 vertex_count);
151
152 /* fp32 vec4 gl_Position */
153 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.position_varying =
154 panfrost_emit_varyings(ctx, &varyings[idx++],
155 sizeof(float) * 4, vertex_count);
156
157
158 if (vs->writes_point_size || fs->reads_point_coord) {
159 /* fp16 vec1 gl_PointSize */
160 ctx->payloads[PIPE_SHADER_FRAGMENT].primitive_size.pointer =
161 panfrost_emit_varyings(ctx, &varyings[idx++],
162 2, vertex_count);
163 } else if (fs->reads_face) {
164 /* Dummy to advance index */
165 ++idx;
166 }
167
168 if (fs->reads_point_coord) {
169 /* Special descriptor */
170 panfrost_emit_point_coord(&varyings[idx++]);
171 } else if (fs->reads_face) {
172 ++idx;
173 }
174
175 if (fs->reads_face) {
176 panfrost_emit_front_face(&varyings[idx++]);
177 }
178
179 mali_ptr varyings_p = panfrost_upload_transient(ctx, &varyings, idx * sizeof(union mali_attr));
180 ctx->payloads[PIPE_SHADER_VERTEX].postfix.varyings = varyings_p;
181 ctx->payloads[PIPE_SHADER_FRAGMENT].postfix.varyings = varyings_p;
182 }