static void fd4_emit_tile_gmem2mem(struct fd_context *ctx, struct fd_tile *tile) { struct fd4_context *fd4_ctx = fd4_context(ctx); struct fd_ringbuffer *ring = ctx->ring; struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd4_emit emit = { .vtx = &fd4_ctx->solid_vbuf_state, .prog = &ctx->solid_prog, .key = key, .format = fd4_emit_format(pfb->cbufs[0]), }; OUT_PKT0(ring, REG_A4XX_RB_DEPTH_CONTROL, 1); OUT_RING(ring, A4XX_RB_DEPTH_CONTROL_ZFUNC(FUNC_NEVER)); OUT_PKT0(ring, REG_A4XX_RB_STENCIL_CONTROL, 2); OUT_RING(ring, A4XX_RB_STENCIL_CONTROL_FUNC(FUNC_NEVER) | A4XX_RB_STENCIL_CONTROL_FAIL(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZPASS(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZFAIL(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_FUNC_BF(FUNC_NEVER) | A4XX_RB_STENCIL_CONTROL_FAIL_BF(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZPASS_BF(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZFAIL_BF(STENCIL_KEEP)); OUT_RING(ring, 0x00000000); /* RB_STENCIL_CONTROL2 */ OUT_PKT0(ring, REG_A4XX_RB_STENCILREFMASK, 2); OUT_RING(ring, 0xff000000 | A4XX_RB_STENCILREFMASK_STENCILREF(0) | A4XX_RB_STENCILREFMASK_STENCILMASK(0) | A4XX_RB_STENCILREFMASK_STENCILWRITEMASK(0xff)); OUT_RING(ring, 0xff000000 | A4XX_RB_STENCILREFMASK_BF_STENCILREF(0) | A4XX_RB_STENCILREFMASK_BF_STENCILMASK(0) | A4XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(0xff)); OUT_PKT0(ring, REG_A4XX_GRAS_SU_MODE_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(0)); fd_wfi(ctx, ring); OUT_PKT0(ring, REG_A4XX_GRAS_CL_CLIP_CNTL, 1); OUT_RING(ring, 0x80000); /* GRAS_CL_CLIP_CNTL */ OUT_PKT0(ring, REG_A4XX_GRAS_CL_VPORT_XOFFSET_0, 6); OUT_RING(ring, A4XX_GRAS_CL_VPORT_XOFFSET_0((float)pfb->width/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_XSCALE_0((float)pfb->width/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_YOFFSET_0((float)pfb->height/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_YSCALE_0(-(float)pfb->height/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_ZOFFSET_0(0.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_ZSCALE_0(1.0)); OUT_PKT0(ring, REG_A4XX_RB_RENDER_CONTROL, 1); OUT_RING(ring, A4XX_RB_RENDER_CONTROL_DISABLE_COLOR_PIPE | 0xa); /* XXX */ OUT_PKT0(ring, REG_A4XX_GRAS_SC_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SC_CONTROL_RENDER_MODE(RB_RESOLVE_PASS) | A4XX_GRAS_SC_CONTROL_MSAA_DISABLE | A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(MSAA_ONE) | A4XX_GRAS_SC_CONTROL_RASTER_MODE(1)); OUT_PKT0(ring, REG_A4XX_PC_PRIM_VTX_CNTL, 1); OUT_RING(ring, A4XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST); OUT_PKT0(ring, REG_A4XX_GRAS_ALPHA_CONTROL, 1); OUT_RING(ring, 0x00000002); OUT_PKT0(ring, REG_A4XX_GRAS_SC_WINDOW_SCISSOR_BR, 2); OUT_RING(ring, A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X(pfb->width - 1) | A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(pfb->height - 1)); OUT_RING(ring, A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X(0) | A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(0)); OUT_PKT0(ring, REG_A4XX_VFD_INDEX_OFFSET, 2); OUT_RING(ring, 0); /* VFD_INDEX_OFFSET */ OUT_RING(ring, 0); /* ??? UNKNOWN_2209 */ fd4_program_emit(ring, &emit); fd4_emit_vertex_bufs(ring, &emit); if (ctx->resolve & (FD_BUFFER_DEPTH | FD_BUFFER_STENCIL)) { uint32_t base = depth_base(ctx); emit_gmem2mem_surf(ctx, base, pfb->zsbuf); } if (ctx->resolve & FD_BUFFER_COLOR) { emit_gmem2mem_surf(ctx, 0, pfb->cbufs[0]); } OUT_PKT0(ring, REG_A4XX_GRAS_SC_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SC_CONTROL_RENDER_MODE(RB_RENDERING_PASS) | A4XX_GRAS_SC_CONTROL_MSAA_DISABLE | A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(MSAA_ONE) | A4XX_GRAS_SC_CONTROL_RASTER_MODE(0)); } /* transfer from system memory to gmem */ static void emit_mem2gmem_surf(struct fd_context *ctx, uint32_t base, struct pipe_surface *psurf, uint32_t bin_w) { struct fd_ringbuffer *ring = ctx->ring; emit_mrt(ring, 1, &psurf, &base, bin_w); fd4_emit_gmem_restore_tex(ring, psurf); fd4_draw(ctx, ring, DI_PT_RECTLIST, IGNORE_VISIBILITY, DI_SRC_SEL_AUTO_INDEX, 2, 1, INDEX_SIZE_IGN, 0, 0, NULL); } static void fd4_emit_tile_mem2gmem(struct fd_context *ctx, struct fd_tile *tile) { struct fd4_context *fd4_ctx = fd4_context(ctx); struct fd_gmem_stateobj *gmem = &ctx->gmem; struct fd_ringbuffer *ring = ctx->ring; struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd4_emit emit = { .vtx = &fd4_ctx->blit_vbuf_state, .prog = &ctx->blit_prog[0], .key = key, .format = fd4_emit_format(pfb->cbufs[0]), }; float x0, y0, x1, y1; unsigned bin_w = tile->bin_w; unsigned bin_h = tile->bin_h; unsigned i; /* write texture coordinates to vertexbuf: */ x0 = ((float)tile->xoff) / ((float)pfb->width); x1 = ((float)tile->xoff + bin_w) / ((float)pfb->width); y0 = ((float)tile->yoff) / ((float)pfb->height); y1 = ((float)tile->yoff + bin_h) / ((float)pfb->height); OUT_PKT3(ring, CP_MEM_WRITE, 5); OUT_RELOCW(ring, fd_resource(fd4_ctx->blit_texcoord_vbuf)->bo, 0, 0, 0); OUT_RING(ring, fui(x0)); OUT_RING(ring, fui(y0)); OUT_RING(ring, fui(x1)); OUT_RING(ring, fui(y1)); for (i = 0; i < 8; i++) { OUT_PKT0(ring, REG_A4XX_RB_MRT_CONTROL(i), 1); OUT_RING(ring, A4XX_RB_MRT_CONTROL_FASTCLEAR | A4XX_RB_MRT_CONTROL_B11 | A4XX_RB_MRT_CONTROL_COMPONENT_ENABLE(0xf)); OUT_PKT0(ring, REG_A4XX_RB_MRT_BLEND_CONTROL(i), 1); OUT_RING(ring, A4XX_RB_MRT_BLEND_CONTROL_RGB_SRC_FACTOR(FACTOR_ONE) | A4XX_RB_MRT_BLEND_CONTROL_RGB_BLEND_OPCODE(BLEND_DST_PLUS_SRC) | A4XX_RB_MRT_BLEND_CONTROL_RGB_DEST_FACTOR(FACTOR_ZERO) | A4XX_RB_MRT_BLEND_CONTROL_ALPHA_SRC_FACTOR(FACTOR_ONE) | A4XX_RB_MRT_BLEND_CONTROL_ALPHA_BLEND_OPCODE(BLEND_DST_PLUS_SRC) | A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(FACTOR_ZERO)); } OUT_PKT0(ring, REG_A4XX_RB_RENDER_CONTROL, 1); OUT_RING(ring, 0x8); /* XXX RB_RENDER_CONTROL */ OUT_PKT0(ring, REG_A4XX_RB_DEPTH_CONTROL, 1); OUT_RING(ring, A4XX_RB_DEPTH_CONTROL_ZFUNC(FUNC_LESS)); OUT_PKT0(ring, REG_A4XX_GRAS_CL_CLIP_CNTL, 1); OUT_RING(ring, 0x280000); /* XXX GRAS_CL_CLIP_CNTL */ OUT_PKT0(ring, REG_A4XX_GRAS_SU_MODE_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(0) | A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS); OUT_PKT0(ring, REG_A4XX_GRAS_CL_VPORT_XOFFSET_0, 6); OUT_RING(ring, A4XX_GRAS_CL_VPORT_XOFFSET_0((float)bin_w/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_XSCALE_0((float)bin_w/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_YOFFSET_0((float)bin_h/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_YSCALE_0(-(float)bin_h/2.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_ZOFFSET_0(0.0)); OUT_RING(ring, A4XX_GRAS_CL_VPORT_ZSCALE_0(1.0)); OUT_PKT0(ring, REG_A4XX_GRAS_SC_WINDOW_SCISSOR_BR, 2); OUT_RING(ring, A4XX_GRAS_SC_WINDOW_SCISSOR_BR_X(bin_w - 1) | A4XX_GRAS_SC_WINDOW_SCISSOR_BR_Y(bin_h - 1)); OUT_RING(ring, A4XX_GRAS_SC_WINDOW_SCISSOR_TL_X(0) | A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(0)); OUT_PKT0(ring, REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL, 2); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X(0) | A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(0)); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X(bin_w - 1) | A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(bin_h - 1)); OUT_PKT0(ring, REG_A4XX_RB_MODE_CONTROL, 1); OUT_RING(ring, A4XX_RB_MODE_CONTROL_WIDTH(gmem->bin_w) | A4XX_RB_MODE_CONTROL_HEIGHT(gmem->bin_h)); OUT_PKT0(ring, REG_A4XX_RB_STENCIL_CONTROL, 2); OUT_RING(ring, A4XX_RB_STENCIL_CONTROL_FUNC(FUNC_ALWAYS) | A4XX_RB_STENCIL_CONTROL_FAIL(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZPASS(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZFAIL(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_FUNC_BF(FUNC_ALWAYS) | A4XX_RB_STENCIL_CONTROL_FAIL_BF(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZPASS_BF(STENCIL_KEEP) | A4XX_RB_STENCIL_CONTROL_ZFAIL_BF(STENCIL_KEEP)); OUT_RING(ring, 0x00000000); /* RB_STENCIL_CONTROL2 */ OUT_PKT0(ring, REG_A4XX_GRAS_SC_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SC_CONTROL_RENDER_MODE(RB_RENDERING_PASS) | A4XX_GRAS_SC_CONTROL_MSAA_DISABLE | A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(MSAA_ONE) | A4XX_GRAS_SC_CONTROL_RASTER_MODE(1)); OUT_PKT0(ring, REG_A4XX_PC_PRIM_VTX_CNTL, 1); OUT_RING(ring, A4XX_PC_PRIM_VTX_CNTL_PROVOKING_VTX_LAST | A4XX_PC_PRIM_VTX_CNTL_VAROUT(1)); OUT_PKT0(ring, REG_A4XX_VFD_INDEX_OFFSET, 2); OUT_RING(ring, 0); /* VFD_INDEX_OFFSET */ OUT_RING(ring, 0); /* ??? UNKNOWN_2209 */ fd4_program_emit(ring, &emit); fd4_emit_vertex_bufs(ring, &emit); /* for gmem pitch/base calculations, we need to use the non- * truncated tile sizes: */ bin_w = gmem->bin_w; bin_h = gmem->bin_h; if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_DEPTH | FD_BUFFER_STENCIL)) emit_mem2gmem_surf(ctx, depth_base(ctx), pfb->zsbuf, bin_w); if (fd_gmem_needs_restore(ctx, tile, FD_BUFFER_COLOR)) emit_mem2gmem_surf(ctx, 0, pfb->cbufs[0], bin_w); OUT_PKT0(ring, REG_A4XX_GRAS_SC_CONTROL, 1); OUT_RING(ring, A4XX_GRAS_SC_CONTROL_RENDER_MODE(RB_RENDERING_PASS) | A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(MSAA_ONE) | A4XX_GRAS_SC_CONTROL_RASTER_MODE(0)); OUT_PKT0(ring, REG_A4XX_RB_MODE_CONTROL, 1); OUT_RING(ring, A4XX_RB_MODE_CONTROL_WIDTH(gmem->bin_w) | A4XX_RB_MODE_CONTROL_HEIGHT(gmem->bin_h) | 0x00010000); /* XXX */ } static void patch_draws(struct fd_context *ctx, enum pc_di_vis_cull_mode vismode) { unsigned i; for (i = 0; i < fd_patch_num_elements(&ctx->draw_patches); i++) { struct fd_cs_patch *patch = fd_patch_element(&ctx->draw_patches, i); *patch->cs = patch->val | DRAW4(0, 0, 0, vismode); } util_dynarray_resize(&ctx->draw_patches, 0); } static void patch_rbrc(struct fd_context *ctx, uint32_t val) { struct fd4_context *fd4_ctx = fd4_context(ctx); unsigned i; for (i = 0; i < fd_patch_num_elements(&fd4_ctx->rbrc_patches); i++) { struct fd_cs_patch *patch = fd_patch_element(&fd4_ctx->rbrc_patches, i); *patch->cs = patch->val | val; } util_dynarray_resize(&fd4_ctx->rbrc_patches, 0); } /* for rendering directly to system memory: */ static void fd4_emit_sysmem_prep(struct fd_context *ctx) { struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd_ringbuffer *ring = ctx->ring; fd4_emit_restore(ctx); OUT_PKT0(ring, REG_A4XX_RB_FRAME_BUFFER_DIMENSION, 1); OUT_RING(ring, A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(pfb->width) | A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(pfb->height)); emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, 0); /* setup scissor/offset for current tile: */ OUT_PKT0(ring, REG_A4XX_RB_BIN_OFFSET, 1); OUT_RING(ring, A4XX_RB_BIN_OFFSET_X(0) | A4XX_RB_BIN_OFFSET_Y(0)); OUT_PKT0(ring, REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL, 2); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X(0) | A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(0)); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X(pfb->width - 1) | A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(pfb->height - 1)); OUT_PKT0(ring, REG_A4XX_RB_MODE_CONTROL, 1); OUT_RING(ring, A4XX_RB_MODE_CONTROL_WIDTH(0) | A4XX_RB_MODE_CONTROL_HEIGHT(0) | 0x00c00000); /* XXX */ patch_draws(ctx, IGNORE_VISIBILITY); patch_rbrc(ctx, 0); // XXX } static void update_vsc_pipe(struct fd_context *ctx) { struct fd4_context *fd4_ctx = fd4_context(ctx); struct fd_ringbuffer *ring = ctx->ring; int i; OUT_PKT0(ring, REG_A4XX_VSC_SIZE_ADDRESS, 1); OUT_RELOCW(ring, fd4_ctx->vsc_size_mem, 0, 0, 0); /* VSC_SIZE_ADDRESS */ OUT_PKT0(ring, REG_A4XX_VSC_PIPE_CONFIG_REG(0), 8); for (i = 0; i < 8; i++) { struct fd_vsc_pipe *pipe = &ctx->pipe[i]; OUT_RING(ring, A4XX_VSC_PIPE_CONFIG_REG_X(pipe->x) | A4XX_VSC_PIPE_CONFIG_REG_Y(pipe->y) | A4XX_VSC_PIPE_CONFIG_REG_W(pipe->w) | A4XX_VSC_PIPE_CONFIG_REG_H(pipe->h)); } OUT_PKT0(ring, REG_A4XX_VSC_PIPE_DATA_ADDRESS_REG(0), 8); for (i = 0; i < 8; i++) { struct fd_vsc_pipe *pipe = &ctx->pipe[i]; if (!pipe->bo) { pipe->bo = fd_bo_new(ctx->dev, 0x40000, DRM_FREEDRENO_GEM_TYPE_KMEM); } OUT_RELOCW(ring, pipe->bo, 0, 0, 0); /* VSC_PIPE_DATA_ADDRESS[i] */ } OUT_PKT0(ring, REG_A4XX_VSC_PIPE_DATA_LENGTH_REG(0), 8); for (i = 0; i < 8; i++) { struct fd_vsc_pipe *pipe = &ctx->pipe[i]; OUT_RING(ring, fd_bo_size(pipe->bo) - 32); /* VSC_PIPE_DATA_LENGTH[i] */ } } /* before first tile */ static void fd4_emit_tile_init(struct fd_context *ctx) { struct fd_ringbuffer *ring = ctx->ring; struct fd_gmem_stateobj *gmem = &ctx->gmem; uint32_t rb_render_control; fd4_emit_restore(ctx); OUT_PKT0(ring, REG_A4XX_VSC_BIN_SIZE, 1); OUT_RING(ring, A4XX_VSC_BIN_SIZE_WIDTH(gmem->bin_w) | A4XX_VSC_BIN_SIZE_HEIGHT(gmem->bin_h)); OUT_PKT0(ring, REG_A4XX_RB_MODE_CONTROL, 1); OUT_RING(ring, A4XX_RB_MODE_CONTROL_WIDTH(gmem->bin_w) | A4XX_RB_MODE_CONTROL_HEIGHT(gmem->bin_h) | 0x00010000); /* XXX */ update_vsc_pipe(ctx); patch_draws(ctx, IGNORE_VISIBILITY); rb_render_control = 0; // XXX or BINNING_PASS.. but maybe we can emit only from gmem patch_rbrc(ctx, rb_render_control); } /* before mem2gmem */ static void fd4_emit_tile_prep(struct fd_context *ctx, struct fd_tile *tile) { struct fd_ringbuffer *ring = ctx->ring; struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct fd_gmem_stateobj *gmem = &ctx->gmem; uint32_t reg; OUT_PKT0(ring, REG_A4XX_RB_DEPTH_INFO, 3); reg = A4XX_RB_DEPTH_INFO_DEPTH_BASE(depth_base(ctx)); if (pfb->zsbuf) { reg |= A4XX_RB_DEPTH_INFO_DEPTH_FORMAT(fd4_pipe2depth(pfb->zsbuf->format)); } OUT_RING(ring, reg); if (pfb->zsbuf) { uint32_t cpp = util_format_get_blocksize(pfb->zsbuf->format); OUT_RING(ring, A4XX_RB_DEPTH_PITCH(cpp * gmem->bin_w)); OUT_RING(ring, A4XX_RB_DEPTH_PITCH2(cpp * gmem->bin_w)); } else { OUT_RING(ring, 0x00000000); OUT_RING(ring, 0x00000000); } OUT_PKT0(ring, REG_A4XX_GRAS_DEPTH_CONTROL, 1); if (pfb->zsbuf) { OUT_RING(ring, A4XX_GRAS_DEPTH_CONTROL_FORMAT( fd4_pipe2depth(pfb->zsbuf->format))); } else { OUT_RING(ring, A4XX_GRAS_DEPTH_CONTROL_FORMAT(DEPTH4_NONE)); } if (ctx->needs_rb_fbd) { fd_wfi(ctx, ring); OUT_PKT0(ring, REG_A4XX_RB_FRAME_BUFFER_DIMENSION, 1); OUT_RING(ring, A4XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(pfb->width) | A4XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(pfb->height)); ctx->needs_rb_fbd = false; } } /* before IB to rendering cmds: */ static void fd4_emit_tile_renderprep(struct fd_context *ctx, struct fd_tile *tile) { struct fd_ringbuffer *ring = ctx->ring; struct fd_gmem_stateobj *gmem = &ctx->gmem; struct pipe_framebuffer_state *pfb = &ctx->framebuffer; uint32_t x1 = tile->xoff; uint32_t y1 = tile->yoff; uint32_t x2 = tile->xoff + tile->bin_w - 1; uint32_t y2 = tile->yoff + tile->bin_h - 1; OUT_PKT3(ring, CP_SET_BIN, 3); OUT_RING(ring, 0x00000000); OUT_RING(ring, CP_SET_BIN_1_X1(x1) | CP_SET_BIN_1_Y1(y1)); OUT_RING(ring, CP_SET_BIN_2_X2(x2) | CP_SET_BIN_2_Y2(y2)); emit_mrt(ring, pfb->nr_cbufs, pfb->cbufs, NULL, gmem->bin_w); /* setup scissor/offset for current tile: */ OUT_PKT0(ring, REG_A4XX_RB_BIN_OFFSET, 1); OUT_RING(ring, A4XX_RB_BIN_OFFSET_X(tile->xoff) | A4XX_RB_BIN_OFFSET_Y(tile->yoff)); OUT_PKT0(ring, REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL, 2); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_TL_X(x1) | A4XX_GRAS_SC_SCREEN_SCISSOR_TL_Y(y1)); OUT_RING(ring, A4XX_GRAS_SC_SCREEN_SCISSOR_BR_X(x2) | A4XX_GRAS_SC_SCREEN_SCISSOR_BR_Y(y2)); } void fd4_gmem_init(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); ctx->emit_sysmem_prep = fd4_emit_sysmem_prep; ctx->emit_tile_init = fd4_emit_tile_init; ctx->emit_tile_prep = fd4_emit_tile_prep; ctx->emit_tile_mem2gmem = fd4_emit_tile_mem2gmem; ctx->emit_tile_renderprep = fd4_emit_tile_renderprep; ctx->emit_tile_gmem2mem = fd4_emit_tile_gmem2mem; }
void fd4_program_emit(struct fd_ringbuffer *ring, struct fd4_emit *emit, int nr, struct pipe_surface **bufs) { struct stage s[MAX_STAGES]; uint32_t pos_regid, posz_regid, psize_regid, color_regid[8]; uint32_t face_regid, coord_regid, zwcoord_regid; enum a3xx_threadsize fssz; int constmode; int i, j, k; debug_assert(nr <= ARRAY_SIZE(color_regid)); if (emit->key.binning_pass) nr = 0; setup_stages(emit, s); fssz = (s[FS].i->max_reg >= 24) ? TWO_QUADS : FOUR_QUADS; /* blob seems to always use constmode currently: */ constmode = 1; pos_regid = ir3_find_output_regid(s[VS].v, VARYING_SLOT_POS); if (pos_regid == regid(63, 0)) { /* hw dislikes when there is no position output, which can * happen for transform-feedback vertex shaders. Just tell * the hw to use r0.x, with whatever random value is there: */ pos_regid = regid(0, 0); } posz_regid = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DEPTH); psize_regid = ir3_find_output_regid(s[VS].v, VARYING_SLOT_PSIZ); if (s[FS].v->color0_mrt) { color_regid[0] = color_regid[1] = color_regid[2] = color_regid[3] = color_regid[4] = color_regid[5] = color_regid[6] = color_regid[7] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_COLOR); } else { color_regid[0] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA0); color_regid[1] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA1); color_regid[2] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA2); color_regid[3] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA3); color_regid[4] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA4); color_regid[5] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA5); color_regid[6] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA6); color_regid[7] = ir3_find_output_regid(s[FS].v, FRAG_RESULT_DATA7); } /* TODO get these dynamically: */ face_regid = s[FS].v->frag_face ? regid(0,0) : regid(63,0); coord_regid = s[FS].v->frag_coord ? regid(0,0) : regid(63,0); zwcoord_regid = s[FS].v->frag_coord ? regid(0,2) : regid(63,0); /* we could probably divide this up into things that need to be * emitted if frag-prog is dirty vs if vert-prog is dirty.. */ OUT_PKT0(ring, REG_A4XX_HLSQ_UPDATE_CONTROL, 1); OUT_RING(ring, 0x00000003); OUT_PKT0(ring, REG_A4XX_HLSQ_CONTROL_0_REG, 5); OUT_RING(ring, A4XX_HLSQ_CONTROL_0_REG_FSTHREADSIZE(fssz) | A4XX_HLSQ_CONTROL_0_REG_CONSTMODE(constmode) | A4XX_HLSQ_CONTROL_0_REG_FSSUPERTHREADENABLE | /* NOTE: I guess SHADERRESTART and CONSTFULLUPDATE maybe * flush some caches? I think we only need to set those * bits if we have updated const or shader.. */ A4XX_HLSQ_CONTROL_0_REG_SPSHADERRESTART | A4XX_HLSQ_CONTROL_0_REG_SPCONSTFULLUPDATE); OUT_RING(ring, A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE(TWO_QUADS) | A4XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE | A4XX_HLSQ_CONTROL_1_REG_COORDREGID(coord_regid) | A4XX_HLSQ_CONTROL_1_REG_ZWCOORDREGID(zwcoord_regid)); OUT_RING(ring, A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD(63) | 0x3f3f000 | /* XXX */ A4XX_HLSQ_CONTROL_2_REG_FACEREGID(face_regid)); OUT_RING(ring, A4XX_HLSQ_CONTROL_3_REG_REGID(s[FS].v->pos_regid) | 0xfcfcfc00); OUT_RING(ring, 0x00fcfcfc); /* XXX HLSQ_CONTROL_4 */ OUT_PKT0(ring, REG_A4XX_HLSQ_VS_CONTROL_REG, 5); OUT_RING(ring, A4XX_HLSQ_VS_CONTROL_REG_CONSTLENGTH(s[VS].constlen) | A4XX_HLSQ_VS_CONTROL_REG_CONSTOBJECTOFFSET(s[VS].constoff) | A4XX_HLSQ_VS_CONTROL_REG_INSTRLENGTH(s[VS].instrlen) | A4XX_HLSQ_VS_CONTROL_REG_SHADEROBJOFFSET(s[VS].instroff)); OUT_RING(ring, A4XX_HLSQ_FS_CONTROL_REG_CONSTLENGTH(s[FS].constlen) | A4XX_HLSQ_FS_CONTROL_REG_CONSTOBJECTOFFSET(s[FS].constoff) | A4XX_HLSQ_FS_CONTROL_REG_INSTRLENGTH(s[FS].instrlen) | A4XX_HLSQ_FS_CONTROL_REG_SHADEROBJOFFSET(s[FS].instroff)); OUT_RING(ring, A4XX_HLSQ_HS_CONTROL_REG_CONSTLENGTH(s[HS].constlen) | A4XX_HLSQ_HS_CONTROL_REG_CONSTOBJECTOFFSET(s[HS].constoff) | A4XX_HLSQ_HS_CONTROL_REG_INSTRLENGTH(s[HS].instrlen) | A4XX_HLSQ_HS_CONTROL_REG_SHADEROBJOFFSET(s[HS].instroff)); OUT_RING(ring, A4XX_HLSQ_DS_CONTROL_REG_CONSTLENGTH(s[DS].constlen) | A4XX_HLSQ_DS_CONTROL_REG_CONSTOBJECTOFFSET(s[DS].constoff) | A4XX_HLSQ_DS_CONTROL_REG_INSTRLENGTH(s[DS].instrlen) | A4XX_HLSQ_DS_CONTROL_REG_SHADEROBJOFFSET(s[DS].instroff)); OUT_RING(ring, A4XX_HLSQ_GS_CONTROL_REG_CONSTLENGTH(s[GS].constlen) | A4XX_HLSQ_GS_CONTROL_REG_CONSTOBJECTOFFSET(s[GS].constoff) | A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(s[GS].instrlen) | A4XX_HLSQ_GS_CONTROL_REG_SHADEROBJOFFSET(s[GS].instroff)); OUT_PKT0(ring, REG_A4XX_SP_SP_CTRL_REG, 1); OUT_RING(ring, 0x140010 | /* XXX */ COND(emit->key.binning_pass, A4XX_SP_SP_CTRL_REG_BINNING_PASS)); OUT_PKT0(ring, REG_A4XX_SP_INSTR_CACHE_CTRL, 1); OUT_RING(ring, 0x7f | /* XXX */ COND(s[VS].instrlen, A4XX_SP_INSTR_CACHE_CTRL_VS_BUFFER) | COND(s[FS].instrlen, A4XX_SP_INSTR_CACHE_CTRL_FS_BUFFER) | COND(s[VS].instrlen && s[FS].instrlen, A4XX_SP_INSTR_CACHE_CTRL_INSTR_BUFFER)); OUT_PKT0(ring, REG_A4XX_SP_VS_LENGTH_REG, 1); OUT_RING(ring, s[VS].v->instrlen); /* SP_VS_LENGTH_REG */ OUT_PKT0(ring, REG_A4XX_SP_VS_CTRL_REG0, 3); OUT_RING(ring, A4XX_SP_VS_CTRL_REG0_THREADMODE(MULTI) | A4XX_SP_VS_CTRL_REG0_HALFREGFOOTPRINT(s[VS].i->max_half_reg + 1) | A4XX_SP_VS_CTRL_REG0_FULLREGFOOTPRINT(s[VS].i->max_reg + 1) | A4XX_SP_VS_CTRL_REG0_INOUTREGOVERLAP(0) | A4XX_SP_VS_CTRL_REG0_THREADSIZE(TWO_QUADS) | A4XX_SP_VS_CTRL_REG0_SUPERTHREADMODE | COND(s[VS].v->has_samp, A4XX_SP_VS_CTRL_REG0_PIXLODENABLE)); OUT_RING(ring, A4XX_SP_VS_CTRL_REG1_CONSTLENGTH(s[VS].constlen) | A4XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(s[VS].v->total_in)); OUT_RING(ring, A4XX_SP_VS_PARAM_REG_POSREGID(pos_regid) | A4XX_SP_VS_PARAM_REG_PSIZEREGID(psize_regid) | A4XX_SP_VS_PARAM_REG_TOTALVSOUTVAR(s[FS].v->varying_in)); for (i = 0, j = -1; (i < 16) && (j < (int)s[FS].v->inputs_count); i++) { uint32_t reg = 0; OUT_PKT0(ring, REG_A4XX_SP_VS_OUT_REG(i), 1); j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) { k = ir3_find_output(s[VS].v, s[FS].v->inputs[j].slot); reg |= A4XX_SP_VS_OUT_REG_A_REGID(s[VS].v->outputs[k].regid); reg |= A4XX_SP_VS_OUT_REG_A_COMPMASK(s[FS].v->inputs[j].compmask); } j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) { k = ir3_find_output(s[VS].v, s[FS].v->inputs[j].slot); reg |= A4XX_SP_VS_OUT_REG_B_REGID(s[VS].v->outputs[k].regid); reg |= A4XX_SP_VS_OUT_REG_B_COMPMASK(s[FS].v->inputs[j].compmask); } OUT_RING(ring, reg); } for (i = 0, j = -1; (i < 8) && (j < (int)s[FS].v->inputs_count); i++) { uint32_t reg = 0; OUT_PKT0(ring, REG_A4XX_SP_VS_VPC_DST_REG(i), 1); j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) reg |= A4XX_SP_VS_VPC_DST_REG_OUTLOC0(s[FS].v->inputs[j].inloc); j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) reg |= A4XX_SP_VS_VPC_DST_REG_OUTLOC1(s[FS].v->inputs[j].inloc); j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) reg |= A4XX_SP_VS_VPC_DST_REG_OUTLOC2(s[FS].v->inputs[j].inloc); j = ir3_next_varying(s[FS].v, j); if (j < s[FS].v->inputs_count) reg |= A4XX_SP_VS_VPC_DST_REG_OUTLOC3(s[FS].v->inputs[j].inloc); OUT_RING(ring, reg); } OUT_PKT0(ring, REG_A4XX_SP_VS_OBJ_OFFSET_REG, 2); OUT_RING(ring, A4XX_SP_VS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[VS].constoff) | A4XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[VS].instroff)); OUT_RELOC(ring, s[VS].v->bo, 0, 0, 0); /* SP_VS_OBJ_START_REG */ if (emit->key.binning_pass) { OUT_PKT0(ring, REG_A4XX_SP_FS_LENGTH_REG, 1); OUT_RING(ring, 0x00000000); /* SP_FS_LENGTH_REG */ OUT_PKT0(ring, REG_A4XX_SP_FS_CTRL_REG0, 2); OUT_RING(ring, A4XX_SP_FS_CTRL_REG0_THREADMODE(MULTI) | COND(s[FS].v->total_in > 0, A4XX_SP_FS_CTRL_REG0_VARYING) | A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(0) | A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(0) | A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP(1) | A4XX_SP_FS_CTRL_REG0_THREADSIZE(fssz) | A4XX_SP_FS_CTRL_REG0_SUPERTHREADMODE); OUT_RING(ring, A4XX_SP_FS_CTRL_REG1_CONSTLENGTH(s[FS].constlen) | 0x80000000); OUT_PKT0(ring, REG_A4XX_SP_FS_OBJ_OFFSET_REG, 2); OUT_RING(ring, A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[FS].constoff) | A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[FS].instroff)); OUT_RING(ring, 0x00000000); } else { OUT_PKT0(ring, REG_A4XX_SP_FS_LENGTH_REG, 1); OUT_RING(ring, s[FS].v->instrlen); /* SP_FS_LENGTH_REG */ OUT_PKT0(ring, REG_A4XX_SP_FS_CTRL_REG0, 2); OUT_RING(ring, A4XX_SP_FS_CTRL_REG0_THREADMODE(MULTI) | COND(s[FS].v->total_in > 0, A4XX_SP_FS_CTRL_REG0_VARYING) | A4XX_SP_FS_CTRL_REG0_HALFREGFOOTPRINT(s[FS].i->max_half_reg + 1) | A4XX_SP_FS_CTRL_REG0_FULLREGFOOTPRINT(s[FS].i->max_reg + 1) | A4XX_SP_FS_CTRL_REG0_INOUTREGOVERLAP(1) | A4XX_SP_FS_CTRL_REG0_THREADSIZE(fssz) | A4XX_SP_FS_CTRL_REG0_SUPERTHREADMODE | COND(s[FS].v->has_samp, A4XX_SP_FS_CTRL_REG0_PIXLODENABLE)); OUT_RING(ring, A4XX_SP_FS_CTRL_REG1_CONSTLENGTH(s[FS].constlen) | 0x80000000 | /* XXX */ COND(s[FS].v->frag_face, A4XX_SP_FS_CTRL_REG1_FACENESS) | COND(s[FS].v->total_in > 0, A4XX_SP_FS_CTRL_REG1_VARYING) | COND(s[FS].v->frag_coord, A4XX_SP_FS_CTRL_REG1_FRAGCOORD)); OUT_PKT0(ring, REG_A4XX_SP_FS_OBJ_OFFSET_REG, 2); OUT_RING(ring, A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[FS].constoff) | A4XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[FS].instroff)); OUT_RELOC(ring, s[FS].v->bo, 0, 0, 0); /* SP_FS_OBJ_START_REG */ } OUT_PKT0(ring, REG_A4XX_SP_HS_OBJ_OFFSET_REG, 1); OUT_RING(ring, A4XX_SP_HS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[HS].constoff) | A4XX_SP_HS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[HS].instroff)); OUT_PKT0(ring, REG_A4XX_SP_DS_OBJ_OFFSET_REG, 1); OUT_RING(ring, A4XX_SP_DS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[DS].constoff) | A4XX_SP_DS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[DS].instroff)); OUT_PKT0(ring, REG_A4XX_SP_GS_OBJ_OFFSET_REG, 1); OUT_RING(ring, A4XX_SP_GS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET(s[GS].constoff) | A4XX_SP_GS_OBJ_OFFSET_REG_SHADEROBJOFFSET(s[GS].instroff)); OUT_PKT0(ring, REG_A4XX_RB_RENDER_CONTROL2, 1); OUT_RING(ring, A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES(0) | COND(s[FS].v->total_in > 0, A4XX_RB_RENDER_CONTROL2_VARYING) | COND(s[FS].v->frag_face, A4XX_RB_RENDER_CONTROL2_FACENESS) | COND(s[FS].v->frag_coord, A4XX_RB_RENDER_CONTROL2_XCOORD | A4XX_RB_RENDER_CONTROL2_YCOORD | A4XX_RB_RENDER_CONTROL2_ZCOORD | A4XX_RB_RENDER_CONTROL2_WCOORD)); OUT_PKT0(ring, REG_A4XX_RB_FS_OUTPUT_REG, 1); OUT_RING(ring, A4XX_RB_FS_OUTPUT_REG_MRT(nr) | COND(s[FS].v->writes_pos, A4XX_RB_FS_OUTPUT_REG_FRAG_WRITES_Z)); OUT_PKT0(ring, REG_A4XX_SP_FS_OUTPUT_REG, 1); OUT_RING(ring, A4XX_SP_FS_OUTPUT_REG_MRT(nr) | COND(s[FS].v->writes_pos, A4XX_SP_FS_OUTPUT_REG_DEPTH_ENABLE) | A4XX_SP_FS_OUTPUT_REG_DEPTH_REGID(posz_regid)); OUT_PKT0(ring, REG_A4XX_SP_FS_MRT_REG(0), 8); for (i = 0; i < 8; i++) { enum a4xx_color_fmt format = 0; bool srgb = false; if (i < nr) { format = fd4_emit_format(bufs[i]); if (bufs[i] && !emit->no_decode_srgb) srgb = util_format_is_srgb(bufs[i]->format); } OUT_RING(ring, A4XX_SP_FS_MRT_REG_REGID(color_regid[i]) | A4XX_SP_FS_MRT_REG_MRTFORMAT(format) | COND(srgb, A4XX_SP_FS_MRT_REG_COLOR_SRGB) | COND(emit->key.half_precision, A4XX_SP_FS_MRT_REG_HALF_PRECISION)); } if (emit->key.binning_pass) { OUT_PKT0(ring, REG_A4XX_VPC_ATTR, 2); OUT_RING(ring, A4XX_VPC_ATTR_THRDASSIGN(1) | 0x40000000 | /* XXX */ COND(s[VS].v->writes_psize, A4XX_VPC_ATTR_PSIZE)); OUT_RING(ring, 0x00000000); } else { uint32_t vinterp[8], vpsrepl[8]; memset(vinterp, 0, sizeof(vinterp)); memset(vpsrepl, 0, sizeof(vpsrepl)); /* looks like we need to do int varyings in the frag * shader on a4xx (no flatshad reg? or a420.0 bug?): * * (sy)(ss)nop * (sy)ldlv.u32 r0.x,l[r0.x], 1 * ldlv.u32 r0.y,l[r0.x+1], 1 * (ss)bary.f (ei)r63.x, 0, r0.x * (ss)(rpt1)cov.s32f16 hr0.x, (r)r0.x * (rpt5)nop * sam (f16)(xyzw)hr0.x, hr0.x, s#0, t#0 * * Possibly on later a4xx variants we'll be able to use * something like the code below instead of workaround * in the shader: */ /* figure out VARYING_INTERP / VARYING_PS_REPL register values: */ for (j = -1; (j = ir3_next_varying(s[FS].v, j)) < (int)s[FS].v->inputs_count; ) { /* NOTE: varyings are packed, so if compmask is 0xb * then first, third, and fourth component occupy * three consecutive varying slots: */ unsigned compmask = s[FS].v->inputs[j].compmask; /* TODO might be cleaner to just +8 in SP_VS_VPC_DST_REG * instead.. rather than -8 everywhere else.. */ uint32_t inloc = s[FS].v->inputs[j].inloc - 8; if ((s[FS].v->inputs[j].interpolate == INTERP_MODE_FLAT) || (s[FS].v->inputs[j].rasterflat && emit->rasterflat)) { uint32_t loc = inloc; for (i = 0; i < 4; i++) { if (compmask & (1 << i)) { vinterp[loc / 16] |= 1 << ((loc % 16) * 2); //flatshade[loc / 32] |= 1 << (loc % 32); loc++; } } } gl_varying_slot slot = s[FS].v->inputs[j].slot; /* since we don't enable PIPE_CAP_TGSI_TEXCOORD: */ if (slot >= VARYING_SLOT_VAR0) { unsigned texmask = 1 << (slot - VARYING_SLOT_VAR0); /* Replace the .xy coordinates with S/T from the point sprite. Set * interpolation bits for .zw such that they become .01 */ if (emit->sprite_coord_enable & texmask) { /* mask is two 2-bit fields, where: * '01' -> S * '10' -> T * '11' -> 1 - T (flip mode) */ unsigned mask = emit->sprite_coord_mode ? 0b1101 : 0b1001; uint32_t loc = inloc; if (compmask & 0x1) { vpsrepl[loc / 16] |= ((mask >> 0) & 0x3) << ((loc % 16) * 2); loc++; } if (compmask & 0x2) { vpsrepl[loc / 16] |= ((mask >> 2) & 0x3) << ((loc % 16) * 2); loc++; } if (compmask & 0x4) { /* .z <- 0.0f */ vinterp[loc / 16] |= 0b10 << ((loc % 16) * 2); loc++; } if (compmask & 0x8) { /* .w <- 1.0f */ vinterp[loc / 16] |= 0b11 << ((loc % 16) * 2); loc++; } }