X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Ffreedreno%2Fa3xx%2Ffd3_draw.c;h=3906c9b996ecca9053076d3eaf32b564b7b5d04a;hb=1e8d0cc62897fc90ac7dc9a92e80e714e52d3e77;hp=4f28b0e0608b7a2be2d8a826a4c12a71fc3e8507;hpb=725d736f6a6a14d10223888d585ddab80ee803f0;p=mesa.git diff --git a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c index 4f28b0e0608..3906c9b996e 100644 --- a/src/gallium/drivers/freedreno/a3xx/fd3_draw.c +++ b/src/gallium/drivers/freedreno/a3xx/fd3_draw.c @@ -30,6 +30,7 @@ #include "util/u_string.h" #include "util/u_memory.h" #include "util/u_prim.h" +#include "util/u_format.h" #include "freedreno_state.h" #include "freedreno_resource.h" @@ -38,66 +39,149 @@ #include "fd3_context.h" #include "fd3_emit.h" #include "fd3_program.h" -#include "fd3_util.h" +#include "fd3_format.h" #include "fd3_zsa.h" +static inline uint32_t +add_sat(uint32_t a, int32_t b) +{ + int64_t ret = (uint64_t)a + (int64_t)b; + if (ret > ~0U) + return ~0U; + if (ret < 0) + return 0; + return (uint32_t)ret; +} static void -emit_vertexbufs(struct fd_context *ctx, struct fd_ringbuffer *ring) +draw_impl(struct fd_context *ctx, struct fd_ringbuffer *ring, + struct fd3_emit *emit) { - struct fd_vertex_stateobj *vtx = ctx->vtx; - struct fd_vertexbuf_stateobj *vertexbuf = &ctx->vertexbuf; - struct fd3_vertex_buf bufs[PIPE_MAX_ATTRIBS]; - unsigned i; + const struct pipe_draw_info *info = emit->info; + enum pc_di_primtype primtype = ctx->primtypes[info->mode]; - if (!vtx->num_elements) + if (!(fd3_emit_get_vp(emit) && fd3_emit_get_fp(emit))) return; - for (i = 0; i < vtx->num_elements; i++) { - struct pipe_vertex_element *elem = &vtx->pipe[i]; - struct pipe_vertex_buffer *vb = - &vertexbuf->vb[elem->vertex_buffer_index]; - bufs[i].offset = vb->buffer_offset + elem->src_offset; - bufs[i].stride = vb->stride; - bufs[i].prsc = vb->buffer; - bufs[i].format = elem->src_format; - } - - fd3_emit_vertex_bufs(ring, &ctx->prog, bufs, vtx->num_elements); -} + fd3_emit_state(ctx, ring, emit); -static void -draw_impl(struct fd_context *ctx, const struct pipe_draw_info *info, - struct fd_ringbuffer *ring, unsigned dirty, bool binning) -{ - fd3_emit_state(ctx, ring, dirty, binning); - - if (dirty & FD_DIRTY_VTXBUF) - emit_vertexbufs(ctx, ring); + if (emit->dirty & (FD_DIRTY_VTXBUF | FD_DIRTY_VTXSTATE)) + fd3_emit_vertex_bufs(ring, emit); OUT_PKT0(ring, REG_A3XX_PC_VERTEX_REUSE_BLOCK_CNTL, 1); - OUT_RING(ring, 0x0000000b); /* PC_VERTEX_REUSE_BLOCK_CNTL */ + OUT_RING(ring, 0x0000000b); /* PC_VERTEX_REUSE_BLOCK_CNTL */ OUT_PKT0(ring, REG_A3XX_VFD_INDEX_MIN, 4); - OUT_RING(ring, info->min_index); /* VFD_INDEX_MIN */ - OUT_RING(ring, info->max_index); /* VFD_INDEX_MAX */ + OUT_RING(ring, add_sat(info->min_index, info->index_bias)); /* VFD_INDEX_MIN */ + OUT_RING(ring, add_sat(info->max_index, info->index_bias)); /* VFD_INDEX_MAX */ OUT_RING(ring, info->start_instance); /* VFD_INSTANCEID_OFFSET */ - OUT_RING(ring, info->start); /* VFD_INDEX_OFFSET */ + OUT_RING(ring, info->indexed ? info->index_bias : info->start); /* VFD_INDEX_OFFSET */ OUT_PKT0(ring, REG_A3XX_PC_RESTART_INDEX, 1); OUT_RING(ring, info->primitive_restart ? /* PC_RESTART_INDEX */ info->restart_index : 0xffffffff); - fd_draw_emit(ctx, ring, binning ? IGNORE_VISIBILITY : USE_VISIBILITY, info); + if (ctx->rasterizer->point_size_per_vertex && + (info->mode == PIPE_PRIM_POINTS)) + primtype = DI_PT_POINTLIST_PSIZE; + + fd_draw_emit(ctx, ring, + primtype, + emit->key.binning_pass ? IGNORE_VISIBILITY : USE_VISIBILITY, + info); } +/* fixup dirty shader state in case some "unrelated" (from the state- + * tracker's perspective) state change causes us to switch to a + * different variant. + */ static void -fd3_draw(struct fd_context *ctx, const struct pipe_draw_info *info) +fixup_shader_state(struct fd_context *ctx, struct ir3_shader_key *key) { - unsigned dirty = ctx->dirty; - draw_impl(ctx, info, ctx->binning_ring, - dirty & ~(FD_DIRTY_BLEND), true); - draw_impl(ctx, info, ctx->ring, dirty, false); + struct fd3_context *fd3_ctx = fd3_context(ctx); + struct ir3_shader_key *last_key = &fd3_ctx->last_key; + + if (!ir3_shader_key_equal(last_key, key)) { + ctx->dirty |= FD_DIRTY_PROG; + + if (last_key->has_per_samp || key->has_per_samp) { + if ((last_key->vsaturate_s != key->vsaturate_s) || + (last_key->vsaturate_t != key->vsaturate_t) || + (last_key->vsaturate_r != key->vsaturate_r)) + ctx->prog.dirty |= FD_SHADER_DIRTY_VP; + + if ((last_key->fsaturate_s != key->fsaturate_s) || + (last_key->fsaturate_t != key->fsaturate_t) || + (last_key->fsaturate_r != key->fsaturate_r)) + ctx->prog.dirty |= FD_SHADER_DIRTY_FP; + } + + if (last_key->color_two_side != key->color_two_side) + ctx->prog.dirty |= FD_SHADER_DIRTY_FP; + + if (last_key->half_precision != key->half_precision) + ctx->prog.dirty |= FD_SHADER_DIRTY_FP; + + fd3_ctx->last_key = *key; + } +} + +static void +fd3_draw_vbo(struct fd_context *ctx, const struct pipe_draw_info *info) +{ + struct fd3_context *fd3_ctx = fd3_context(ctx); + struct fd3_emit emit = { + .vtx = &ctx->vtx, + .prog = &ctx->prog, + .info = info, + .key = { + /* do binning pass first: */ + .binning_pass = true, + .color_two_side = ctx->rasterizer->light_twoside, + // TODO set .half_precision based on render target format, + // ie. float16 and smaller use half, float32 use full.. + .half_precision = !!(fd_mesa_debug & FD_DBG_FRAGHALF), + .has_per_samp = (fd3_ctx->fsaturate || fd3_ctx->vsaturate), + .vsaturate_s = fd3_ctx->vsaturate_s, + .vsaturate_t = fd3_ctx->vsaturate_t, + .vsaturate_r = fd3_ctx->vsaturate_r, + .fsaturate_s = fd3_ctx->fsaturate_s, + .fsaturate_t = fd3_ctx->fsaturate_t, + .fsaturate_r = fd3_ctx->fsaturate_r, + }, + .rasterflat = ctx->rasterizer->flatshade, + .sprite_coord_enable = ctx->rasterizer->sprite_coord_enable, + .sprite_coord_mode = ctx->rasterizer->sprite_coord_mode, + }; + unsigned dirty; + + fixup_shader_state(ctx, &emit.key); + + dirty = ctx->dirty; + emit.dirty = dirty & ~(FD_DIRTY_BLEND); + draw_impl(ctx, ctx->binning_ring, &emit); + + /* and now regular (non-binning) pass: */ + emit.key.binning_pass = false; + emit.dirty = dirty; + emit.vp = NULL; /* we changed key so need to refetch vp */ + draw_impl(ctx, ctx->ring, &emit); +} + +/* clear operations ignore viewport state, so we need to reset it + * based on framebuffer state: + */ +static void +reset_viewport(struct fd_ringbuffer *ring, struct pipe_framebuffer_state *pfb) +{ + float half_width = pfb->width * 0.5f; + float half_height = pfb->height * 0.5f; + + OUT_PKT0(ring, REG_A3XX_GRAS_CL_VPORT_XOFFSET, 4); + OUT_RING(ring, A3XX_GRAS_CL_VPORT_XOFFSET(half_width - 0.5)); + OUT_RING(ring, A3XX_GRAS_CL_VPORT_XSCALE(half_width)); + OUT_RING(ring, A3XX_GRAS_CL_VPORT_YOFFSET(half_height - 0.5)); + OUT_RING(ring, A3XX_GRAS_CL_VPORT_YSCALE(-half_height)); } /* binning pass cmds for a clear: @@ -113,15 +197,19 @@ fd3_clear_binning(struct fd_context *ctx, unsigned dirty) { struct fd3_context *fd3_ctx = fd3_context(ctx); struct fd_ringbuffer *ring = ctx->binning_ring; - - fd3_emit_state(ctx, ring, dirty & (FD_DIRTY_VIEWPORT | - FD_DIRTY_FRAMEBUFFER | FD_DIRTY_SCISSOR), true); - - fd3_program_emit(ring, &ctx->solid_prog, true); - - fd3_emit_vertex_bufs(ring, &ctx->solid_prog, (struct fd3_vertex_buf[]) { - { .prsc = fd3_ctx->solid_vbuf, .stride = 12, .format = PIPE_FORMAT_R32G32B32_FLOAT }, - }, 1); + struct fd3_emit emit = { + .vtx = &fd3_ctx->solid_vbuf_state, + .prog = &ctx->solid_prog, + .key = { + .binning_pass = true, + .half_precision = true, + }, + .dirty = dirty, + }; + + fd3_emit_state(ctx, ring, &emit); + fd3_emit_vertex_bufs(ring, &emit); + reset_viewport(ring, &ctx->framebuffer); OUT_PKT0(ring, REG_A3XX_PC_PRIM_VTX_CNTL, 1); OUT_RING(ring, A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC(0) | @@ -136,11 +224,10 @@ fd3_clear_binning(struct fd_context *ctx, unsigned dirty) OUT_PKT0(ring, REG_A3XX_PC_RESTART_INDEX, 1); OUT_RING(ring, 0xffffffff); /* PC_RESTART_INDEX */ - OUT_PKT3(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, PERFCOUNTER_STOP); + fd_event_write(ctx, ring, PERFCOUNTER_STOP); fd_draw(ctx, ring, DI_PT_RECTLIST, IGNORE_VISIBILITY, - DI_SRC_SEL_AUTO_INDEX, 2, INDEX_SIZE_IGN, 0, 0, NULL); + DI_SRC_SEL_AUTO_INDEX, 2, 0, INDEX_SIZE_IGN, 0, 0, NULL); } static void @@ -148,15 +235,27 @@ fd3_clear(struct fd_context *ctx, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct fd3_context *fd3_ctx = fd3_context(ctx); + struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd_ringbuffer *ring = ctx->ring; unsigned dirty = ctx->dirty; - unsigned ce, i; + unsigned i; + struct fd3_emit emit = { + .vtx = &fd3_ctx->solid_vbuf_state, + .prog = &ctx->solid_prog, + .key = { + .half_precision = fd_half_precision(pfb), + }, + }; + + dirty &= FD_DIRTY_FRAMEBUFFER | FD_DIRTY_SCISSOR; + dirty |= FD_DIRTY_PROG; + emit.dirty = dirty; fd3_clear_binning(ctx, dirty); /* emit generic state now: */ - fd3_emit_state(ctx, ring, dirty & (FD_DIRTY_VIEWPORT | - FD_DIRTY_FRAMEBUFFER | FD_DIRTY_SCISSOR), false); + fd3_emit_state(ctx, ring, &emit); + reset_viewport(ring, &ctx->framebuffer); OUT_PKT0(ring, REG_A3XX_RB_BLEND_ALPHA, 1); OUT_RING(ring, A3XX_RB_BLEND_ALPHA_UINT(0xff) | @@ -172,6 +271,7 @@ fd3_clear(struct fd_context *ctx, unsigned buffers, A3XX_RB_DEPTH_CONTROL_Z_ENABLE | A3XX_RB_DEPTH_CONTROL_ZFUNC(FUNC_ALWAYS)); + fd_wfi(ctx, ring); OUT_PKT0(ring, REG_A3XX_GRAS_CL_VPORT_ZOFFSET, 2); OUT_RING(ring, A3XX_GRAS_CL_VPORT_ZOFFSET(0.0)); OUT_RING(ring, A3XX_GRAS_CL_VPORT_ZSCALE(depth)); @@ -221,17 +321,12 @@ fd3_clear(struct fd_context *ctx, unsigned buffers, A3XX_RB_STENCIL_CONTROL_ZFAIL_BF(STENCIL_KEEP)); } - if (buffers & PIPE_CLEAR_COLOR) { - ce = 0xf; - } else { - ce = 0x0; - } - - for (i = 0; i < 4; i++) { + for (i = 0; i < A3XX_MAX_RENDER_TARGETS; i++) { OUT_PKT0(ring, REG_A3XX_RB_MRT_CONTROL(i), 1); - OUT_RING(ring, A3XX_RB_MRT_CONTROL_ROP_CODE(12) | + OUT_RING(ring, A3XX_RB_MRT_CONTROL_ROP_CODE(ROP_COPY) | A3XX_RB_MRT_CONTROL_DITHER_MODE(DITHER_ALWAYS) | - A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE(ce)); + COND(buffers & (PIPE_CLEAR_COLOR0 << i), + A3XX_RB_MRT_CONTROL_COMPONENT_ENABLE(0xf))); OUT_PKT0(ring, REG_A3XX_RB_MRT_BLEND_CONTROL(i), 1); OUT_RING(ring, A3XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(FACTOR_ONE) | @@ -239,20 +334,15 @@ fd3_clear(struct fd_context *ctx, unsigned buffers, A3XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(FACTOR_ZERO) | A3XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(FACTOR_ONE) | A3XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(BLEND_DST_PLUS_SRC) | - A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(FACTOR_ZERO) | - A3XX_RB_MRT_BLEND_CONTROL_CLAMP_ENABLE); + A3XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(FACTOR_ZERO)); } OUT_PKT0(ring, REG_A3XX_GRAS_SU_MODE_CONTROL, 1); OUT_RING(ring, A3XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(0)); - fd3_program_emit(ring, &ctx->solid_prog, false); - - fd3_emit_vertex_bufs(ring, &ctx->solid_prog, (struct fd3_vertex_buf[]) { - { .prsc = fd3_ctx->solid_vbuf, .stride = 12, .format = PIPE_FORMAT_R32G32B32_FLOAT }, - }, 1); + fd3_emit_vertex_bufs(ring, &emit); - fd3_emit_constant(ring, SB_FRAG_SHADER, 0, 0, 4, color->ui, NULL); + fd3_emit_const(ring, SHADER_FRAGMENT, 0, 0, 4, color->ui, NULL); OUT_PKT0(ring, REG_A3XX_PC_PRIM_VTX_CNTL, 1); OUT_RING(ring, A3XX_PC_PRIM_VTX_CNTL_STRIDE_IN_VPC(0) | @@ -267,17 +357,16 @@ fd3_clear(struct fd_context *ctx, unsigned buffers, OUT_PKT0(ring, REG_A3XX_PC_RESTART_INDEX, 1); OUT_RING(ring, 0xffffffff); /* PC_RESTART_INDEX */ - OUT_PKT3(ring, CP_EVENT_WRITE, 1); - OUT_RING(ring, PERFCOUNTER_STOP); + fd_event_write(ctx, ring, PERFCOUNTER_STOP); fd_draw(ctx, ring, DI_PT_RECTLIST, USE_VISIBILITY, - DI_SRC_SEL_AUTO_INDEX, 2, INDEX_SIZE_IGN, 0, 0, NULL); + DI_SRC_SEL_AUTO_INDEX, 2, 0, INDEX_SIZE_IGN, 0, 0, NULL); } void fd3_draw_init(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); - ctx->draw = fd3_draw; + ctx->draw_vbo = fd3_draw_vbo; ctx->clear = fd3_clear; }