+static void
+panfrost_upload_sampler_descriptors(struct panfrost_context *ctx)
+{
+ size_t desc_size = sizeof(struct mali_sampler_descriptor);
+
+ for (int t = 0; t <= PIPE_SHADER_FRAGMENT; ++t) {
+ mali_ptr upload = 0;
+
+ if (ctx->sampler_count[t] && ctx->sampler_view_count[t]) {
+ size_t transfer_size = desc_size * ctx->sampler_count[t];
+
+ struct panfrost_transfer transfer =
+ panfrost_allocate_transient(ctx, transfer_size);
+
+ struct mali_sampler_descriptor *desc =
+ (struct mali_sampler_descriptor *) transfer.cpu;
+
+ for (int i = 0; i < ctx->sampler_count[t]; ++i)
+ desc[i] = ctx->samplers[t][i]->hw;
+
+ upload = transfer.gpu;
+ }
+
+ if (t == PIPE_SHADER_FRAGMENT)
+ ctx->payload_tiler.postfix.sampler_descriptor = upload;
+ else if (t == PIPE_SHADER_VERTEX)
+ ctx->payload_vertex.postfix.sampler_descriptor = upload;
+ else
+ assert(0);
+ }
+}
+
+/* Computes the address to a texture at a particular slice */
+
+static mali_ptr
+panfrost_get_texture_address(
+ struct panfrost_resource *rsrc,
+ unsigned level, unsigned face)
+{
+ unsigned level_offset = rsrc->bo->slices[level].offset;
+ unsigned face_offset = face * rsrc->bo->cubemap_stride;
+
+ return rsrc->bo->gpu + level_offset + face_offset;
+
+}
+
+static mali_ptr
+panfrost_upload_tex(
+ struct panfrost_context *ctx,
+ struct panfrost_sampler_view *view)
+{
+ if (!view)
+ return (mali_ptr) NULL;
+
+ struct pipe_sampler_view *pview = &view->base;
+ struct panfrost_resource *rsrc = pan_resource(pview->texture);
+
+ /* Do we interleave an explicit stride with every element? */
+
+ bool has_manual_stride =
+ view->hw.format.usage2 & MALI_TEX_MANUAL_STRIDE;
+
+ /* For easy access */
+
+ assert(pview->target != PIPE_BUFFER);
+ unsigned first_level = pview->u.tex.first_level;
+ unsigned last_level = pview->u.tex.last_level;
+
+ /* Inject the addresses in, interleaving mip levels, cube faces, and
+ * strides in that order */
+
+ unsigned idx = 0;
+
+ for (unsigned l = first_level; l <= last_level; ++l) {
+ for (unsigned f = 0; f < pview->texture->array_size; ++f) {
+ view->hw.payload[idx++] =
+ panfrost_get_texture_address(rsrc, l, f);
+
+ if (has_manual_stride) {
+ view->hw.payload[idx++] =
+ rsrc->bo->slices[l].stride;
+ }
+ }
+ }
+
+ return panfrost_upload_transient(ctx, &view->hw,
+ sizeof(struct mali_texture_descriptor));
+}
+
+static void
+panfrost_upload_texture_descriptors(struct panfrost_context *ctx)
+{
+ for (int t = 0; t <= PIPE_SHADER_FRAGMENT; ++t) {
+ mali_ptr trampoline = 0;
+
+ if (ctx->sampler_view_count[t]) {
+ uint64_t trampolines[PIPE_MAX_SHADER_SAMPLER_VIEWS];
+
+ for (int i = 0; i < ctx->sampler_view_count[t]; ++i)
+ trampolines[i] =
+ panfrost_upload_tex(ctx, ctx->sampler_views[t][i]);
+
+ trampoline = panfrost_upload_transient(ctx, trampolines, sizeof(uint64_t) * ctx->sampler_view_count[t]);
+ }
+
+ if (t == PIPE_SHADER_FRAGMENT)
+ ctx->payload_tiler.postfix.texture_trampoline = trampoline;
+ else if (t == PIPE_SHADER_VERTEX)
+ ctx->payload_vertex.postfix.texture_trampoline = trampoline;
+ else
+ assert(0);
+ }
+}
+
+struct sysval_uniform {
+ union {
+ float f[4];
+ int32_t i[4];
+ uint32_t u[4];
+ };
+};
+
+static void panfrost_upload_viewport_scale_sysval(struct panfrost_context *ctx,
+ struct sysval_uniform *uniform)
+{
+ const struct pipe_viewport_state *vp = &ctx->pipe_viewport;
+
+ uniform->f[0] = vp->scale[0];
+ uniform->f[1] = vp->scale[1];
+ uniform->f[2] = vp->scale[2];
+}
+
+static void panfrost_upload_viewport_offset_sysval(struct panfrost_context *ctx,
+ struct sysval_uniform *uniform)
+{
+ const struct pipe_viewport_state *vp = &ctx->pipe_viewport;
+
+ uniform->f[0] = vp->translate[0];
+ uniform->f[1] = vp->translate[1];
+ uniform->f[2] = vp->translate[2];
+}
+
+static void panfrost_upload_txs_sysval(struct panfrost_context *ctx,
+ enum pipe_shader_type st,
+ unsigned int sysvalid,
+ struct sysval_uniform *uniform)
+{
+ unsigned texidx = PAN_SYSVAL_ID_TO_TXS_TEX_IDX(sysvalid);
+ unsigned dim = PAN_SYSVAL_ID_TO_TXS_DIM(sysvalid);
+ bool is_array = PAN_SYSVAL_ID_TO_TXS_IS_ARRAY(sysvalid);
+ struct pipe_sampler_view *tex = &ctx->sampler_views[st][texidx]->base;
+
+ assert(dim);
+ uniform->i[0] = u_minify(tex->texture->width0, tex->u.tex.first_level);
+
+ if (dim > 1)
+ uniform->i[1] = u_minify(tex->texture->height0,
+ tex->u.tex.first_level);
+
+ if (dim > 2)
+ uniform->i[2] = u_minify(tex->texture->depth0,
+ tex->u.tex.first_level);
+
+ if (is_array)
+ uniform->i[dim] = tex->texture->array_size;
+}
+
+static void panfrost_upload_sysvals(struct panfrost_context *ctx, void *buf,
+ struct panfrost_shader_state *ss,
+ enum pipe_shader_type st)
+{
+ struct sysval_uniform *uniforms = (void *)buf;
+
+ for (unsigned i = 0; i < ss->sysval_count; ++i) {
+ int sysval = ss->sysval[i];
+
+ switch (PAN_SYSVAL_TYPE(sysval)) {
+ case PAN_SYSVAL_VIEWPORT_SCALE:
+ panfrost_upload_viewport_scale_sysval(ctx, &uniforms[i]);
+ break;
+ case PAN_SYSVAL_VIEWPORT_OFFSET:
+ panfrost_upload_viewport_offset_sysval(ctx, &uniforms[i]);
+ break;
+ case PAN_SYSVAL_TEXTURE_SIZE:
+ panfrost_upload_txs_sysval(ctx, st, PAN_SYSVAL_ID(sysval),
+ &uniforms[i]);
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+static const void *
+panfrost_map_constant_buffer_cpu(struct panfrost_constant_buffer *buf, unsigned index)
+{
+ struct pipe_constant_buffer *cb = &buf->cb[index];
+ struct panfrost_resource *rsrc = pan_resource(cb->buffer);
+
+ if (rsrc)
+ return rsrc->bo->cpu;
+ else if (cb->user_buffer)
+ return cb->user_buffer;
+ else
+ unreachable("No constant buffer");
+}
+
+static mali_ptr
+panfrost_map_constant_buffer_gpu(
+ struct panfrost_context *ctx,
+ struct panfrost_constant_buffer *buf,
+ unsigned index)
+{
+ struct pipe_constant_buffer *cb = &buf->cb[index];
+ struct panfrost_resource *rsrc = pan_resource(cb->buffer);
+
+ if (rsrc)
+ return rsrc->bo->gpu;
+ else if (cb->user_buffer)
+ return panfrost_upload_transient(ctx, cb->user_buffer, cb->buffer_size);
+ else
+ unreachable("No constant buffer");
+}
+
+/* Compute number of UBOs active (more specifically, compute the highest UBO
+ * number addressable -- if there are gaps, include them in the count anyway).
+ * We always include UBO #0 in the count, since we *need* uniforms enabled for
+ * sysvals. */
+
+static unsigned
+panfrost_ubo_count(struct panfrost_context *ctx, enum pipe_shader_type stage)
+{
+ unsigned mask = ctx->constant_buffer[stage].enabled_mask | 1;
+ return 32 - __builtin_clz(mask);
+}
+
+/* Fixes up a shader state with current state, returning a GPU address to the
+ * patched shader */
+
+static mali_ptr
+panfrost_patch_shader_state(
+ struct panfrost_context *ctx,
+ struct panfrost_shader_state *ss,
+ enum pipe_shader_type stage)
+{
+ ss->tripipe->texture_count = ctx->sampler_view_count[stage];
+ ss->tripipe->sampler_count = ctx->sampler_count[stage];
+
+ ss->tripipe->midgard1.flags = 0x220;
+
+ unsigned ubo_count = panfrost_ubo_count(ctx, stage);
+ ss->tripipe->midgard1.uniform_buffer_count = ubo_count;
+
+ return ss->tripipe_gpu;
+}
+