static void fd_clear(struct pipe_context *pctx, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct fd_context *ctx = fd_context(pctx); struct pipe_framebuffer_state *pfb = &ctx->framebuffer; ctx->cleared |= buffers; ctx->resolve |= buffers; ctx->needs_flush = true; if (buffers & PIPE_CLEAR_COLOR) fd_resource(pfb->cbufs[0]->texture)->dirty = true; if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { fd_resource(pfb->zsbuf->texture)->dirty = true; ctx->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL; } DBG("%x depth=%f, stencil=%u (%s/%s)", buffers, depth, stencil, util_format_short_name(pipe_surface_format(pfb->cbufs[0])), util_format_short_name(pipe_surface_format(pfb->zsbuf))); ctx->clear(ctx, buffers, color, depth, stencil); ctx->dirty |= FD_DIRTY_ZSA | FD_DIRTY_RASTERIZER | FD_DIRTY_SAMPLE_MASK | FD_DIRTY_PROG | FD_DIRTY_CONSTBUF | FD_DIRTY_BLEND; if (fd_mesa_debug & FD_DBG_DCLEAR) ctx->dirty = 0xffffffff; }
static void draw_emit_indirect(struct fd_batch *batch, struct fd_ringbuffer *ring, enum pc_di_primtype primtype, enum pc_di_vis_cull_mode vismode, const struct pipe_draw_info *info, unsigned index_offset) { struct fd_resource *ind = fd_resource(info->indirect->buffer); if (info->index_size) { struct pipe_resource *idx = info->index.resource; unsigned max_indicies = (idx->width0 - info->indirect->offset) / info->index_size; OUT_PKT7(ring, CP_DRAW_INDX_INDIRECT, 6); OUT_RINGP(ring, DRAW4(primtype, DI_SRC_SEL_DMA, fd4_size2indextype(info->index_size), 0), &batch->draw_patches); OUT_RELOC(ring, fd_resource(idx)->bo, index_offset, 0, 0); // XXX: Check A5xx vs A6xx OUT_RING(ring, A5XX_CP_DRAW_INDX_INDIRECT_3_MAX_INDICES(max_indicies)); OUT_RELOC(ring, ind->bo, info->indirect->offset, 0, 0); } else { OUT_PKT7(ring, CP_DRAW_INDIRECT, 3); OUT_RINGP(ring, DRAW4(primtype, DI_SRC_SEL_AUTO_INDEX, 0, 0), &batch->draw_patches); OUT_RELOC(ring, ind->bo, info->indirect->offset, 0, 0); } }
static void fd3_emit_const_bo(struct fd_ringbuffer *ring, enum shader_t type, boolean write, uint32_t regid, uint32_t num, struct pipe_resource **prscs, uint32_t *offsets) { uint32_t i; debug_assert((regid % 4) == 0); debug_assert((num % 4) == 0); OUT_PKT3(ring, CP_LOAD_STATE, 2 + num); OUT_RING(ring, CP_LOAD_STATE_0_DST_OFF(regid/2) | CP_LOAD_STATE_0_STATE_SRC(SS_DIRECT) | CP_LOAD_STATE_0_STATE_BLOCK(sb[type]) | CP_LOAD_STATE_0_NUM_UNIT(num/2)); OUT_RING(ring, CP_LOAD_STATE_1_EXT_SRC_ADDR(0) | CP_LOAD_STATE_1_STATE_TYPE(ST_CONSTANTS)); for (i = 0; i < num; i++) { if (prscs[i]) { if (write) { OUT_RELOCW(ring, fd_resource(prscs[i])->bo, offsets[i], 0, 0); } else { OUT_RELOC(ring, fd_resource(prscs[i])->bo, offsets[i], 0, 0); } } else { OUT_RING(ring, 0xbad00000 | (i << 16)); } } }
static void fd_clear(struct pipe_context *pctx, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct fd_context *ctx = fd_context(pctx); struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx); unsigned cleared_buffers; /* for bookkeeping about which buffers have been cleared (and thus * can fully or partially skip mem2gmem) we need to ignore buffers * that have already had a draw, in case apps do silly things like * clear after draw (ie. if you only clear the color buffer, but * something like alpha-test causes side effects from the draw in * the depth buffer, etc) */ cleared_buffers = buffers & (FD_BUFFER_ALL & ~ctx->restore); /* do we have full-screen scissor? */ if (!memcmp(scissor, &ctx->disabled_scissor, sizeof(*scissor))) { ctx->cleared |= cleared_buffers; } else { ctx->partial_cleared |= cleared_buffers; if (cleared_buffers & PIPE_CLEAR_COLOR) ctx->cleared_scissor.color = *scissor; if (cleared_buffers & PIPE_CLEAR_DEPTH) ctx->cleared_scissor.depth = *scissor; if (cleared_buffers & PIPE_CLEAR_STENCIL) ctx->cleared_scissor.stencil = *scissor; } ctx->resolve |= buffers; ctx->needs_flush = true; if (buffers & PIPE_CLEAR_COLOR) fd_resource(pfb->cbufs[0]->texture)->dirty = true; if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) { fd_resource(pfb->zsbuf->texture)->dirty = true; ctx->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL; } DBG("%x depth=%f, stencil=%u (%s/%s)", buffers, depth, stencil, util_format_short_name(pipe_surface_format(pfb->cbufs[0])), util_format_short_name(pipe_surface_format(pfb->zsbuf))); fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_CLEAR); ctx->clear(ctx, buffers, color, depth, stencil); ctx->dirty |= FD_DIRTY_ZSA | FD_DIRTY_VIEWPORT | FD_DIRTY_RASTERIZER | FD_DIRTY_SAMPLE_MASK | FD_DIRTY_PROG | FD_DIRTY_CONSTBUF | FD_DIRTY_BLEND; if (fd_mesa_debug & FD_DBG_DCLEAR) ctx->dirty = 0xffffffff; }
/* emit accumulated render cmds, needed for example if render target has * changed, or for flush() */ void fd_context_render(struct pipe_context *pctx) { struct fd_context *ctx = fd_context(pctx); struct pipe_framebuffer_state *pfb = &ctx->framebuffer; DBG("needs_flush: %d", ctx->needs_flush); if (!ctx->needs_flush) return; fd_gmem_render_tiles(pctx); DBG("%p/%p/%p", ctx->ring->start, ctx->ring->cur, ctx->ring->end); /* if size in dwords is more than half the buffer size, then wait and * wrap around: */ if ((ctx->ring->cur - ctx->ring->start) > ctx->ring->size/8) fd_context_next_rb(pctx); ctx->needs_flush = false; ctx->cleared = ctx->restore = ctx->resolve = 0; ctx->gmem_reason = 0; ctx->num_draws = 0; if (pfb->cbufs[0]) fd_resource(pfb->cbufs[0]->texture)->dirty = false; if (pfb->zsbuf) fd_resource(pfb->zsbuf->texture)->dirty = false; }
static void fd_clear(struct pipe_context *pctx, unsigned buffers, const union pipe_color_union *color, double depth, unsigned stencil) { struct fd_context *ctx = fd_context(pctx); struct fd_ringbuffer *ring = ctx->ring; struct pipe_framebuffer_state *fb = &ctx->framebuffer.base; uint32_t reg, colr = 0; ctx->cleared |= buffers; ctx->resolve |= buffers; ctx->needs_flush = true; if (buffers & PIPE_CLEAR_COLOR) fd_resource(fb->cbufs[0]->texture)->dirty = true; if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) fd_resource(fb->zsbuf->texture)->dirty = true; DBG("depth=%f, stencil=%u", depth, stencil); if ((buffers & PIPE_CLEAR_COLOR) && fb->nr_cbufs) colr = pack_rgba(fb->cbufs[0]->format, color->f); /* emit generic state now: */ fd_state_emit(pctx, ctx->dirty & (FD_DIRTY_BLEND | FD_DIRTY_VIEWPORT | FD_DIRTY_FRAMEBUFFER | FD_DIRTY_SCISSOR)); fd_emit_vertex_bufs(ring, 0x9c, (struct fd_vertex_buf[]) { { .prsc = ctx->solid_vertexbuf, .size = 48 }, }, 1);
static void fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info) { struct fd_context *ctx = fd_context(pctx); struct pipe_framebuffer_state *pfb = &ctx->framebuffer; struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx); unsigned i, buffers = 0; /* if we supported transform feedback, we'd have to disable this: */ if (((scissor->maxx - scissor->minx) * (scissor->maxy - scissor->miny)) == 0) { return; } ctx->needs_flush = true; /* * Figure out the buffers/features we need: */ if (fd_depth_enabled(ctx)) { buffers |= FD_BUFFER_DEPTH; fd_resource(pfb->zsbuf->texture)->dirty = true; ctx->gmem_reason |= FD_GMEM_DEPTH_ENABLED; } if (fd_stencil_enabled(ctx)) { buffers |= FD_BUFFER_STENCIL; fd_resource(pfb->zsbuf->texture)->dirty = true; ctx->gmem_reason |= FD_GMEM_STENCIL_ENABLED; } if (fd_logicop_enabled(ctx)) ctx->gmem_reason |= FD_GMEM_LOGICOP_ENABLED; for (i = 0; i < pfb->nr_cbufs; i++) { struct pipe_resource *surf = pfb->cbufs[i]->texture; fd_resource(surf)->dirty = true; buffers |= FD_BUFFER_COLOR; if (surf->nr_samples > 1) ctx->gmem_reason |= FD_GMEM_MSAA_ENABLED; if (fd_blend_enabled(ctx, i)) ctx->gmem_reason |= FD_GMEM_BLEND_ENABLED; } ctx->num_draws++; /* any buffers that haven't been cleared, we need to restore: */ ctx->restore |= buffers & (FD_BUFFER_ALL & ~ctx->cleared); /* and any buffers used, need to be resolved: */ ctx->resolve |= buffers; ctx->draw(ctx, info); }
/* regid: base const register * prsc or dwords: buffer containing constant values * sizedwords: size of const value buffer */ void fd4_emit_constant(struct fd_ringbuffer *ring, enum adreno_state_block sb, uint32_t regid, uint32_t offset, uint32_t sizedwords, const uint32_t *dwords, struct pipe_resource *prsc) { uint32_t i, sz; enum adreno_state_src src; if (prsc) { sz = 0; src = 0x2; // TODO ?? } else { sz = sizedwords; src = SS_DIRECT; } OUT_PKT3(ring, CP_LOAD_STATE, 2 + sz); OUT_RING(ring, CP_LOAD_STATE_0_DST_OFF(regid/4) | CP_LOAD_STATE_0_STATE_SRC(src) | CP_LOAD_STATE_0_STATE_BLOCK(sb) | CP_LOAD_STATE_0_NUM_UNIT(sizedwords/4)); if (prsc) { struct fd_bo *bo = fd_resource(prsc)->bo; OUT_RELOC(ring, bo, offset, CP_LOAD_STATE_1_STATE_TYPE(ST_CONSTANTS), 0); } else { OUT_RING(ring, CP_LOAD_STATE_1_EXT_SRC_ADDR(0) | CP_LOAD_STATE_1_STATE_TYPE(ST_CONSTANTS)); dwords = (uint32_t *)&((uint8_t *)dwords)[offset]; } for (i = 0; i < sz; i++) { OUT_RING(ring, dwords[i]); } }
static struct pipe_sampler_view * fd3_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, const struct pipe_sampler_view *cso) { struct fd3_pipe_sampler_view *so = CALLOC_STRUCT(fd3_pipe_sampler_view); struct fd_resource *rsc = fd_resource(prsc); if (!so) return NULL; so->base = *cso; pipe_reference(NULL, &prsc->reference); so->base.texture = prsc; so->base.reference.count = 1; so->base.context = pctx; so->tex_resource = rsc; so->texconst0 = 0x40000000 | /* ??? */ A3XX_TEX_CONST_0_FMT(fd3_pipe2tex(cso->format)) | fd3_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, cso->swizzle_a); so->texconst1 = A3XX_TEX_CONST_1_FETCHSIZE(fd3_pipe2fetchsize(cso->format)) | A3XX_TEX_CONST_1_WIDTH(prsc->width0) | A3XX_TEX_CONST_1_HEIGHT(prsc->height0); /* when emitted, A3XX_TEX_CONST_2_INDX() must be OR'd in: */ so->texconst2 = A3XX_TEX_CONST_2_PITCH(rsc->pitch * rsc->cpp); so->texconst3 = 0x00000000; /* ??? */ return &so->base; }
static void emit_vertexbufs(struct fd_context *ctx) { struct fd_vertex_stateobj *vtx = ctx->vtx.vtx; struct fd_vertexbuf_stateobj *vertexbuf = &ctx->vtx.vertexbuf; struct fd2_vertex_buf bufs[PIPE_MAX_ATTRIBS]; unsigned i; if (!vtx->num_elements) 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; bufs[i].size = fd_bo_size(fd_resource(vb->buffer)->bo); bufs[i].prsc = vb->buffer; } // NOTE I believe the 0x78 (or 0x9c in solid_vp) relates to the // CONST(20,0) (or CONST(26,0) in soliv_vp) fd2_emit_vertex_bufs(ctx->ring, 0x78, bufs, vtx->num_elements); }
static void fd_resource_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans) { struct fd_context *ctx = fd_context(pctx); struct fd_resource *rsc = fd_resource(ptrans->resource); struct fd_transfer *trans = fd_transfer(ptrans); if (trans->staging && !(ptrans->usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) { struct pipe_box box; u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); fd_resource_flush(trans, &box); } if (!(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { fd_bo_cpu_fini(rsc->bo); if (rsc->stencil) fd_bo_cpu_fini(rsc->stencil->bo); } util_range_add(&rsc->valid_buffer_range, ptrans->box.x, ptrans->box.x + ptrans->box.width); pipe_resource_reference(&ptrans->resource, NULL); util_slab_free(&ctx->transfer_pool, ptrans); free(trans->staging); }
static void fd_resource_flush_z32s8(struct fd_transfer *trans, const struct pipe_box *box) { struct fd_resource *rsc = fd_resource(trans->base.resource); struct fd_resource_slice *slice = fd_resource_slice(rsc, trans->base.level); struct fd_resource_slice *sslice = fd_resource_slice(rsc->stencil, trans->base.level); enum pipe_format format = trans->base.resource->format; float *depth = fd_bo_map(rsc->bo) + slice->offset + fd_resource_layer_offset(rsc, slice, trans->base.box.z) + (trans->base.box.y + box->y) * slice->pitch * 4 + (trans->base.box.x + box->x) * 4; uint8_t *stencil = fd_bo_map(rsc->stencil->bo) + sslice->offset + fd_resource_layer_offset(rsc->stencil, sslice, trans->base.box.z) + (trans->base.box.y + box->y) * sslice->pitch + trans->base.box.x + box->x; if (format != PIPE_FORMAT_X32_S8X24_UINT) util_format_z32_float_s8x24_uint_unpack_z_float( depth, slice->pitch * 4, trans->staging, trans->base.stride, box->width, box->height); util_format_z32_float_s8x24_uint_unpack_s_8uint( stencil, sslice->pitch, trans->staging, trans->base.stride, box->width, box->height); }
static void fd5_emit_tile_gmem2mem(struct fd_batch *batch, struct fd_tile *tile) { struct fd_context *ctx = batch->ctx; struct fd_gmem_stateobj *gmem = &ctx->gmem; struct pipe_framebuffer_state *pfb = &batch->framebuffer; if (batch->resolve & (FD_BUFFER_DEPTH | FD_BUFFER_STENCIL)) { struct fd_resource *rsc = fd_resource(pfb->zsbuf->texture); // XXX BLIT_ZS vs BLIT_Z32 .. need some more cmdstream traces // with z32_x24s8.. if (!rsc->stencil || (batch->resolve & FD_BUFFER_DEPTH)) emit_gmem2mem_surf(batch, gmem->zsbuf_base[0], pfb->zsbuf, BLIT_ZS); if (rsc->stencil && (batch->resolve & FD_BUFFER_STENCIL)) emit_gmem2mem_surf(batch, gmem->zsbuf_base[1], pfb->zsbuf, BLIT_ZS); } if (batch->resolve & FD_BUFFER_COLOR) { unsigned i; for (i = 0; i < pfb->nr_cbufs; i++) { if (!pfb->cbufs[i]) continue; if (!(batch->resolve & (PIPE_CLEAR_COLOR0 << i))) continue; emit_gmem2mem_surf(batch, gmem->cbuf_base[i], pfb->cbufs[i], BLIT_MRT0 + i); } } }
static void emit_gmem2mem_surf(struct fd_batch *batch, uint32_t base, struct pipe_surface *psurf, enum a5xx_blit_buf buf) { struct fd_ringbuffer *ring = batch->gmem; struct fd_resource *rsc = fd_resource(psurf->texture); struct fd_resource_slice *slice; uint32_t offset; slice = fd_resource_slice(rsc, psurf->u.tex.level); offset = fd_resource_offset(rsc, psurf->u.tex.level, psurf->u.tex.first_layer); debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer); OUT_PKT4(ring, REG_A5XX_RB_BLIT_FLAG_DST_LO, 4); OUT_RING(ring, 0x00000000); /* RB_BLIT_FLAG_DST_LO */ OUT_RING(ring, 0x00000000); /* RB_BLIT_FLAG_DST_HI */ OUT_RING(ring, 0x00000000); /* RB_BLIT_FLAG_DST_PITCH */ OUT_RING(ring, 0x00000000); /* RB_BLIT_FLAG_DST_ARRAY_PITCH */ OUT_PKT4(ring, REG_A5XX_RB_RESOLVE_CNTL_3, 5); OUT_RING(ring, 0x00000004); /* XXX RB_RESOLVE_CNTL_3 */ OUT_RELOCW(ring, rsc->bo, offset, 0, 0); /* RB_BLIT_DST_LO/HI */ OUT_RING(ring, A5XX_RB_BLIT_DST_PITCH(slice->pitch * rsc->cpp)); OUT_RING(ring, A5XX_RB_BLIT_DST_ARRAY_PITCH(slice->size0)); OUT_PKT4(ring, REG_A5XX_RB_BLIT_CNTL, 1); OUT_RING(ring, A5XX_RB_BLIT_CNTL_BUF(buf)); fd5_emit_blit(batch->ctx, ring); }
static struct pipe_sampler_view * fd4_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, const struct pipe_sampler_view *cso) { struct fd4_pipe_sampler_view *so = CALLOC_STRUCT(fd4_pipe_sampler_view); struct fd_resource *rsc = fd_resource(prsc); unsigned lvl = fd_sampler_first_level(cso); unsigned miplevels = fd_sampler_last_level(cso) - lvl; if (!so) return NULL; so->base = *cso; pipe_reference(NULL, &prsc->reference); so->base.texture = prsc; so->base.reference.count = 1; so->base.context = pctx; so->texconst0 = A4XX_TEX_CONST_0_TYPE(tex_type(prsc->target)) | A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(cso->format)) | A4XX_TEX_CONST_0_MIPLVLS(miplevels) | fd4_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, cso->swizzle_a); if (util_format_is_srgb(cso->format)) so->texconst0 |= A4XX_TEX_CONST_0_SRGB; so->texconst1 = A4XX_TEX_CONST_1_WIDTH(u_minify(prsc->width0, lvl)) | A4XX_TEX_CONST_1_HEIGHT(u_minify(prsc->height0, lvl)); so->texconst2 = A4XX_TEX_CONST_2_FETCHSIZE(fd4_pipe2fetchsize(cso->format)) | A4XX_TEX_CONST_2_PITCH(rsc->slices[lvl].pitch * rsc->cpp); switch (prsc->target) { case PIPE_TEXTURE_1D_ARRAY: case PIPE_TEXTURE_2D_ARRAY: so->texconst3 = A4XX_TEX_CONST_3_DEPTH(prsc->array_size) | A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_CUBE: case PIPE_TEXTURE_CUBE_ARRAY: so->texconst3 = A4XX_TEX_CONST_3_DEPTH(prsc->array_size / 6) | A4XX_TEX_CONST_3_LAYERSZ(rsc->layer_size); break; case PIPE_TEXTURE_3D: so->texconst3 = A4XX_TEX_CONST_3_DEPTH(u_minify(prsc->depth0, lvl)) | A4XX_TEX_CONST_3_LAYERSZ(rsc->slices[0].size0); break; default: so->texconst3 = 0x00000000; break; } return &so->base; }
static void emit_gmem2mem_surf(struct fd_context *ctx, uint32_t base, struct pipe_surface *psurf) { struct fd_ringbuffer *ring = ctx->ring; struct fd_resource *rsc = fd_resource(psurf->texture); struct fd_resource_slice *slice = &rsc->slices[psurf->u.tex.level]; uint32_t offset = fd_resource_offset(rsc, psurf->u.tex.level, psurf->u.tex.first_layer); debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer); OUT_PKT0(ring, REG_A4XX_RB_COPY_CONTROL, 4); OUT_RING(ring, A4XX_RB_COPY_CONTROL_MSAA_RESOLVE(MSAA_ONE) | A4XX_RB_COPY_CONTROL_MODE(RB_COPY_RESOLVE) | A4XX_RB_COPY_CONTROL_GMEM_BASE(base)); OUT_RELOCW(ring, rsc->bo, offset, 0, 0); /* RB_COPY_DEST_BASE */ OUT_RING(ring, A4XX_RB_COPY_DEST_PITCH_PITCH(slice->pitch * rsc->cpp)); OUT_RING(ring, A4XX_RB_COPY_DEST_INFO_TILE(TILE4_LINEAR) | A4XX_RB_COPY_DEST_INFO_FORMAT(fd4_pipe2color(psurf->format)) | A4XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE(0xf) | A4XX_RB_COPY_DEST_INFO_ENDIAN(ENDIAN_NONE) | A4XX_RB_COPY_DEST_INFO_SWAP(fd4_pipe2swap(psurf->format))); fd4_draw(ctx, ring, DI_PT_RECTLIST, IGNORE_VISIBILITY, DI_SRC_SEL_AUTO_INDEX, 2, 1, INDEX_SIZE_IGN, 0, 0, NULL); }
static void emit_gmem2mem_surf(struct fd_ringbuffer *ring, uint32_t swap, uint32_t base, struct pipe_surface *psurf) { struct fd_resource *rsc = fd_resource(psurf->texture); OUT_PKT3(ring, CP_SET_CONSTANT, 2); OUT_RING(ring, CP_REG(REG_RB_COLOR_INFO)); OUT_RING(ring, RB_COLOR_INFO_COLOR_SWAP(swap) | RB_COLOR_INFO_COLOR_BASE(base / 1024) | RB_COLOR_INFO_COLOR_FORMAT(fd_pipe2color(psurf->format))); OUT_PKT3(ring, CP_SET_CONSTANT, 5); OUT_RING(ring, CP_REG(REG_RB_COPY_CONTROL)); OUT_RING(ring, 0x00000000); /* RB_COPY_CONTROL */ OUT_RELOC(ring, rsc->bo, 0, 0); /* RB_COPY_DEST_BASE */ OUT_RING(ring, rsc->pitch >> 5); /* RB_COPY_DEST_PITCH */ OUT_RING(ring, RB_COPY_DEST_INFO_FORMAT(fd_pipe2color(psurf->format)) | RB_COPY_DEST_INFO_LINEAR | /* RB_COPY_DEST_INFO */ RB_COPY_DEST_INFO_SWAP(swap) | RB_COPY_DEST_INFO_WRITE_RED | RB_COPY_DEST_INFO_WRITE_GREEN | RB_COPY_DEST_INFO_WRITE_BLUE | RB_COPY_DEST_INFO_WRITE_ALPHA); OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1); OUT_RING(ring, 0x0000000); OUT_PKT3(ring, CP_DRAW_INDX, 3); OUT_RING(ring, 0x00000000); OUT_RING(ring, DRAW(DI_PT_RECTLIST, DI_SRC_SEL_AUTO_INDEX, INDEX_SIZE_IGN, IGNORE_VISIBILITY)); OUT_RING(ring, 3); /* NumIndices */ }
static void * fd_resource_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **pptrans) { struct fd_context *ctx = fd_context(pctx); struct fd_resource *rsc = fd_resource(prsc); struct pipe_transfer *ptrans = util_slab_alloc(&ctx->transfer_pool); enum pipe_format format = prsc->format; char *buf; if (!ptrans) return NULL; ptrans->resource = prsc; ptrans->level = level; ptrans->usage = usage; ptrans->box = *box; ptrans->stride = rsc->pitch * rsc->cpp; ptrans->layer_stride = ptrans->stride; buf = fd_bo_map(rsc->bo); *pptrans = ptrans; return buf + box->y / util_format_get_blockheight(format) * ptrans->stride + box->x / util_format_get_blockwidth(format) * rsc->cpp; }
static struct pipe_stream_output_target * fd_create_stream_output_target(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned buffer_offset, unsigned buffer_size) { struct pipe_stream_output_target *target; struct fd_resource *rsc = fd_resource(prsc); target = CALLOC_STRUCT(pipe_stream_output_target); if (!target) return NULL; pipe_reference_init(&target->reference, 1); pipe_resource_reference(&target->buffer, prsc); target->context = pctx; target->buffer_offset = buffer_offset; target->buffer_size = buffer_size; assert(rsc->base.target == PIPE_BUFFER); util_range_add(&rsc->valid_buffer_range, buffer_offset, buffer_offset + buffer_size); return target; }
static void emit_gmem2mem_surf(struct fd_ringbuffer *ring, enum adreno_rb_copy_control_mode mode, uint32_t base, struct pipe_surface *psurf) { struct fd_resource *rsc = fd_resource(psurf->texture); OUT_PKT0(ring, REG_A3XX_RB_COPY_CONTROL, 4); OUT_RING(ring, A3XX_RB_COPY_CONTROL_MSAA_RESOLVE(MSAA_ONE) | A3XX_RB_COPY_CONTROL_MODE(mode) | A3XX_RB_COPY_CONTROL_GMEM_BASE(base)); OUT_RELOCW(ring, rsc->bo, 0, 0, -1); /* RB_COPY_DEST_BASE */ OUT_RING(ring, A3XX_RB_COPY_DEST_PITCH_PITCH(rsc->pitch * rsc->cpp)); OUT_RING(ring, A3XX_RB_COPY_DEST_INFO_TILE(LINEAR) | A3XX_RB_COPY_DEST_INFO_FORMAT(fd3_pipe2color(psurf->format)) | A3XX_RB_COPY_DEST_INFO_COMPONENT_ENABLE(0xf) | A3XX_RB_COPY_DEST_INFO_ENDIAN(ENDIAN_NONE) | A3XX_RB_COPY_DEST_INFO_SWAP(fd3_pipe2swap(psurf->format))); OUT_PKT3(ring, CP_DRAW_INDX, 3); OUT_RING(ring, 0x00000000); OUT_RING(ring, DRAW(DI_PT_RECTLIST, DI_SRC_SEL_AUTO_INDEX, INDEX_SIZE_IGN, IGNORE_VISIBILITY)); OUT_RING(ring, 2); /* NumIndices */ }
/* this is same for a2xx/a3xx, so split into helper: */ void fd_draw_emit(struct fd_context *ctx, struct fd_ringbuffer *ring, enum pc_di_vis_cull_mode vismode, const struct pipe_draw_info *info) { struct pipe_index_buffer *idx = &ctx->indexbuf; struct fd_bo *idx_bo = NULL; enum pc_di_index_size idx_type = INDEX_SIZE_IGN; enum pc_di_src_sel src_sel; uint32_t idx_size, idx_offset; if (info->indexed) { assert(!idx->user_buffer); idx_bo = fd_resource(idx->buffer)->bo; idx_type = size2indextype(idx->index_size); idx_size = idx->index_size * info->count; idx_offset = idx->offset; src_sel = DI_SRC_SEL_DMA; } else { idx_bo = NULL; idx_type = INDEX_SIZE_IGN; idx_size = 0; idx_offset = 0; src_sel = DI_SRC_SEL_AUTO_INDEX; } fd_draw(ctx, ring, ctx->primtypes[info->mode], vismode, src_sel, info->count, idx_type, idx_size, idx_offset, idx_bo); }
static texmask emit_texture(struct fd_ringbuffer *ring, struct fd_context *ctx, struct fd_texture_stateobj *tex, unsigned samp_id, texmask emitted) { unsigned const_idx = fd2_get_const_idx(ctx, tex, samp_id); static const struct fd2_sampler_stateobj dummy_sampler = {}; const struct fd2_sampler_stateobj *sampler; struct fd2_pipe_sampler_view *view; if (emitted & (1 << const_idx)) return 0; sampler = tex->samplers[samp_id] ? fd2_sampler_stateobj(tex->samplers[samp_id]) : &dummy_sampler; view = fd2_pipe_sampler_view(tex->textures[samp_id]); OUT_PKT3(ring, CP_SET_CONSTANT, 7); OUT_RING(ring, 0x00010000 + (0x6 * const_idx)); OUT_RING(ring, sampler->tex0 | view->tex0); OUT_RELOC(ring, fd_resource(view->base.texture)->bo, 0, view->fmt, 0); OUT_RING(ring, view->tex2); OUT_RING(ring, sampler->tex3 | view->tex3); OUT_RING(ring, sampler->tex4); OUT_RING(ring, sampler->tex5); return (1 << const_idx); }
static struct pipe_sampler_view * fd_sampler_view_create(struct pipe_context *pctx, struct pipe_resource *prsc, const struct pipe_sampler_view *cso) { struct fd_pipe_sampler_view *so = CALLOC_STRUCT(fd_pipe_sampler_view); struct fd_resource *rsc = fd_resource(prsc); if (!so) return NULL; so->base = *cso; pipe_reference(NULL, &prsc->reference); so->base.texture = prsc; so->base.reference.count = 1; so->base.context = pctx; so->tex_resource = rsc; so->fmt = fd_pipe2surface(cso->format); so->tex0 = SQ_TEX0_PITCH(rsc->pitch); so->tex2 = SQ_TEX2_HEIGHT(prsc->height0) | SQ_TEX2_WIDTH(prsc->width0); so->tex3 = fd_tex_swiz(cso->format, cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, cso->swizzle_a); return &so->base; }
static void emit_constants(struct fd_ringbuffer *ring, uint32_t base, struct fd_constbuf_stateobj *constbuf, struct fd2_shader_stateobj *shader) { uint32_t enabled_mask = constbuf->enabled_mask; uint32_t start_base = base; unsigned i; /* emit user constants: */ while (enabled_mask) { unsigned index = ffs(enabled_mask) - 1; struct pipe_constant_buffer *cb = &constbuf->cb[index]; unsigned size = align(cb->buffer_size, 4) / 4; /* size in dwords */ // I expect that size should be a multiple of vec4's: assert(size == align(size, 4)); /* hmm, sometimes we still seem to end up with consts bound, * even if shader isn't using them, which ends up overwriting * const reg's used for immediates.. this is a hack to work * around that: */ if (shader && ((base - start_base) >= (shader->first_immediate * 4))) break; const uint32_t *dwords; if (cb->user_buffer) { dwords = cb->user_buffer; } else { struct fd_resource *rsc = fd_resource(cb->buffer); dwords = fd_bo_map(rsc->bo); } dwords = (uint32_t *)(((uint8_t *)dwords) + cb->buffer_offset); OUT_PKT3(ring, CP_SET_CONSTANT, size + 1); OUT_RING(ring, base); for (i = 0; i < size; i++) OUT_RING(ring, *(dwords++)); base += size; enabled_mask &= ~(1 << index); } /* emit shader immediates: */ if (shader) { for (i = 0; i < shader->num_immediates; i++) { OUT_PKT3(ring, CP_SET_CONSTANT, 5); OUT_RING(ring, start_base + (4 * (shader->first_immediate + i))); OUT_RING(ring, shader->immediates[i].val[0]); OUT_RING(ring, shader->immediates[i].val[1]); OUT_RING(ring, shader->immediates[i].val[2]); OUT_RING(ring, shader->immediates[i].val[3]); base += 4; } } }
static void fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) { struct fd_resource *rsc = fd_resource(prsc); if (rsc->dirty) fd_context_render(pctx); }
static void fd_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) { struct fd_resource *rsc = fd_resource(prsc); fd_bo_del(rsc->bo); FREE(rsc); }
static void fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) { struct fd_resource *rsc = fd_resource(prsc); if (pending(rsc, FD_PENDING_WRITE | FD_PENDING_READ)) fd_context_render(pctx); }
/* used by clover to bind global objects, returning the bo address * via handles[n] */ static void fd_set_global_binding(struct pipe_context *pctx, unsigned first, unsigned count, struct pipe_resource **prscs, uint32_t **handles) { struct fd_context *ctx = fd_context(pctx); struct fd_global_bindings_stateobj *so = &ctx->global_bindings; unsigned mask = 0; if (prscs) { for (unsigned i = 0; i < count; i++) { unsigned n = i + first; mask |= BIT(n); pipe_resource_reference(&so->buf[n], prscs[i]); if (so->buf[n]) { struct fd_resource *rsc = fd_resource(so->buf[n]); uint64_t iova = fd_bo_get_iova(rsc->bo); // TODO need to scream if iova > 32b or fix gallium API.. *handles[i] += iova; } if (prscs[i]) so->enabled_mask |= BIT(n); else so->enabled_mask &= ~BIT(n); } } else { mask = (BIT(count) - 1) << first; for (unsigned i = 0; i < count; i++) { unsigned n = i + first; if (so->buf[n]) { struct fd_resource *rsc = fd_resource(so->buf[n]); fd_bo_put_iova(rsc->bo); } pipe_resource_reference(&so->buf[n], NULL); } so->enabled_mask &= ~mask; } }
static boolean fd_resource_get_handle(struct pipe_screen *pscreen, struct pipe_resource *prsc, struct winsys_handle *handle) { struct fd_resource *rsc = fd_resource(prsc); return fd_screen_bo_get_handle(pscreen, rsc->bo, rsc->pitch, handle); }
static void emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs, struct pipe_surface **bufs, uint32_t *bases, uint32_t bin_w) { enum a3xx_tile_mode tile_mode; unsigned i; if (bin_w) { tile_mode = TILE_32X32; } else { tile_mode = LINEAR; } for (i = 0; i < 4; i++) { enum a3xx_color_fmt format = 0; enum a3xx_color_swap swap = WZYX; struct fd_resource *rsc = NULL; struct fd_resource_slice *slice = NULL; uint32_t stride = 0; uint32_t base = 0; if ((i < nr_bufs) && bufs[i]) { struct pipe_surface *psurf = bufs[i]; rsc = fd_resource(psurf->texture); slice = &rsc->slices[psurf->u.tex.level]; format = fd3_pipe2color(psurf->format); swap = fd3_pipe2swap(psurf->format); if (bin_w) { stride = bin_w * rsc->cpp; if (bases) { base = bases[i]; } } else { stride = slice->pitch * rsc->cpp; } } OUT_PKT0(ring, REG_A3XX_RB_MRT_BUF_INFO(i), 2); OUT_RING(ring, A3XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format) | A3XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) | A3XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(stride) | A3XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap)); if (bin_w || (i >= nr_bufs)) { OUT_RING(ring, A3XX_RB_MRT_BUF_BASE_COLOR_BUF_BASE(base)); } else { OUT_RELOCW(ring, rsc->bo, slice->offset, 0, -1); } OUT_PKT0(ring, REG_A3XX_SP_FS_IMAGE_OUTPUT_REG(i), 1); OUT_RING(ring, A3XX_SP_FS_IMAGE_OUTPUT_REG_MRTFORMAT(format)); } }