+static mali_ptr
+panfrost_emit_varyings(
+ struct panfrost_context *ctx,
+ union mali_attr *slot,
+ unsigned stride,
+ unsigned count)
+{
+ mali_ptr varying_address = ctx->varying_mem.gpu + ctx->varying_height;
+
+ /* Fill out the descriptor */
+ slot->elements = varying_address | MALI_ATTR_LINEAR;
+ slot->stride = stride;
+ slot->size = stride * count;
+
+ ctx->varying_height += ALIGN(slot->size, 64);
+ assert(ctx->varying_height < ctx->varying_mem.size);
+
+ return varying_address;
+}
+
+static void
+panfrost_emit_point_coord(union mali_attr *slot)
+{
+ slot->elements = MALI_VARYING_POINT_COORD | MALI_ATTR_LINEAR;
+ slot->stride = slot->size = 0;
+}
+
+static void
+panfrost_emit_varying_descriptor(
+ struct panfrost_context *ctx,
+ unsigned invocation_count)
+{
+ /* Load the shaders */
+
+ struct panfrost_shader_state *vs = &ctx->vs->variants[ctx->vs->active_variant];
+ struct panfrost_shader_state *fs = &ctx->fs->variants[ctx->fs->active_variant];
+
+ /* Allocate the varying descriptor */
+
+ size_t vs_size = sizeof(struct mali_attr_meta) * vs->tripipe->varying_count;
+ size_t fs_size = sizeof(struct mali_attr_meta) * fs->tripipe->varying_count;
+
+ struct panfrost_transfer trans = panfrost_allocate_transient(ctx,
+ vs_size + fs_size);
+
+ memcpy(trans.cpu, vs->varyings, vs_size);
+ memcpy(trans.cpu + vs_size, fs->varyings, fs_size);
+
+ ctx->payload_vertex.postfix.varying_meta = trans.gpu;
+ ctx->payload_tiler.postfix.varying_meta = trans.gpu + vs_size;
+
+ /* Buffer indices must be in this order per our convention */
+ union mali_attr varyings[PIPE_MAX_ATTRIBS];
+ unsigned idx = 0;
+
+ /* General varyings -- use the VS's, since those are more likely to be
+ * accurate on desktop */
+
+ panfrost_emit_varyings(ctx, &varyings[idx++],
+ vs->general_varying_stride, invocation_count);
+
+ /* fp32 vec4 gl_Position */
+ ctx->payload_tiler.postfix.position_varying =
+ panfrost_emit_varyings(ctx, &varyings[idx++],
+ sizeof(float) * 4, invocation_count);
+
+
+ if (vs->writes_point_size || fs->reads_point_coord) {
+ /* fp16 vec1 gl_PointSize */
+ ctx->payload_tiler.primitive_size.pointer =
+ panfrost_emit_varyings(ctx, &varyings[idx++],
+ 2, invocation_count);
+ }
+
+ if (fs->reads_point_coord) {
+ /* Special descriptor */
+ panfrost_emit_point_coord(&varyings[idx++]);
+ }
+
+ mali_ptr varyings_p = panfrost_upload_transient(ctx, &varyings, idx * sizeof(union mali_attr));
+ ctx->payload_vertex.postfix.varyings = varyings_p;
+ ctx->payload_tiler.postfix.varyings = varyings_p;
+}
+