panfrost: Move draw_vbo to pan_cmdstream.c
This needs to be conditionally compiled per-generation. Signed-off-by: Alyssa Rosenzweig <alyssa@collabora.com> Acked-by: Boris Brezillon <boris.brezillon@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11745>
This commit is contained in:
committed by
Marge Bot
parent
265a900229
commit
a13eb5fcc5
@@ -27,6 +27,8 @@
|
||||
#include "util/u_prim.h"
|
||||
#include "util/u_vbuf.h"
|
||||
#include "util/u_helpers.h"
|
||||
#include "util/u_draw.h"
|
||||
#include "indices/u_primconvert.h"
|
||||
|
||||
#include "panfrost-quirks.h"
|
||||
|
||||
@@ -37,6 +39,8 @@
|
||||
#include "pan_job.h"
|
||||
#include "pan_shader.h"
|
||||
#include "pan_texture.h"
|
||||
#include "pan_util.h"
|
||||
#include "pan_indirect_draw.h"
|
||||
|
||||
/* Statically assert that PIPE_* enums match the hardware enums.
|
||||
* (As long as they match, we don't need to translate them.)
|
||||
@@ -2453,3 +2457,664 @@ panfrost_emit_fragment_job(struct panfrost_batch *batch,
|
||||
|
||||
return transfer.gpu;
|
||||
}
|
||||
|
||||
#define DEFINE_CASE(c) case PIPE_PRIM_##c: return MALI_DRAW_MODE_##c;
|
||||
|
||||
static uint8_t
|
||||
pan_draw_mode(enum pipe_prim_type mode)
|
||||
{
|
||||
switch (mode) {
|
||||
DEFINE_CASE(POINTS);
|
||||
DEFINE_CASE(LINES);
|
||||
DEFINE_CASE(LINE_LOOP);
|
||||
DEFINE_CASE(LINE_STRIP);
|
||||
DEFINE_CASE(TRIANGLES);
|
||||
DEFINE_CASE(TRIANGLE_STRIP);
|
||||
DEFINE_CASE(TRIANGLE_FAN);
|
||||
DEFINE_CASE(QUADS);
|
||||
DEFINE_CASE(QUAD_STRIP);
|
||||
DEFINE_CASE(POLYGON);
|
||||
|
||||
default:
|
||||
unreachable("Invalid draw mode");
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEFINE_CASE
|
||||
|
||||
/* Count generated primitives (when there is no geom/tess shaders) for
|
||||
* transform feedback */
|
||||
|
||||
static void
|
||||
panfrost_statistics_record(
|
||||
struct panfrost_context *ctx,
|
||||
const struct pipe_draw_info *info,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
if (!ctx->active_queries)
|
||||
return;
|
||||
|
||||
uint32_t prims = u_prims_for_vertices(info->mode, draw->count);
|
||||
ctx->prims_generated += prims;
|
||||
|
||||
if (!ctx->streamout.num_targets)
|
||||
return;
|
||||
|
||||
ctx->tf_prims_generated += prims;
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_streamout_offsets(struct panfrost_context *ctx)
|
||||
{
|
||||
for (unsigned i = 0; i < ctx->streamout.num_targets; ++i) {
|
||||
unsigned count;
|
||||
|
||||
count = u_stream_outputs_for_vertices(ctx->active_prim,
|
||||
ctx->vertex_count);
|
||||
pan_so_target(ctx->streamout.targets[i])->offset += count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
pan_emit_draw_descs(struct panfrost_batch *batch,
|
||||
struct MALI_DRAW *d, enum pipe_shader_type st)
|
||||
{
|
||||
d->offset_start = batch->ctx->offset_start;
|
||||
d->instance_size = batch->ctx->instance_count > 1 ?
|
||||
batch->ctx->padded_count : 1;
|
||||
|
||||
d->uniform_buffers = batch->uniform_buffers[st];
|
||||
d->push_uniforms = batch->push_uniforms[st];
|
||||
d->textures = batch->textures[st];
|
||||
d->samplers = batch->samplers[st];
|
||||
}
|
||||
|
||||
static inline enum mali_index_type
|
||||
panfrost_translate_index_size(unsigned size)
|
||||
{
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_NONE == 0);
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_UINT8 == 1);
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_UINT16 == 2);
|
||||
|
||||
return (size == 4) ? MALI_INDEX_TYPE_UINT32 : size;
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_emit_vertex(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
void *invocation_template,
|
||||
mali_ptr vs_vary, mali_ptr varyings,
|
||||
mali_ptr attribs, mali_ptr attrib_bufs,
|
||||
void *job)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
void *section =
|
||||
pan_section_ptr(job, COMPUTE_JOB, INVOCATION);
|
||||
memcpy(section, invocation_template, MALI_INVOCATION_LENGTH);
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, PARAMETERS, cfg) {
|
||||
cfg.job_task_split = 5;
|
||||
}
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, DRAW, cfg) {
|
||||
cfg.draw_descriptor_is_64b = true;
|
||||
if (!pan_is_bifrost(device))
|
||||
cfg.texture_descriptor_is_64b = true;
|
||||
cfg.state = batch->rsd[PIPE_SHADER_VERTEX];
|
||||
cfg.attributes = attribs;
|
||||
cfg.attribute_buffers = attrib_bufs;
|
||||
cfg.varyings = vs_vary;
|
||||
cfg.varying_buffers = vs_vary ? varyings : 0;
|
||||
cfg.thread_storage = batch->tls.gpu;
|
||||
pan_emit_draw_descs(batch, &cfg, PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, DRAW_PADDING, cfg);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_emit_primitive_size(struct panfrost_context *ctx,
|
||||
bool points, mali_ptr size_array,
|
||||
void *prim_size)
|
||||
{
|
||||
struct panfrost_rasterizer *rast = ctx->rasterizer;
|
||||
|
||||
pan_pack(prim_size, PRIMITIVE_SIZE, cfg) {
|
||||
if (panfrost_writes_point_size(ctx)) {
|
||||
cfg.size_array = size_array;
|
||||
} else {
|
||||
cfg.constant = points ?
|
||||
rast->base.point_size :
|
||||
rast->base.line_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
panfrost_is_implicit_prim_restart(const struct pipe_draw_info *info)
|
||||
{
|
||||
unsigned implicit_index = (1 << (info->index_size * 8)) - 1;
|
||||
bool implicit = info->restart_index == implicit_index;
|
||||
return info->primitive_restart && implicit;
|
||||
}
|
||||
|
||||
static inline void
|
||||
panfrost_update_state_tex(struct panfrost_batch *batch,
|
||||
enum pipe_shader_type st)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, st);
|
||||
|
||||
unsigned dirty_3d = ctx->dirty;
|
||||
unsigned dirty = ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_TEXTURE) {
|
||||
batch->textures[st] =
|
||||
panfrost_emit_texture_descriptors(batch, st);
|
||||
}
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_SAMPLER) {
|
||||
batch->samplers[st] =
|
||||
panfrost_emit_sampler_descriptors(batch, st);
|
||||
}
|
||||
|
||||
if ((dirty & ss->dirty_shader) || (dirty_3d & ss->dirty_3d)) {
|
||||
batch->uniform_buffers[st] = panfrost_emit_const_buf(batch, st,
|
||||
&batch->push_uniforms[st]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
panfrost_update_state_3d(struct panfrost_batch *batch)
|
||||
{
|
||||
unsigned dirty = batch->ctx->dirty;
|
||||
|
||||
if (dirty & (PAN_DIRTY_VIEWPORT | PAN_DIRTY_SCISSOR))
|
||||
batch->viewport = panfrost_emit_viewport(batch);
|
||||
|
||||
if (dirty & PAN_DIRTY_TLS_SIZE)
|
||||
panfrost_batch_adjust_stack_size(batch);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_state_vs(struct panfrost_batch *batch)
|
||||
{
|
||||
enum pipe_shader_type st = PIPE_SHADER_VERTEX;
|
||||
unsigned dirty = batch->ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_RENDERER)
|
||||
batch->rsd[st] = panfrost_emit_compute_shader_meta(batch, st);
|
||||
|
||||
panfrost_update_state_tex(batch, st);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_state_fs(struct panfrost_batch *batch)
|
||||
{
|
||||
enum pipe_shader_type st = PIPE_SHADER_FRAGMENT;
|
||||
unsigned dirty = batch->ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_RENDERER)
|
||||
batch->rsd[st] = panfrost_emit_frag_shader_meta(batch);
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_IMAGE) {
|
||||
batch->attribs[st] = panfrost_emit_image_attribs(batch,
|
||||
&batch->attrib_bufs[st], st);
|
||||
}
|
||||
|
||||
panfrost_update_state_tex(batch, st);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_emit_tiler(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
const struct pipe_draw_start_count_bias *draw,
|
||||
void *invocation_template,
|
||||
mali_ptr indices, mali_ptr fs_vary, mali_ptr varyings,
|
||||
mali_ptr pos, mali_ptr psiz, void *job)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct pipe_rasterizer_state *rast = &ctx->rasterizer->base;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
void *section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, INVOCATION) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, INVOCATION);
|
||||
memcpy(section, invocation_template, MALI_INVOCATION_LENGTH);
|
||||
|
||||
section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, PRIMITIVE) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, PRIMITIVE);
|
||||
pan_pack(section, PRIMITIVE, cfg) {
|
||||
cfg.draw_mode = pan_draw_mode(info->mode);
|
||||
if (panfrost_writes_point_size(ctx))
|
||||
cfg.point_size_array_format = MALI_POINT_SIZE_ARRAY_FORMAT_FP16;
|
||||
|
||||
/* For line primitives, PRIMITIVE.first_provoking_vertex must
|
||||
* be set to true and the provoking vertex is selected with
|
||||
* DRAW.flat_shading_vertex.
|
||||
*/
|
||||
if (info->mode == PIPE_PRIM_LINES ||
|
||||
info->mode == PIPE_PRIM_LINE_LOOP ||
|
||||
info->mode == PIPE_PRIM_LINE_STRIP)
|
||||
cfg.first_provoking_vertex = true;
|
||||
else
|
||||
cfg.first_provoking_vertex = rast->flatshade_first;
|
||||
|
||||
if (panfrost_is_implicit_prim_restart(info)) {
|
||||
cfg.primitive_restart = MALI_PRIMITIVE_RESTART_IMPLICIT;
|
||||
} else if (info->primitive_restart) {
|
||||
cfg.primitive_restart = MALI_PRIMITIVE_RESTART_EXPLICIT;
|
||||
cfg.primitive_restart_index = info->restart_index;
|
||||
}
|
||||
|
||||
cfg.job_task_split = 6;
|
||||
|
||||
cfg.index_count = ctx->indirect_draw ? 1 : draw->count;
|
||||
cfg.index_type = panfrost_translate_index_size(info->index_size);
|
||||
|
||||
if (cfg.index_type) {
|
||||
cfg.indices = indices;
|
||||
cfg.base_vertex_offset = draw->index_bias - ctx->offset_start;
|
||||
}
|
||||
}
|
||||
|
||||
bool points = info->mode == PIPE_PRIM_POINTS;
|
||||
void *prim_size = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, PRIMITIVE_SIZE) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, PRIMITIVE_SIZE);
|
||||
|
||||
if (pan_is_bifrost(device)) {
|
||||
panfrost_emit_primitive_size(ctx, points, psiz, prim_size);
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, TILER, cfg) {
|
||||
cfg.address = panfrost_batch_get_bifrost_tiler(batch, ~0);
|
||||
}
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, PADDING, padding) {}
|
||||
}
|
||||
|
||||
section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, DRAW) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, DRAW);
|
||||
pan_pack(section, DRAW, cfg) {
|
||||
cfg.four_components_per_vertex = true;
|
||||
cfg.draw_descriptor_is_64b = true;
|
||||
if (!pan_is_bifrost(device))
|
||||
cfg.texture_descriptor_is_64b = true;
|
||||
cfg.front_face_ccw = rast->front_ccw;
|
||||
cfg.cull_front_face = rast->cull_face & PIPE_FACE_FRONT;
|
||||
cfg.cull_back_face = rast->cull_face & PIPE_FACE_BACK;
|
||||
cfg.position = pos;
|
||||
cfg.state = batch->rsd[PIPE_SHADER_FRAGMENT];
|
||||
cfg.attributes = batch->attribs[PIPE_SHADER_FRAGMENT];
|
||||
cfg.attribute_buffers = batch->attrib_bufs[PIPE_SHADER_FRAGMENT];
|
||||
cfg.viewport = batch->viewport;
|
||||
cfg.varyings = fs_vary;
|
||||
cfg.varying_buffers = fs_vary ? varyings : 0;
|
||||
cfg.thread_storage = batch->tls.gpu;
|
||||
|
||||
/* For all primitives but lines DRAW.flat_shading_vertex must
|
||||
* be set to 0 and the provoking vertex is selected with the
|
||||
* PRIMITIVE.first_provoking_vertex field.
|
||||
*/
|
||||
if (info->mode == PIPE_PRIM_LINES ||
|
||||
info->mode == PIPE_PRIM_LINE_LOOP ||
|
||||
info->mode == PIPE_PRIM_LINE_STRIP) {
|
||||
/* The logic is inverted on bifrost. */
|
||||
cfg.flat_shading_vertex =
|
||||
pan_is_bifrost(device) ?
|
||||
rast->flatshade_first : !rast->flatshade_first;
|
||||
}
|
||||
|
||||
pan_emit_draw_descs(batch, &cfg, PIPE_SHADER_FRAGMENT);
|
||||
|
||||
if (ctx->occlusion_query && ctx->active_queries) {
|
||||
if (ctx->occlusion_query->type == PIPE_QUERY_OCCLUSION_COUNTER)
|
||||
cfg.occlusion_query = MALI_OCCLUSION_MODE_COUNTER;
|
||||
else
|
||||
cfg.occlusion_query = MALI_OCCLUSION_MODE_PREDICATE;
|
||||
|
||||
struct panfrost_resource *rsrc = pan_resource(ctx->occlusion_query->rsrc);
|
||||
cfg.occlusion = rsrc->image.data.bo->ptr.gpu;
|
||||
panfrost_batch_write_rsrc(ctx->batch, rsrc,
|
||||
PIPE_SHADER_FRAGMENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pan_is_bifrost(device))
|
||||
panfrost_emit_primitive_size(ctx, points, psiz, prim_size);
|
||||
else
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, DRAW_PADDING, cfg);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_direct_draw(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
if (!draw->count || !info->instance_count)
|
||||
return;
|
||||
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
/* Fallback for unsupported modes */
|
||||
if (!(ctx->draw_modes & BITFIELD_BIT(info->mode))) {
|
||||
if (draw->count < 4) {
|
||||
/* Degenerate case? */
|
||||
return;
|
||||
}
|
||||
|
||||
util_primconvert_save_rasterizer_state(ctx->primconvert, &ctx->rasterizer->base);
|
||||
util_primconvert_draw_vbo(ctx->primconvert, info, drawid_offset, NULL, draw, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take into account a negative bias */
|
||||
ctx->indirect_draw = false;
|
||||
ctx->vertex_count = draw->count + (info->index_size ? abs(draw->index_bias) : 0);
|
||||
ctx->instance_count = info->instance_count;
|
||||
ctx->base_vertex = info->index_size ? draw->index_bias : 0;
|
||||
ctx->base_instance = info->start_instance;
|
||||
ctx->active_prim = info->mode;
|
||||
ctx->drawid = drawid_offset;
|
||||
|
||||
struct panfrost_ptr tiler =
|
||||
pan_is_bifrost(device) ?
|
||||
pan_pool_alloc_desc(&batch->pool.base, BIFROST_TILER_JOB) :
|
||||
pan_pool_alloc_desc(&batch->pool.base, MIDGARD_TILER_JOB);
|
||||
struct panfrost_ptr vertex =
|
||||
pan_pool_alloc_desc(&batch->pool.base, COMPUTE_JOB);
|
||||
|
||||
unsigned vertex_count = ctx->vertex_count;
|
||||
|
||||
unsigned min_index = 0, max_index = 0;
|
||||
mali_ptr indices = 0;
|
||||
|
||||
if (info->index_size) {
|
||||
indices = panfrost_get_index_buffer_bounded(batch, info, draw,
|
||||
&min_index,
|
||||
&max_index);
|
||||
|
||||
/* Use the corresponding values */
|
||||
vertex_count = max_index - min_index + 1;
|
||||
ctx->offset_start = min_index + draw->index_bias;
|
||||
} else {
|
||||
ctx->offset_start = draw->start;
|
||||
}
|
||||
|
||||
if (info->instance_count > 1)
|
||||
ctx->padded_count = panfrost_padded_vertex_count(vertex_count);
|
||||
else
|
||||
ctx->padded_count = vertex_count;
|
||||
|
||||
panfrost_statistics_record(ctx, info, draw);
|
||||
|
||||
struct mali_invocation_packed invocation;
|
||||
if (info->instance_count > 1) {
|
||||
panfrost_pack_work_groups_compute(&invocation,
|
||||
1, vertex_count, info->instance_count,
|
||||
1, 1, 1, true, false);
|
||||
} else {
|
||||
pan_pack(&invocation, INVOCATION, cfg) {
|
||||
cfg.invocations = MALI_POSITIVE(vertex_count);
|
||||
cfg.size_y_shift = 0;
|
||||
cfg.size_z_shift = 0;
|
||||
cfg.workgroups_x_shift = 0;
|
||||
cfg.workgroups_y_shift = 0;
|
||||
cfg.workgroups_z_shift = 32;
|
||||
cfg.thread_group_split = MALI_SPLIT_MIN_EFFICIENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit all sort of descriptors. */
|
||||
mali_ptr varyings = 0, vs_vary = 0, fs_vary = 0, pos = 0, psiz = 0;
|
||||
|
||||
panfrost_emit_varying_descriptor(batch,
|
||||
ctx->padded_count *
|
||||
ctx->instance_count,
|
||||
&vs_vary, &fs_vary, &varyings,
|
||||
NULL, &pos, &psiz,
|
||||
info->mode == PIPE_PRIM_POINTS);
|
||||
|
||||
mali_ptr attribs, attrib_bufs;
|
||||
attribs = panfrost_emit_vertex_data(batch, &attrib_bufs);
|
||||
|
||||
panfrost_update_state_3d(batch);
|
||||
panfrost_update_state_vs(batch);
|
||||
panfrost_update_state_fs(batch);
|
||||
panfrost_clean_state_3d(ctx);
|
||||
|
||||
/* Fire off the draw itself */
|
||||
panfrost_draw_emit_vertex(batch, info, &invocation,
|
||||
vs_vary, varyings, attribs, attrib_bufs, vertex.cpu);
|
||||
panfrost_draw_emit_tiler(batch, info, draw, &invocation, indices,
|
||||
fs_vary, varyings, pos, psiz, tiler.cpu);
|
||||
panfrost_emit_vertex_tiler_jobs(batch, &vertex, &tiler);
|
||||
|
||||
/* Increment transform feedback offsets */
|
||||
panfrost_update_streamout_offsets(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_indirect_draw(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_indirect_info *indirect,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
/* Indirect draw count and multi-draw not supported. */
|
||||
assert(indirect->draw_count == 1 && !indirect->indirect_draw_count);
|
||||
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *dev = pan_device(ctx->base.screen);
|
||||
|
||||
/* TODO: update statistics (see panfrost_statistics_record()) */
|
||||
/* TODO: Increment transform feedback offsets */
|
||||
assert(ctx->streamout.num_targets == 0);
|
||||
|
||||
assert(ctx->draw_modes & (1 << info->mode));
|
||||
ctx->active_prim = info->mode;
|
||||
ctx->drawid = drawid_offset;
|
||||
ctx->indirect_draw = true;
|
||||
|
||||
struct panfrost_ptr tiler =
|
||||
pan_pool_alloc_aligned(&batch->pool.base,
|
||||
pan_is_bifrost(dev) ?
|
||||
MALI_BIFROST_TILER_JOB_LENGTH :
|
||||
MALI_MIDGARD_TILER_JOB_LENGTH,
|
||||
64);
|
||||
struct panfrost_ptr vertex =
|
||||
pan_pool_alloc_aligned(&batch->pool.base,
|
||||
MALI_COMPUTE_JOB_LENGTH,
|
||||
64);
|
||||
|
||||
struct panfrost_shader_state *vs =
|
||||
panfrost_get_shader_state(ctx, PIPE_SHADER_VERTEX);
|
||||
|
||||
struct panfrost_bo *index_buf = NULL;
|
||||
|
||||
if (info->index_size) {
|
||||
assert(!info->has_user_indices);
|
||||
struct panfrost_resource *rsrc = pan_resource(info->index.resource);
|
||||
index_buf = rsrc->image.data.bo;
|
||||
panfrost_batch_read_rsrc(batch, rsrc, PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
mali_ptr varyings = 0, vs_vary = 0, fs_vary = 0, pos = 0, psiz = 0;
|
||||
unsigned varying_buf_count;
|
||||
|
||||
/* We want to create templates, set all count fields to 0 to reflect
|
||||
* that.
|
||||
*/
|
||||
ctx->instance_count = ctx->vertex_count = ctx->padded_count = 0;
|
||||
ctx->offset_start = 0;
|
||||
|
||||
/* Set the {first,base}_vertex sysvals to NULL. Will be updated if the
|
||||
* vertex shader uses gl_VertexID or gl_BaseVertex.
|
||||
*/
|
||||
ctx->first_vertex_sysval_ptr = 0;
|
||||
ctx->base_vertex_sysval_ptr = 0;
|
||||
ctx->base_instance_sysval_ptr = 0;
|
||||
|
||||
panfrost_update_state_3d(batch);
|
||||
panfrost_update_state_vs(batch);
|
||||
panfrost_update_state_fs(batch);
|
||||
panfrost_clean_state_3d(ctx);
|
||||
|
||||
bool point_coord_replace = (info->mode == PIPE_PRIM_POINTS);
|
||||
|
||||
panfrost_emit_varying_descriptor(batch, 0,
|
||||
&vs_vary, &fs_vary, &varyings,
|
||||
&varying_buf_count, &pos, &psiz,
|
||||
point_coord_replace);
|
||||
|
||||
mali_ptr attribs, attrib_bufs;
|
||||
attribs = panfrost_emit_vertex_data(batch, &attrib_bufs);
|
||||
|
||||
/* Zero-ed invocation, the compute job will update it. */
|
||||
static struct mali_invocation_packed invocation;
|
||||
|
||||
/* Fire off the draw itself */
|
||||
panfrost_draw_emit_vertex(batch, info, &invocation, vs_vary, varyings,
|
||||
attribs, attrib_bufs, vertex.cpu);
|
||||
panfrost_draw_emit_tiler(batch, info, draw, &invocation,
|
||||
index_buf ? index_buf->ptr.gpu : 0,
|
||||
fs_vary, varyings, pos, psiz, tiler.cpu);
|
||||
|
||||
/* Add the varying heap BO to the batch if we're allocating varyings. */
|
||||
if (varyings) {
|
||||
panfrost_batch_add_bo(batch,
|
||||
dev->indirect_draw_shaders.varying_heap,
|
||||
PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
assert(indirect->buffer);
|
||||
|
||||
struct panfrost_resource *draw_buf = pan_resource(indirect->buffer);
|
||||
|
||||
/* Don't count images: those attributes don't need to be patched. */
|
||||
unsigned attrib_count =
|
||||
vs->info.attribute_count -
|
||||
util_bitcount(ctx->image_mask[PIPE_SHADER_VERTEX]);
|
||||
|
||||
panfrost_batch_read_rsrc(batch, draw_buf, PIPE_SHADER_VERTEX);
|
||||
|
||||
struct pan_indirect_draw_info draw_info = {
|
||||
.last_indirect_draw = batch->indirect_draw_job_id,
|
||||
.draw_buf = draw_buf->image.data.bo->ptr.gpu + indirect->offset,
|
||||
.index_buf = index_buf ? index_buf->ptr.gpu : 0,
|
||||
.first_vertex_sysval = ctx->first_vertex_sysval_ptr,
|
||||
.base_vertex_sysval = ctx->base_vertex_sysval_ptr,
|
||||
.base_instance_sysval = ctx->base_instance_sysval_ptr,
|
||||
.vertex_job = vertex.gpu,
|
||||
.tiler_job = tiler.gpu,
|
||||
.attrib_bufs = attrib_bufs,
|
||||
.attribs = attribs,
|
||||
.attrib_count = attrib_count,
|
||||
.varying_bufs = varyings,
|
||||
.index_size = info->index_size,
|
||||
};
|
||||
|
||||
if (panfrost_writes_point_size(ctx))
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_UPDATE_PRIM_SIZE;
|
||||
|
||||
if (vs->info.vs.writes_point_size)
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_HAS_PSIZ;
|
||||
|
||||
|
||||
if (info->primitive_restart) {
|
||||
draw_info.restart_index = info->restart_index;
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_PRIMITIVE_RESTART;
|
||||
}
|
||||
|
||||
batch->indirect_draw_job_id =
|
||||
panfrost_emit_indirect_draw(&batch->pool.base,
|
||||
&batch->scoreboard,
|
||||
&draw_info,
|
||||
&batch->indirect_draw_ctx);
|
||||
|
||||
panfrost_emit_vertex_tiler_jobs(batch, &vertex, &tiler);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_vbo(struct pipe_context *pipe,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_indirect_info *indirect,
|
||||
const struct pipe_draw_start_count_bias *draws,
|
||||
unsigned num_draws)
|
||||
{
|
||||
struct panfrost_context *ctx = pan_context(pipe);
|
||||
struct panfrost_device *dev = pan_device(pipe->screen);
|
||||
|
||||
if (!panfrost_render_condition_check(ctx))
|
||||
return;
|
||||
|
||||
/* Emulate indirect draws when debugging */
|
||||
if (dev->debug & PAN_DBG_NOINDIRECT && indirect && indirect->buffer) {
|
||||
assert(num_draws == 1);
|
||||
util_draw_indirect(pipe, info, indirect);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do some common setup */
|
||||
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
|
||||
|
||||
/* Don't add too many jobs to a single batch. Hardware has a hard limit
|
||||
* of 65536 jobs, but we choose a smaller soft limit (arbitrary) to
|
||||
* avoid the risk of timeouts. This might not be a good idea. */
|
||||
if (unlikely(batch->scoreboard.job_index > 10000))
|
||||
batch = panfrost_get_fresh_batch_for_fbo(ctx);
|
||||
|
||||
unsigned zs_draws = ctx->depth_stencil->draws;
|
||||
batch->draws |= zs_draws;
|
||||
batch->resolve |= zs_draws;
|
||||
|
||||
/* Mark everything dirty when debugging */
|
||||
if (unlikely(dev->debug & PAN_DBG_DIRTY))
|
||||
panfrost_dirty_state_all(ctx);
|
||||
|
||||
/* Conservatively assume draw parameters always change */
|
||||
ctx->dirty |= PAN_DIRTY_PARAMS | PAN_DIRTY_DRAWID;
|
||||
|
||||
if (indirect) {
|
||||
assert(num_draws == 1);
|
||||
|
||||
if (indirect->count_from_stream_output) {
|
||||
struct pipe_draw_start_count_bias tmp_draw = *draws;
|
||||
struct panfrost_streamout_target *so =
|
||||
pan_so_target(indirect->count_from_stream_output);
|
||||
|
||||
tmp_draw.start = 0;
|
||||
tmp_draw.count = so->offset;
|
||||
tmp_draw.index_bias = 0;
|
||||
panfrost_direct_draw(batch, info, drawid_offset, &tmp_draw);
|
||||
return;
|
||||
}
|
||||
|
||||
panfrost_indirect_draw(batch, info, drawid_offset, indirect, &draws[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pipe_draw_info tmp_info = *info;
|
||||
unsigned drawid = drawid_offset;
|
||||
|
||||
for (unsigned i = 0; i < num_draws; i++) {
|
||||
panfrost_direct_draw(batch, &tmp_info, drawid, &draws[i]);
|
||||
|
||||
if (tmp_info.increment_draw_id) {
|
||||
ctx->dirty |= PAN_DIRTY_DRAWID;
|
||||
drawid++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
panfrost_cmdstream_context_init(struct pipe_context *pipe)
|
||||
{
|
||||
pipe->draw_vbo = panfrost_draw_vbo;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include "util/format/u_format.h"
|
||||
#include "util/u_prim.h"
|
||||
#include "util/u_prim_restart.h"
|
||||
#include "util/u_draw.h"
|
||||
#include "indices/u_primconvert.h"
|
||||
#include "tgsi/tgsi_parse.h"
|
||||
#include "tgsi/tgsi_from_mesa.h"
|
||||
@@ -53,7 +52,6 @@
|
||||
#include "midgard_pack.h"
|
||||
#include "pan_screen.h"
|
||||
#include "pan_cmdstream.h"
|
||||
#include "pan_indirect_draw.h"
|
||||
#include "pan_util.h"
|
||||
#include "decode.h"
|
||||
#include "util/pan_lower_framebuffer.h"
|
||||
@@ -130,662 +128,6 @@ panfrost_set_frontend_noop(struct pipe_context *pipe, bool enable)
|
||||
ctx->is_noop = enable;
|
||||
}
|
||||
|
||||
#define DEFINE_CASE(c) case PIPE_PRIM_##c: return MALI_DRAW_MODE_##c;
|
||||
|
||||
static uint8_t
|
||||
pan_draw_mode(enum pipe_prim_type mode)
|
||||
{
|
||||
switch (mode) {
|
||||
DEFINE_CASE(POINTS);
|
||||
DEFINE_CASE(LINES);
|
||||
DEFINE_CASE(LINE_LOOP);
|
||||
DEFINE_CASE(LINE_STRIP);
|
||||
DEFINE_CASE(TRIANGLES);
|
||||
DEFINE_CASE(TRIANGLE_STRIP);
|
||||
DEFINE_CASE(TRIANGLE_FAN);
|
||||
DEFINE_CASE(QUADS);
|
||||
DEFINE_CASE(QUAD_STRIP);
|
||||
DEFINE_CASE(POLYGON);
|
||||
|
||||
default:
|
||||
unreachable("Invalid draw mode");
|
||||
}
|
||||
}
|
||||
|
||||
#undef DEFINE_CASE
|
||||
|
||||
/* Count generated primitives (when there is no geom/tess shaders) for
|
||||
* transform feedback */
|
||||
|
||||
static void
|
||||
panfrost_statistics_record(
|
||||
struct panfrost_context *ctx,
|
||||
const struct pipe_draw_info *info,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
if (!ctx->active_queries)
|
||||
return;
|
||||
|
||||
uint32_t prims = u_prims_for_vertices(info->mode, draw->count);
|
||||
ctx->prims_generated += prims;
|
||||
|
||||
if (!ctx->streamout.num_targets)
|
||||
return;
|
||||
|
||||
ctx->tf_prims_generated += prims;
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_streamout_offsets(struct panfrost_context *ctx)
|
||||
{
|
||||
for (unsigned i = 0; i < ctx->streamout.num_targets; ++i) {
|
||||
unsigned count;
|
||||
|
||||
count = u_stream_outputs_for_vertices(ctx->active_prim,
|
||||
ctx->vertex_count);
|
||||
pan_so_target(ctx->streamout.targets[i])->offset += count;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
pan_emit_draw_descs(struct panfrost_batch *batch,
|
||||
struct MALI_DRAW *d, enum pipe_shader_type st)
|
||||
{
|
||||
d->offset_start = batch->ctx->offset_start;
|
||||
d->instance_size = batch->ctx->instance_count > 1 ?
|
||||
batch->ctx->padded_count : 1;
|
||||
|
||||
d->uniform_buffers = batch->uniform_buffers[st];
|
||||
d->push_uniforms = batch->push_uniforms[st];
|
||||
d->textures = batch->textures[st];
|
||||
d->samplers = batch->samplers[st];
|
||||
}
|
||||
|
||||
static inline enum mali_index_type
|
||||
panfrost_translate_index_size(unsigned size)
|
||||
{
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_NONE == 0);
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_UINT8 == 1);
|
||||
STATIC_ASSERT(MALI_INDEX_TYPE_UINT16 == 2);
|
||||
|
||||
return (size == 4) ? MALI_INDEX_TYPE_UINT32 : size;
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_emit_vertex(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
void *invocation_template,
|
||||
mali_ptr vs_vary, mali_ptr varyings,
|
||||
mali_ptr attribs, mali_ptr attrib_bufs,
|
||||
void *job)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
void *section =
|
||||
pan_section_ptr(job, COMPUTE_JOB, INVOCATION);
|
||||
memcpy(section, invocation_template, MALI_INVOCATION_LENGTH);
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, PARAMETERS, cfg) {
|
||||
cfg.job_task_split = 5;
|
||||
}
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, DRAW, cfg) {
|
||||
cfg.draw_descriptor_is_64b = true;
|
||||
if (!pan_is_bifrost(device))
|
||||
cfg.texture_descriptor_is_64b = true;
|
||||
cfg.state = batch->rsd[PIPE_SHADER_VERTEX];
|
||||
cfg.attributes = attribs;
|
||||
cfg.attribute_buffers = attrib_bufs;
|
||||
cfg.varyings = vs_vary;
|
||||
cfg.varying_buffers = vs_vary ? varyings : 0;
|
||||
cfg.thread_storage = batch->tls.gpu;
|
||||
pan_emit_draw_descs(batch, &cfg, PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
pan_section_pack(job, COMPUTE_JOB, DRAW_PADDING, cfg);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_emit_primitive_size(struct panfrost_context *ctx,
|
||||
bool points, mali_ptr size_array,
|
||||
void *prim_size)
|
||||
{
|
||||
struct panfrost_rasterizer *rast = ctx->rasterizer;
|
||||
|
||||
pan_pack(prim_size, PRIMITIVE_SIZE, cfg) {
|
||||
if (panfrost_writes_point_size(ctx)) {
|
||||
cfg.size_array = size_array;
|
||||
} else {
|
||||
cfg.constant = points ?
|
||||
rast->base.point_size :
|
||||
rast->base.line_width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
panfrost_is_implicit_prim_restart(const struct pipe_draw_info *info)
|
||||
{
|
||||
unsigned implicit_index = (1 << (info->index_size * 8)) - 1;
|
||||
bool implicit = info->restart_index == implicit_index;
|
||||
return info->primitive_restart && implicit;
|
||||
}
|
||||
|
||||
static inline void
|
||||
panfrost_update_state_tex(struct panfrost_batch *batch,
|
||||
enum pipe_shader_type st)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_shader_state *ss = panfrost_get_shader_state(ctx, st);
|
||||
|
||||
unsigned dirty_3d = ctx->dirty;
|
||||
unsigned dirty = ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_TEXTURE) {
|
||||
batch->textures[st] =
|
||||
panfrost_emit_texture_descriptors(batch, st);
|
||||
}
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_SAMPLER) {
|
||||
batch->samplers[st] =
|
||||
panfrost_emit_sampler_descriptors(batch, st);
|
||||
}
|
||||
|
||||
if ((dirty & ss->dirty_shader) || (dirty_3d & ss->dirty_3d)) {
|
||||
batch->uniform_buffers[st] = panfrost_emit_const_buf(batch, st,
|
||||
&batch->push_uniforms[st]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
panfrost_update_state_3d(struct panfrost_batch *batch)
|
||||
{
|
||||
unsigned dirty = batch->ctx->dirty;
|
||||
|
||||
if (dirty & (PAN_DIRTY_VIEWPORT | PAN_DIRTY_SCISSOR))
|
||||
batch->viewport = panfrost_emit_viewport(batch);
|
||||
|
||||
if (dirty & PAN_DIRTY_TLS_SIZE)
|
||||
panfrost_batch_adjust_stack_size(batch);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_state_vs(struct panfrost_batch *batch)
|
||||
{
|
||||
enum pipe_shader_type st = PIPE_SHADER_VERTEX;
|
||||
unsigned dirty = batch->ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_RENDERER)
|
||||
batch->rsd[st] = panfrost_emit_compute_shader_meta(batch, st);
|
||||
|
||||
panfrost_update_state_tex(batch, st);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_update_state_fs(struct panfrost_batch *batch)
|
||||
{
|
||||
enum pipe_shader_type st = PIPE_SHADER_FRAGMENT;
|
||||
unsigned dirty = batch->ctx->dirty_shader[st];
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_RENDERER)
|
||||
batch->rsd[st] = panfrost_emit_frag_shader_meta(batch);
|
||||
|
||||
if (dirty & PAN_DIRTY_STAGE_IMAGE) {
|
||||
batch->attribs[st] = panfrost_emit_image_attribs(batch,
|
||||
&batch->attrib_bufs[st], st);
|
||||
}
|
||||
|
||||
panfrost_update_state_tex(batch, st);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_emit_tiler(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
const struct pipe_draw_start_count_bias *draw,
|
||||
void *invocation_template,
|
||||
mali_ptr indices, mali_ptr fs_vary, mali_ptr varyings,
|
||||
mali_ptr pos, mali_ptr psiz, void *job)
|
||||
{
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct pipe_rasterizer_state *rast = &ctx->rasterizer->base;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
void *section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, INVOCATION) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, INVOCATION);
|
||||
memcpy(section, invocation_template, MALI_INVOCATION_LENGTH);
|
||||
|
||||
section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, PRIMITIVE) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, PRIMITIVE);
|
||||
pan_pack(section, PRIMITIVE, cfg) {
|
||||
cfg.draw_mode = pan_draw_mode(info->mode);
|
||||
if (panfrost_writes_point_size(ctx))
|
||||
cfg.point_size_array_format = MALI_POINT_SIZE_ARRAY_FORMAT_FP16;
|
||||
|
||||
/* For line primitives, PRIMITIVE.first_provoking_vertex must
|
||||
* be set to true and the provoking vertex is selected with
|
||||
* DRAW.flat_shading_vertex.
|
||||
*/
|
||||
if (info->mode == PIPE_PRIM_LINES ||
|
||||
info->mode == PIPE_PRIM_LINE_LOOP ||
|
||||
info->mode == PIPE_PRIM_LINE_STRIP)
|
||||
cfg.first_provoking_vertex = true;
|
||||
else
|
||||
cfg.first_provoking_vertex = rast->flatshade_first;
|
||||
|
||||
if (panfrost_is_implicit_prim_restart(info)) {
|
||||
cfg.primitive_restart = MALI_PRIMITIVE_RESTART_IMPLICIT;
|
||||
} else if (info->primitive_restart) {
|
||||
cfg.primitive_restart = MALI_PRIMITIVE_RESTART_EXPLICIT;
|
||||
cfg.primitive_restart_index = info->restart_index;
|
||||
}
|
||||
|
||||
cfg.job_task_split = 6;
|
||||
|
||||
cfg.index_count = ctx->indirect_draw ? 1 : draw->count;
|
||||
cfg.index_type = panfrost_translate_index_size(info->index_size);
|
||||
|
||||
if (cfg.index_type) {
|
||||
cfg.indices = indices;
|
||||
cfg.base_vertex_offset = draw->index_bias - ctx->offset_start;
|
||||
}
|
||||
}
|
||||
|
||||
bool points = info->mode == PIPE_PRIM_POINTS;
|
||||
void *prim_size = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, PRIMITIVE_SIZE) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, PRIMITIVE_SIZE);
|
||||
|
||||
if (pan_is_bifrost(device)) {
|
||||
panfrost_emit_primitive_size(ctx, points, psiz, prim_size);
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, TILER, cfg) {
|
||||
cfg.address = panfrost_batch_get_bifrost_tiler(batch, ~0);
|
||||
}
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, PADDING, padding) {}
|
||||
}
|
||||
|
||||
section = pan_is_bifrost(device) ?
|
||||
pan_section_ptr(job, BIFROST_TILER_JOB, DRAW) :
|
||||
pan_section_ptr(job, MIDGARD_TILER_JOB, DRAW);
|
||||
pan_pack(section, DRAW, cfg) {
|
||||
cfg.four_components_per_vertex = true;
|
||||
cfg.draw_descriptor_is_64b = true;
|
||||
if (!pan_is_bifrost(device))
|
||||
cfg.texture_descriptor_is_64b = true;
|
||||
cfg.front_face_ccw = rast->front_ccw;
|
||||
cfg.cull_front_face = rast->cull_face & PIPE_FACE_FRONT;
|
||||
cfg.cull_back_face = rast->cull_face & PIPE_FACE_BACK;
|
||||
cfg.position = pos;
|
||||
cfg.state = batch->rsd[PIPE_SHADER_FRAGMENT];
|
||||
cfg.attributes = batch->attribs[PIPE_SHADER_FRAGMENT];
|
||||
cfg.attribute_buffers = batch->attrib_bufs[PIPE_SHADER_FRAGMENT];
|
||||
cfg.viewport = batch->viewport;
|
||||
cfg.varyings = fs_vary;
|
||||
cfg.varying_buffers = fs_vary ? varyings : 0;
|
||||
cfg.thread_storage = batch->tls.gpu;
|
||||
|
||||
/* For all primitives but lines DRAW.flat_shading_vertex must
|
||||
* be set to 0 and the provoking vertex is selected with the
|
||||
* PRIMITIVE.first_provoking_vertex field.
|
||||
*/
|
||||
if (info->mode == PIPE_PRIM_LINES ||
|
||||
info->mode == PIPE_PRIM_LINE_LOOP ||
|
||||
info->mode == PIPE_PRIM_LINE_STRIP) {
|
||||
/* The logic is inverted on bifrost. */
|
||||
cfg.flat_shading_vertex =
|
||||
pan_is_bifrost(device) ?
|
||||
rast->flatshade_first : !rast->flatshade_first;
|
||||
}
|
||||
|
||||
pan_emit_draw_descs(batch, &cfg, PIPE_SHADER_FRAGMENT);
|
||||
|
||||
if (ctx->occlusion_query && ctx->active_queries) {
|
||||
if (ctx->occlusion_query->type == PIPE_QUERY_OCCLUSION_COUNTER)
|
||||
cfg.occlusion_query = MALI_OCCLUSION_MODE_COUNTER;
|
||||
else
|
||||
cfg.occlusion_query = MALI_OCCLUSION_MODE_PREDICATE;
|
||||
|
||||
struct panfrost_resource *rsrc = pan_resource(ctx->occlusion_query->rsrc);
|
||||
cfg.occlusion = rsrc->image.data.bo->ptr.gpu;
|
||||
panfrost_batch_write_rsrc(ctx->batch, rsrc,
|
||||
PIPE_SHADER_FRAGMENT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pan_is_bifrost(device))
|
||||
panfrost_emit_primitive_size(ctx, points, psiz, prim_size);
|
||||
else
|
||||
pan_section_pack(job, BIFROST_TILER_JOB, DRAW_PADDING, cfg);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_direct_draw(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
if (!draw->count || !info->instance_count)
|
||||
return;
|
||||
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *device = pan_device(ctx->base.screen);
|
||||
|
||||
/* Fallback for unsupported modes */
|
||||
if (!(ctx->draw_modes & BITFIELD_BIT(info->mode))) {
|
||||
if (draw->count < 4) {
|
||||
/* Degenerate case? */
|
||||
return;
|
||||
}
|
||||
|
||||
util_primconvert_save_rasterizer_state(ctx->primconvert, &ctx->rasterizer->base);
|
||||
util_primconvert_draw_vbo(ctx->primconvert, info, drawid_offset, NULL, draw, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take into account a negative bias */
|
||||
ctx->indirect_draw = false;
|
||||
ctx->vertex_count = draw->count + (info->index_size ? abs(draw->index_bias) : 0);
|
||||
ctx->instance_count = info->instance_count;
|
||||
ctx->base_vertex = info->index_size ? draw->index_bias : 0;
|
||||
ctx->base_instance = info->start_instance;
|
||||
ctx->active_prim = info->mode;
|
||||
ctx->drawid = drawid_offset;
|
||||
|
||||
struct panfrost_ptr tiler =
|
||||
pan_is_bifrost(device) ?
|
||||
pan_pool_alloc_desc(&batch->pool.base, BIFROST_TILER_JOB) :
|
||||
pan_pool_alloc_desc(&batch->pool.base, MIDGARD_TILER_JOB);
|
||||
struct panfrost_ptr vertex =
|
||||
pan_pool_alloc_desc(&batch->pool.base, COMPUTE_JOB);
|
||||
|
||||
unsigned vertex_count = ctx->vertex_count;
|
||||
|
||||
unsigned min_index = 0, max_index = 0;
|
||||
mali_ptr indices = 0;
|
||||
|
||||
if (info->index_size) {
|
||||
indices = panfrost_get_index_buffer_bounded(batch, info, draw,
|
||||
&min_index,
|
||||
&max_index);
|
||||
|
||||
/* Use the corresponding values */
|
||||
vertex_count = max_index - min_index + 1;
|
||||
ctx->offset_start = min_index + draw->index_bias;
|
||||
} else {
|
||||
ctx->offset_start = draw->start;
|
||||
}
|
||||
|
||||
if (info->instance_count > 1)
|
||||
ctx->padded_count = panfrost_padded_vertex_count(vertex_count);
|
||||
else
|
||||
ctx->padded_count = vertex_count;
|
||||
|
||||
panfrost_statistics_record(ctx, info, draw);
|
||||
|
||||
struct mali_invocation_packed invocation;
|
||||
if (info->instance_count > 1) {
|
||||
panfrost_pack_work_groups_compute(&invocation,
|
||||
1, vertex_count, info->instance_count,
|
||||
1, 1, 1, true, false);
|
||||
} else {
|
||||
pan_pack(&invocation, INVOCATION, cfg) {
|
||||
cfg.invocations = MALI_POSITIVE(vertex_count);
|
||||
cfg.size_y_shift = 0;
|
||||
cfg.size_z_shift = 0;
|
||||
cfg.workgroups_x_shift = 0;
|
||||
cfg.workgroups_y_shift = 0;
|
||||
cfg.workgroups_z_shift = 32;
|
||||
cfg.thread_group_split = MALI_SPLIT_MIN_EFFICIENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emit all sort of descriptors. */
|
||||
mali_ptr varyings = 0, vs_vary = 0, fs_vary = 0, pos = 0, psiz = 0;
|
||||
|
||||
panfrost_emit_varying_descriptor(batch,
|
||||
ctx->padded_count *
|
||||
ctx->instance_count,
|
||||
&vs_vary, &fs_vary, &varyings,
|
||||
NULL, &pos, &psiz,
|
||||
info->mode == PIPE_PRIM_POINTS);
|
||||
|
||||
mali_ptr attribs, attrib_bufs;
|
||||
attribs = panfrost_emit_vertex_data(batch, &attrib_bufs);
|
||||
|
||||
panfrost_update_state_3d(batch);
|
||||
panfrost_update_state_vs(batch);
|
||||
panfrost_update_state_fs(batch);
|
||||
panfrost_clean_state_3d(ctx);
|
||||
|
||||
/* Fire off the draw itself */
|
||||
panfrost_draw_emit_vertex(batch, info, &invocation,
|
||||
vs_vary, varyings, attribs, attrib_bufs, vertex.cpu);
|
||||
panfrost_draw_emit_tiler(batch, info, draw, &invocation, indices,
|
||||
fs_vary, varyings, pos, psiz, tiler.cpu);
|
||||
panfrost_emit_vertex_tiler_jobs(batch, &vertex, &tiler);
|
||||
|
||||
/* Increment transform feedback offsets */
|
||||
panfrost_update_streamout_offsets(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_indirect_draw(struct panfrost_batch *batch,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_indirect_info *indirect,
|
||||
const struct pipe_draw_start_count_bias *draw)
|
||||
{
|
||||
/* Indirect draw count and multi-draw not supported. */
|
||||
assert(indirect->draw_count == 1 && !indirect->indirect_draw_count);
|
||||
|
||||
struct panfrost_context *ctx = batch->ctx;
|
||||
struct panfrost_device *dev = pan_device(ctx->base.screen);
|
||||
|
||||
/* TODO: update statistics (see panfrost_statistics_record()) */
|
||||
/* TODO: Increment transform feedback offsets */
|
||||
assert(ctx->streamout.num_targets == 0);
|
||||
|
||||
assert(ctx->draw_modes & (1 << info->mode));
|
||||
ctx->active_prim = info->mode;
|
||||
ctx->drawid = drawid_offset;
|
||||
ctx->indirect_draw = true;
|
||||
|
||||
struct panfrost_ptr tiler =
|
||||
pan_pool_alloc_aligned(&batch->pool.base,
|
||||
pan_is_bifrost(dev) ?
|
||||
MALI_BIFROST_TILER_JOB_LENGTH :
|
||||
MALI_MIDGARD_TILER_JOB_LENGTH,
|
||||
64);
|
||||
struct panfrost_ptr vertex =
|
||||
pan_pool_alloc_aligned(&batch->pool.base,
|
||||
MALI_COMPUTE_JOB_LENGTH,
|
||||
64);
|
||||
|
||||
struct panfrost_shader_state *vs =
|
||||
panfrost_get_shader_state(ctx, PIPE_SHADER_VERTEX);
|
||||
|
||||
struct panfrost_bo *index_buf = NULL;
|
||||
|
||||
if (info->index_size) {
|
||||
assert(!info->has_user_indices);
|
||||
struct panfrost_resource *rsrc = pan_resource(info->index.resource);
|
||||
index_buf = rsrc->image.data.bo;
|
||||
panfrost_batch_read_rsrc(batch, rsrc, PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
mali_ptr varyings = 0, vs_vary = 0, fs_vary = 0, pos = 0, psiz = 0;
|
||||
unsigned varying_buf_count;
|
||||
|
||||
/* We want to create templates, set all count fields to 0 to reflect
|
||||
* that.
|
||||
*/
|
||||
ctx->instance_count = ctx->vertex_count = ctx->padded_count = 0;
|
||||
ctx->offset_start = 0;
|
||||
|
||||
/* Set the {first,base}_vertex sysvals to NULL. Will be updated if the
|
||||
* vertex shader uses gl_VertexID or gl_BaseVertex.
|
||||
*/
|
||||
ctx->first_vertex_sysval_ptr = 0;
|
||||
ctx->base_vertex_sysval_ptr = 0;
|
||||
ctx->base_instance_sysval_ptr = 0;
|
||||
|
||||
panfrost_update_state_3d(batch);
|
||||
panfrost_update_state_vs(batch);
|
||||
panfrost_update_state_fs(batch);
|
||||
panfrost_clean_state_3d(ctx);
|
||||
|
||||
bool point_coord_replace = (info->mode == PIPE_PRIM_POINTS);
|
||||
|
||||
panfrost_emit_varying_descriptor(batch, 0,
|
||||
&vs_vary, &fs_vary, &varyings,
|
||||
&varying_buf_count, &pos, &psiz,
|
||||
point_coord_replace);
|
||||
|
||||
mali_ptr attribs, attrib_bufs;
|
||||
attribs = panfrost_emit_vertex_data(batch, &attrib_bufs);
|
||||
|
||||
/* Zero-ed invocation, the compute job will update it. */
|
||||
static struct mali_invocation_packed invocation;
|
||||
|
||||
/* Fire off the draw itself */
|
||||
panfrost_draw_emit_vertex(batch, info, &invocation, vs_vary, varyings,
|
||||
attribs, attrib_bufs, vertex.cpu);
|
||||
panfrost_draw_emit_tiler(batch, info, draw, &invocation,
|
||||
index_buf ? index_buf->ptr.gpu : 0,
|
||||
fs_vary, varyings, pos, psiz, tiler.cpu);
|
||||
|
||||
/* Add the varying heap BO to the batch if we're allocating varyings. */
|
||||
if (varyings) {
|
||||
panfrost_batch_add_bo(batch,
|
||||
dev->indirect_draw_shaders.varying_heap,
|
||||
PIPE_SHADER_VERTEX);
|
||||
}
|
||||
|
||||
assert(indirect->buffer);
|
||||
|
||||
struct panfrost_resource *draw_buf = pan_resource(indirect->buffer);
|
||||
|
||||
/* Don't count images: those attributes don't need to be patched. */
|
||||
unsigned attrib_count =
|
||||
vs->info.attribute_count -
|
||||
util_bitcount(ctx->image_mask[PIPE_SHADER_VERTEX]);
|
||||
|
||||
panfrost_batch_read_rsrc(batch, draw_buf, PIPE_SHADER_VERTEX);
|
||||
|
||||
struct pan_indirect_draw_info draw_info = {
|
||||
.last_indirect_draw = batch->indirect_draw_job_id,
|
||||
.draw_buf = draw_buf->image.data.bo->ptr.gpu + indirect->offset,
|
||||
.index_buf = index_buf ? index_buf->ptr.gpu : 0,
|
||||
.first_vertex_sysval = ctx->first_vertex_sysval_ptr,
|
||||
.base_vertex_sysval = ctx->base_vertex_sysval_ptr,
|
||||
.base_instance_sysval = ctx->base_instance_sysval_ptr,
|
||||
.vertex_job = vertex.gpu,
|
||||
.tiler_job = tiler.gpu,
|
||||
.attrib_bufs = attrib_bufs,
|
||||
.attribs = attribs,
|
||||
.attrib_count = attrib_count,
|
||||
.varying_bufs = varyings,
|
||||
.index_size = info->index_size,
|
||||
};
|
||||
|
||||
if (panfrost_writes_point_size(ctx))
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_UPDATE_PRIM_SIZE;
|
||||
|
||||
if (vs->info.vs.writes_point_size)
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_HAS_PSIZ;
|
||||
|
||||
|
||||
if (info->primitive_restart) {
|
||||
draw_info.restart_index = info->restart_index;
|
||||
draw_info.flags |= PAN_INDIRECT_DRAW_PRIMITIVE_RESTART;
|
||||
}
|
||||
|
||||
batch->indirect_draw_job_id =
|
||||
panfrost_emit_indirect_draw(&batch->pool.base,
|
||||
&batch->scoreboard,
|
||||
&draw_info,
|
||||
&batch->indirect_draw_ctx);
|
||||
|
||||
panfrost_emit_vertex_tiler_jobs(batch, &vertex, &tiler);
|
||||
}
|
||||
|
||||
static void
|
||||
panfrost_draw_vbo(struct pipe_context *pipe,
|
||||
const struct pipe_draw_info *info,
|
||||
unsigned drawid_offset,
|
||||
const struct pipe_draw_indirect_info *indirect,
|
||||
const struct pipe_draw_start_count_bias *draws,
|
||||
unsigned num_draws)
|
||||
{
|
||||
struct panfrost_context *ctx = pan_context(pipe);
|
||||
struct panfrost_device *dev = pan_device(pipe->screen);
|
||||
|
||||
if (!panfrost_render_condition_check(ctx))
|
||||
return;
|
||||
|
||||
/* Emulate indirect draws when debugging */
|
||||
if (dev->debug & PAN_DBG_NOINDIRECT && indirect && indirect->buffer) {
|
||||
assert(num_draws == 1);
|
||||
util_draw_indirect(pipe, info, indirect);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do some common setup */
|
||||
struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx);
|
||||
|
||||
/* Don't add too many jobs to a single batch. Hardware has a hard limit
|
||||
* of 65536 jobs, but we choose a smaller soft limit (arbitrary) to
|
||||
* avoid the risk of timeouts. This might not be a good idea. */
|
||||
if (unlikely(batch->scoreboard.job_index > 10000))
|
||||
batch = panfrost_get_fresh_batch_for_fbo(ctx);
|
||||
|
||||
unsigned zs_draws = ctx->depth_stencil->draws;
|
||||
batch->draws |= zs_draws;
|
||||
batch->resolve |= zs_draws;
|
||||
|
||||
/* Mark everything dirty when debugging */
|
||||
if (unlikely(dev->debug & PAN_DBG_DIRTY))
|
||||
panfrost_dirty_state_all(ctx);
|
||||
|
||||
/* Conservatively assume draw parameters always change */
|
||||
ctx->dirty |= PAN_DIRTY_PARAMS | PAN_DIRTY_DRAWID;
|
||||
|
||||
if (indirect) {
|
||||
assert(num_draws == 1);
|
||||
|
||||
if (indirect->count_from_stream_output) {
|
||||
struct pipe_draw_start_count_bias tmp_draw = *draws;
|
||||
struct panfrost_streamout_target *so =
|
||||
pan_so_target(indirect->count_from_stream_output);
|
||||
|
||||
tmp_draw.start = 0;
|
||||
tmp_draw.count = so->offset;
|
||||
tmp_draw.index_bias = 0;
|
||||
panfrost_direct_draw(batch, info, drawid_offset, &tmp_draw);
|
||||
return;
|
||||
}
|
||||
|
||||
panfrost_indirect_draw(batch, info, drawid_offset, indirect, &draws[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
struct pipe_draw_info tmp_info = *info;
|
||||
unsigned drawid = drawid_offset;
|
||||
|
||||
for (unsigned i = 0; i < num_draws; i++) {
|
||||
panfrost_direct_draw(batch, &tmp_info, drawid, &draws[i]);
|
||||
|
||||
if (tmp_info.increment_draw_id) {
|
||||
ctx->dirty |= PAN_DIRTY_DRAWID;
|
||||
drawid++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* CSO state */
|
||||
|
||||
static void
|
||||
panfrost_generic_cso_delete(struct pipe_context *pctx, void *hwcso)
|
||||
@@ -1945,7 +1287,6 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
|
||||
|
||||
gallium->flush = panfrost_flush;
|
||||
gallium->clear = panfrost_clear;
|
||||
gallium->draw_vbo = panfrost_draw_vbo;
|
||||
gallium->texture_barrier = panfrost_texture_barrier;
|
||||
gallium->set_frontend_noop = panfrost_set_frontend_noop;
|
||||
|
||||
@@ -2005,6 +1346,7 @@ panfrost_create_context(struct pipe_screen *screen, void *priv, unsigned flags)
|
||||
gallium->stream_output_target_destroy = panfrost_stream_output_target_destroy;
|
||||
gallium->set_stream_output_targets = panfrost_set_stream_output_targets;
|
||||
|
||||
panfrost_cmdstream_context_init(gallium);
|
||||
panfrost_resource_context_init(gallium);
|
||||
panfrost_blend_context_init(gallium);
|
||||
panfrost_compute_context_init(gallium);
|
||||
|
||||
@@ -437,4 +437,7 @@ panfrost_clean_state_3d(struct panfrost_context *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
panfrost_cmdstream_context_init(struct pipe_context *pipe);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user