panfrost: Move the const buf emission logic out of panfrost_emit_for_draw()

Let's move the constant buffer emission logic in a dedicated helper
to make panfrost_emit_for_draw() a bit more dry.

Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4083>
This commit is contained in:
Boris Brezillon
2020-03-05 09:46:42 +01:00
parent a72bab1c3e
commit 0b735a2d80
4 changed files with 293 additions and 258 deletions

View File

@@ -23,6 +23,7 @@
*/ */
#include "pan_allocate.h" #include "pan_allocate.h"
#include "pan_bo.h"
#include "pan_cmdstream.h" #include "pan_cmdstream.h"
#include "pan_context.h" #include "pan_context.h"
#include "pan_job.h" #include "pan_job.h"
@@ -142,3 +143,282 @@ panfrost_emit_viewport(struct panfrost_batch *batch,
tp->postfix.viewport = panfrost_upload_transient(batch, &mvp, tp->postfix.viewport = panfrost_upload_transient(batch, &mvp,
sizeof(mvp)); sizeof(mvp));
} }
static mali_ptr
panfrost_map_constant_buffer_gpu(struct panfrost_batch *batch,
enum pipe_shader_type st,
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) {
panfrost_batch_add_bo(batch, rsrc->bo,
PAN_BO_ACCESS_SHARED |
PAN_BO_ACCESS_READ |
panfrost_bo_access_for_stage(st));
/* Alignment gauranteed by
* PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT */
return rsrc->bo->gpu + cb->buffer_offset;
} else if (cb->user_buffer) {
return panfrost_upload_transient(batch,
cb->user_buffer +
cb->buffer_offset,
cb->buffer_size);
} else {
unreachable("No constant buffer");
}
}
struct sysval_uniform {
union {
float f[4];
int32_t i[4];
uint32_t u[4];
uint64_t du[2];
};
};
static void
panfrost_upload_viewport_scale_sysval(struct panfrost_batch *batch,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
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_batch *batch,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
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_batch *batch,
enum pipe_shader_type st,
unsigned int sysvalid,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
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_ssbo_sysval(struct panfrost_batch *batch,
enum pipe_shader_type st,
unsigned ssbo_id,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
assert(ctx->ssbo_mask[st] & (1 << ssbo_id));
struct pipe_shader_buffer sb = ctx->ssbo[st][ssbo_id];
/* Compute address */
struct panfrost_bo *bo = pan_resource(sb.buffer)->bo;
panfrost_batch_add_bo(batch, bo,
PAN_BO_ACCESS_SHARED | PAN_BO_ACCESS_RW |
panfrost_bo_access_for_stage(st));
/* Upload address and size as sysval */
uniform->du[0] = bo->gpu + sb.buffer_offset;
uniform->u[2] = sb.buffer_size;
}
static void
panfrost_upload_sampler_sysval(struct panfrost_batch *batch,
enum pipe_shader_type st,
unsigned samp_idx,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
struct pipe_sampler_state *sampl = &ctx->samplers[st][samp_idx]->base;
uniform->f[0] = sampl->min_lod;
uniform->f[1] = sampl->max_lod;
uniform->f[2] = sampl->lod_bias;
/* Even without any errata, Midgard represents "no mipmapping" as
* fixing the LOD with the clamps; keep behaviour consistent. c.f.
* panfrost_create_sampler_state which also explains our choice of
* epsilon value (again to keep behaviour consistent) */
if (sampl->min_mip_filter == PIPE_TEX_MIPFILTER_NONE)
uniform->f[1] = uniform->f[0] + (1.0/256.0);
}
static void
panfrost_upload_num_work_groups_sysval(struct panfrost_batch *batch,
struct sysval_uniform *uniform)
{
struct panfrost_context *ctx = batch->ctx;
uniform->u[0] = ctx->compute_grid->grid[0];
uniform->u[1] = ctx->compute_grid->grid[1];
uniform->u[2] = ctx->compute_grid->grid[2];
}
static void
panfrost_upload_sysvals(struct panfrost_batch *batch, 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(batch,
&uniforms[i]);
break;
case PAN_SYSVAL_VIEWPORT_OFFSET:
panfrost_upload_viewport_offset_sysval(batch,
&uniforms[i]);
break;
case PAN_SYSVAL_TEXTURE_SIZE:
panfrost_upload_txs_sysval(batch, st,
PAN_SYSVAL_ID(sysval),
&uniforms[i]);
break;
case PAN_SYSVAL_SSBO:
panfrost_upload_ssbo_sysval(batch, st,
PAN_SYSVAL_ID(sysval),
&uniforms[i]);
break;
case PAN_SYSVAL_NUM_WORK_GROUPS:
panfrost_upload_num_work_groups_sysval(batch,
&uniforms[i]);
break;
case PAN_SYSVAL_SAMPLER:
panfrost_upload_sampler_sysval(batch, 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");
}
void
panfrost_emit_const_buf(struct panfrost_batch *batch,
enum pipe_shader_type stage,
struct midgard_payload_vertex_tiler *vtp)
{
struct panfrost_context *ctx = batch->ctx;
struct panfrost_shader_variants *all = ctx->shader[stage];
if (!all)
return;
struct panfrost_constant_buffer *buf = &ctx->constant_buffer[stage];
struct panfrost_shader_state *ss = &all->variants[all->active_variant];
/* Uniforms are implicitly UBO #0 */
bool has_uniforms = buf->enabled_mask & (1 << 0);
/* Allocate room for the sysval and the uniforms */
size_t sys_size = sizeof(float) * 4 * ss->sysval_count;
size_t uniform_size = has_uniforms ? (buf->cb[0].buffer_size) : 0;
size_t size = sys_size + uniform_size;
struct panfrost_transfer transfer = panfrost_allocate_transient(batch,
size);
/* Upload sysvals requested by the shader */
panfrost_upload_sysvals(batch, transfer.cpu, ss, stage);
/* Upload uniforms */
if (has_uniforms && uniform_size) {
const void *cpu = panfrost_map_constant_buffer_cpu(buf, 0);
memcpy(transfer.cpu + sys_size, cpu, uniform_size);
}
struct mali_vertex_tiler_postfix *postfix = &vtp->postfix;
/* Next up, attach UBOs. UBO #0 is the uniforms we just
* uploaded */
unsigned ubo_count = panfrost_ubo_count(ctx, stage);
assert(ubo_count >= 1);
size_t sz = sizeof(uint64_t) * ubo_count;
uint64_t ubos[PAN_MAX_CONST_BUFFERS];
int uniform_count = ss->uniform_count;
/* Upload uniforms as a UBO */
ubos[0] = MALI_MAKE_UBO(2 + uniform_count, transfer.gpu);
/* The rest are honest-to-goodness UBOs */
for (unsigned ubo = 1; ubo < ubo_count; ++ubo) {
size_t usz = buf->cb[ubo].buffer_size;
bool enabled = buf->enabled_mask & (1 << ubo);
bool empty = usz == 0;
if (!enabled || empty) {
/* Stub out disabled UBOs to catch accesses */
ubos[ubo] = MALI_MAKE_UBO(0, 0xDEAD0000);
continue;
}
mali_ptr gpu = panfrost_map_constant_buffer_gpu(batch, stage,
buf, ubo);
unsigned bytes_per_field = 16;
unsigned aligned = ALIGN_POT(usz, bytes_per_field);
ubos[ubo] = MALI_MAKE_UBO(aligned / bytes_per_field, gpu);
}
mali_ptr ubufs = panfrost_upload_transient(batch, ubos, sz);
postfix->uniforms = transfer.gpu;
postfix->uniform_buffers = ubufs;
buf->dirty_mask = 0;
}

View File

@@ -25,6 +25,8 @@
#ifndef __PAN_CMDSTREAM_H__ #ifndef __PAN_CMDSTREAM_H__
#define __PAN_CMDSTREAM_H__ #define __PAN_CMDSTREAM_H__
#include "pipe/p_defines.h"
#include "panfrost-job.h" #include "panfrost-job.h"
#include "pan_job.h" #include "pan_job.h"
@@ -33,4 +35,9 @@ void
panfrost_emit_viewport(struct panfrost_batch *batch, panfrost_emit_viewport(struct panfrost_batch *batch,
struct midgard_payload_vertex_tiler *tp); struct midgard_payload_vertex_tiler *tp);
void
panfrost_emit_const_buf(struct panfrost_batch *batch,
enum pipe_shader_type stage,
struct midgard_payload_vertex_tiler *vtp);
#endif /* __PAN_CMDSTREAM_H__ */ #endif /* __PAN_CMDSTREAM_H__ */

View File

@@ -518,196 +518,12 @@ panfrost_upload_texture_descriptors(struct panfrost_context *ctx)
} }
} }
struct sysval_uniform {
union {
float f[4];
int32_t i[4];
uint32_t u[4];
uint64_t du[2];
};
};
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_ssbo_sysval(
struct panfrost_context *ctx,
enum pipe_shader_type st,
unsigned ssbo_id,
struct sysval_uniform *uniform)
{
assert(ctx->ssbo_mask[st] & (1 << ssbo_id));
struct pipe_shader_buffer sb = ctx->ssbo[st][ssbo_id];
/* Compute address */
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
struct panfrost_bo *bo = pan_resource(sb.buffer)->bo;
panfrost_batch_add_bo(batch, bo,
PAN_BO_ACCESS_SHARED | PAN_BO_ACCESS_RW |
panfrost_bo_access_for_stage(st));
/* Upload address and size as sysval */
uniform->du[0] = bo->gpu + sb.buffer_offset;
uniform->u[2] = sb.buffer_size;
}
static void
panfrost_upload_sampler_sysval(
struct panfrost_context *ctx,
enum pipe_shader_type st,
unsigned sampler_index,
struct sysval_uniform *uniform)
{
struct pipe_sampler_state *sampl =
&ctx->samplers[st][sampler_index]->base;
uniform->f[0] = sampl->min_lod;
uniform->f[1] = sampl->max_lod;
uniform->f[2] = sampl->lod_bias;
/* Even without any errata, Midgard represents "no mipmapping" as
* fixing the LOD with the clamps; keep behaviour consistent. c.f.
* panfrost_create_sampler_state which also explains our choice of
* epsilon value (again to keep behaviour consistent) */
if (sampl->min_mip_filter == PIPE_TEX_MIPFILTER_NONE)
uniform->f[1] = uniform->f[0] + (1.0/256.0);
}
static void panfrost_upload_num_work_groups_sysval(struct panfrost_context *ctx,
struct sysval_uniform *uniform)
{
uniform->u[0] = ctx->compute_grid->grid[0];
uniform->u[1] = ctx->compute_grid->grid[1];
uniform->u[2] = ctx->compute_grid->grid[2];
}
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;
case PAN_SYSVAL_SSBO:
panfrost_upload_ssbo_sysval(ctx, st, PAN_SYSVAL_ID(sysval),
&uniforms[i]);
break;
case PAN_SYSVAL_NUM_WORK_GROUPS:
panfrost_upload_num_work_groups_sysval(ctx, &uniforms[i]);
break;
case PAN_SYSVAL_SAMPLER:
panfrost_upload_sampler_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,
enum pipe_shader_type st,
struct panfrost_constant_buffer *buf,
unsigned index)
{
struct pipe_constant_buffer *cb = &buf->cb[index];
struct panfrost_resource *rsrc = pan_resource(cb->buffer);
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
if (rsrc) {
panfrost_batch_add_bo(batch, rsrc->bo,
PAN_BO_ACCESS_SHARED |
PAN_BO_ACCESS_READ |
panfrost_bo_access_for_stage(st));
/* Alignment gauranteed by PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT */
return rsrc->bo->gpu + cb->buffer_offset;
} else if (cb->user_buffer) {
return panfrost_upload_transient(batch, cb->user_buffer + cb->buffer_offset, cb->buffer_size);
} else {
unreachable("No constant buffer");
}
}
/* Compute number of UBOs active (more specifically, compute the highest UBO /* Compute number of UBOs active (more specifically, compute the highest UBO
* number addressable -- if there are gaps, include them in the count anyway). * 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 * We always include UBO #0 in the count, since we *need* uniforms enabled for
* sysvals. */ * sysvals. */
static unsigned unsigned
panfrost_ubo_count(struct panfrost_context *ctx, enum pipe_shader_type stage) panfrost_ubo_count(struct panfrost_context *ctx, enum pipe_shader_type stage)
{ {
unsigned mask = ctx->constant_buffer[stage].enabled_mask | 1; unsigned mask = ctx->constant_buffer[stage].enabled_mask | 1;
@@ -953,79 +769,8 @@ panfrost_emit_for_draw(struct panfrost_context *ctx, bool with_vertex_data)
panfrost_upload_sampler_descriptors(ctx); panfrost_upload_sampler_descriptors(ctx);
panfrost_upload_texture_descriptors(ctx); panfrost_upload_texture_descriptors(ctx);
for (int i = 0; i < PIPE_SHADER_TYPES; ++i) { for (int i = 0; i < PIPE_SHADER_TYPES; ++i)
struct panfrost_shader_variants *all = ctx->shader[i]; panfrost_emit_const_buf(batch, i, &ctx->payloads[i]);
if (!all)
continue;
struct panfrost_constant_buffer *buf = &ctx->constant_buffer[i];
struct panfrost_shader_state *ss = &all->variants[all->active_variant];
/* Uniforms are implicitly UBO #0 */
bool has_uniforms = buf->enabled_mask & (1 << 0);
/* Allocate room for the sysval and the uniforms */
size_t sys_size = sizeof(float) * 4 * ss->sysval_count;
size_t uniform_size = has_uniforms ? (buf->cb[0].buffer_size) : 0;
size_t size = sys_size + uniform_size;
struct panfrost_transfer transfer = panfrost_allocate_transient(batch, size);
/* Upload sysvals requested by the shader */
panfrost_upload_sysvals(ctx, transfer.cpu, ss, i);
/* Upload uniforms */
if (has_uniforms && uniform_size) {
const void *cpu = panfrost_map_constant_buffer_cpu(buf, 0);
memcpy(transfer.cpu + sys_size, cpu, uniform_size);
}
int uniform_count =
ctx->shader[i]->variants[ctx->shader[i]->active_variant].uniform_count;
struct mali_vertex_tiler_postfix *postfix =
&ctx->payloads[i].postfix;
/* Next up, attach UBOs. UBO #0 is the uniforms we just
* uploaded */
unsigned ubo_count = panfrost_ubo_count(ctx, i);
assert(ubo_count >= 1);
size_t sz = sizeof(uint64_t) * ubo_count;
uint64_t ubos[PAN_MAX_CONST_BUFFERS];
/* Upload uniforms as a UBO */
ubos[0] = MALI_MAKE_UBO(2 + uniform_count, transfer.gpu);
/* The rest are honest-to-goodness UBOs */
for (unsigned ubo = 1; ubo < ubo_count; ++ubo) {
size_t usz = buf->cb[ubo].buffer_size;
bool enabled = buf->enabled_mask & (1 << ubo);
bool empty = usz == 0;
if (!enabled || empty) {
/* Stub out disabled UBOs to catch accesses */
ubos[ubo] = MALI_MAKE_UBO(0, 0xDEAD0000);
continue;
}
mali_ptr gpu = panfrost_map_constant_buffer_gpu(ctx, i, buf, ubo);
unsigned bytes_per_field = 16;
unsigned aligned = ALIGN_POT(usz, bytes_per_field);
ubos[ubo] = MALI_MAKE_UBO(aligned / bytes_per_field, gpu);
}
mali_ptr ubufs = panfrost_upload_transient(batch, ubos, sz);
postfix->uniforms = transfer.gpu;
postfix->uniform_buffers = ubufs;
buf->dirty_mask = 0;
}
/* TODO: Upload the viewport somewhere more appropriate */ /* TODO: Upload the viewport somewhere more appropriate */

View File

@@ -330,6 +330,9 @@ panfrost_shader_compile(
struct panfrost_shader_state *state, struct panfrost_shader_state *state,
uint64_t *outputs_written); uint64_t *outputs_written);
unsigned
panfrost_ubo_count(struct panfrost_context *ctx, enum pipe_shader_type stage);
/* Instancing */ /* Instancing */
mali_ptr mali_ptr