Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
/* 2d array and 3d textures seem to want their layers aligned to
 * page boundaries
 */
static uint32_t
setup_slices_array(struct fd_resource *rsc)
{
	struct pipe_resource *prsc = &rsc->base.b;
	uint32_t level, size = 0;
	uint32_t width = prsc->width0;
	uint32_t height = prsc->height0;
	uint32_t depth = prsc->depth0;

	for (level = 0; level <= prsc->last_level; level++) {
		struct fd_resource_slice *slice = fd_resource_slice(rsc, level);

		slice->pitch = align(width, 32);
		slice->offset = size;
		slice->size0 = align(slice->pitch * height * rsc->cpp, 4096);

		size += slice->size0 * depth * prsc->array_size;

		width = u_minify(width, 1);
		height = u_minify(height, 1);
		depth = u_minify(depth, 1);
	}

	return size;
}
Example #4
0
static void
emit_gmem2mem_surf(struct fd_batch *batch, uint32_t base,
		struct pipe_surface *psurf)
{
	struct fd_ringbuffer *ring = batch->gmem;
	struct fd_resource *rsc = fd_resource(psurf->texture);
	uint32_t swap = fmt2swap(psurf->format);
	struct fd_resource_slice *slice =
		fd_resource_slice(rsc, psurf->u.tex.level);
	uint32_t offset =
		fd_resource_offset(rsc, psurf->u.tex.level, psurf->u.tex.first_layer);

	assert((slice->pitch & 31) == 0);
	assert((offset & 0xfff) == 0);

	if (!rsc->valid)
		return;

	OUT_PKT3(ring, CP_SET_CONSTANT, 2);
	OUT_RING(ring, CP_REG(REG_A2XX_RB_COLOR_INFO));
	OUT_RING(ring, A2XX_RB_COLOR_INFO_SWAP(swap) |
			A2XX_RB_COLOR_INFO_BASE(base) |
			A2XX_RB_COLOR_INFO_FORMAT(fd2_pipe2color(psurf->format)));

	OUT_PKT3(ring, CP_SET_CONSTANT, 5);
	OUT_RING(ring, CP_REG(REG_A2XX_RB_COPY_CONTROL));
	OUT_RING(ring, 0x00000000);             /* RB_COPY_CONTROL */
	OUT_RELOCW(ring, rsc->bo, offset, 0, 0);     /* RB_COPY_DEST_BASE */
	OUT_RING(ring, slice->pitch >> 5); /* RB_COPY_DEST_PITCH */
	OUT_RING(ring,                          /* RB_COPY_DEST_INFO */
			A2XX_RB_COPY_DEST_INFO_FORMAT(fd2_pipe2color(psurf->format)) |
			A2XX_RB_COPY_DEST_INFO_LINEAR |
			A2XX_RB_COPY_DEST_INFO_SWAP(swap) |
			A2XX_RB_COPY_DEST_INFO_WRITE_RED |
			A2XX_RB_COPY_DEST_INFO_WRITE_GREEN |
			A2XX_RB_COPY_DEST_INFO_WRITE_BLUE |
			A2XX_RB_COPY_DEST_INFO_WRITE_ALPHA);

	if (!is_a20x(batch->ctx->screen)) {
		OUT_WFI (ring);

		OUT_PKT3(ring, CP_SET_CONSTANT, 3);
		OUT_RING(ring, CP_REG(REG_A2XX_VGT_MAX_VTX_INDX));
		OUT_RING(ring, 3);                 /* VGT_MAX_VTX_INDX */
		OUT_RING(ring, 0);                 /* VGT_MIN_VTX_INDX */
	}

	fd_draw(batch, ring, DI_PT_RECTLIST, IGNORE_VISIBILITY,
			DI_SRC_SEL_AUTO_INDEX, 3, 0, INDEX_SIZE_IGN, 0, 0, NULL);
}
Example #5
0
static uint32_t
setup_slices(struct fd_resource *rsc, uint32_t alignment, enum pipe_format format)
{
	struct pipe_resource *prsc = &rsc->base.b;
	enum util_format_layout layout = util_format_description(format)->layout;
	uint32_t level, size = 0;
	uint32_t width = prsc->width0;
	uint32_t height = prsc->height0;
	uint32_t depth = prsc->depth0;
	/* in layer_first layout, the level (slice) contains just one
	 * layer (since in fact the layer contains the slices)
	 */
	uint32_t layers_in_level = rsc->layer_first ? 1 : prsc->array_size;

	for (level = 0; level <= prsc->last_level; level++) {
		struct fd_resource_slice *slice = fd_resource_slice(rsc, level);
		uint32_t blocks;

		if (layout == UTIL_FORMAT_LAYOUT_ASTC)
			slice->pitch = width =
				util_align_npot(width, 32 * util_format_get_blockwidth(format));
		else
			slice->pitch = width = align(width, 32);
		slice->offset = size;
		blocks = util_format_get_nblocks(format, width, height);
		/* 1d array and 2d array textures must all have the same layer size
		 * for each miplevel on a3xx. 3d textures can have different layer
		 * sizes for high levels, but the hw auto-sizer is buggy (or at least
		 * different than what this code does), so as soon as the layer size
		 * range gets into range, we stop reducing it.
		 */
		if (prsc->target == PIPE_TEXTURE_3D && (
					level == 1 ||
					(level > 1 && rsc->slices[level - 1].size0 > 0xf000)))
			slice->size0 = align(blocks * rsc->cpp, alignment);
		else if (level == 0 || rsc->layer_first || alignment == 1)
			slice->size0 = align(blocks * rsc->cpp, alignment);
		else
			slice->size0 = rsc->slices[level - 1].size0;

		size += slice->size0 * depth * layers_in_level;

		width = u_minify(width, 1);
		height = u_minify(height, 1);
		depth = u_minify(depth, 1);
	}

	return size;
}
Example #6
0
/* emit texture state for mem->gmem restore operation.. eventually it would
 * be good to get rid of this and use normal CSO/etc state for more of these
 * special cases..
 */
void
fd4_emit_gmem_restore_tex(struct fd_ringbuffer *ring, struct pipe_surface *psurf)
{
	struct fd_resource *rsc = fd_resource(psurf->texture);
	unsigned lvl = psurf->u.tex.level;
	struct fd_resource_slice *slice = fd_resource_slice(rsc, lvl);
	uint32_t offset = fd_resource_offset(rsc, lvl, psurf->u.tex.first_layer);
	enum pipe_format format = fd4_gmem_restore_format(psurf->format);

	debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer);

	/* output sampler state: */
	OUT_PKT3(ring, CP_LOAD_STATE, 4);
	OUT_RING(ring, CP_LOAD_STATE_0_DST_OFF(0) |
			CP_LOAD_STATE_0_STATE_SRC(SS_DIRECT) |
			CP_LOAD_STATE_0_STATE_BLOCK(SB_FRAG_TEX) |
			CP_LOAD_STATE_0_NUM_UNIT(1));
	OUT_RING(ring, CP_LOAD_STATE_1_STATE_TYPE(ST_SHADER) |
			CP_LOAD_STATE_1_EXT_SRC_ADDR(0));
	OUT_RING(ring, A4XX_TEX_SAMP_0_XY_MAG(A4XX_TEX_NEAREST) |
			A4XX_TEX_SAMP_0_XY_MIN(A4XX_TEX_NEAREST) |
			A4XX_TEX_SAMP_0_WRAP_S(A4XX_TEX_CLAMP_TO_EDGE) |
			A4XX_TEX_SAMP_0_WRAP_T(A4XX_TEX_CLAMP_TO_EDGE) |
			A4XX_TEX_SAMP_0_WRAP_R(A4XX_TEX_REPEAT));
	OUT_RING(ring, 0x00000000);

	/* emit texture state: */
	OUT_PKT3(ring, CP_LOAD_STATE, 10);
	OUT_RING(ring, CP_LOAD_STATE_0_DST_OFF(0) |
			CP_LOAD_STATE_0_STATE_SRC(SS_DIRECT) |
			CP_LOAD_STATE_0_STATE_BLOCK(SB_FRAG_TEX) |
			CP_LOAD_STATE_0_NUM_UNIT(1));
	OUT_RING(ring, CP_LOAD_STATE_1_STATE_TYPE(ST_CONSTANTS) |
			CP_LOAD_STATE_1_EXT_SRC_ADDR(0));
	OUT_RING(ring, A4XX_TEX_CONST_0_FMT(fd4_pipe2tex(format)) |
			A4XX_TEX_CONST_0_TYPE(A4XX_TEX_2D) |
			fd4_tex_swiz(format,  PIPE_SWIZZLE_RED, PIPE_SWIZZLE_GREEN,
					PIPE_SWIZZLE_BLUE, PIPE_SWIZZLE_ALPHA));
	OUT_RING(ring, A4XX_TEX_CONST_1_WIDTH(psurf->width) |
			A4XX_TEX_CONST_1_HEIGHT(psurf->height));
	OUT_RING(ring, A4XX_TEX_CONST_2_PITCH(slice->pitch * rsc->cpp));
	OUT_RING(ring, 0x00000000);
	OUT_RELOC(ring, rsc->bo, offset, 0, 0);
	OUT_RING(ring, 0x00000000);
	OUT_RING(ring, 0x00000000);
	OUT_RING(ring, 0x00000000);
}
Example #7
0
static void
fd_resource_flush_rgtc(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);
	enum pipe_format format = trans->base.resource->format;

	uint8_t *data = 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 +
		 trans->base.box.x + box->x) * rsc->cpp;

	uint8_t *source = trans->staging +
		util_format_get_nblocksy(format, box->y) * trans->base.stride +
		util_format_get_stride(format, box->x);

	switch (format) {
	case PIPE_FORMAT_RGTC1_UNORM:
	case PIPE_FORMAT_RGTC1_SNORM:
	case PIPE_FORMAT_LATC1_UNORM:
	case PIPE_FORMAT_LATC1_SNORM:
		util_format_rgtc1_unorm_unpack_rgba_8unorm(
				data, slice->pitch * rsc->cpp,
				source, trans->base.stride,
				box->width, box->height);
		break;
	case PIPE_FORMAT_RGTC2_UNORM:
	case PIPE_FORMAT_RGTC2_SNORM:
	case PIPE_FORMAT_LATC2_UNORM:
	case PIPE_FORMAT_LATC2_SNORM:
		util_format_rgtc2_unorm_unpack_rgba_8unorm(
				data, slice->pitch * rsc->cpp,
				source, trans->base.stride,
				box->width, box->height);
		break;
	default:
		assert(!"Unexpected format\n");
		break;
	}
}
Example #8
0
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 fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct fd_transfer *trans;
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	uint32_t offset;
	char *buf;
	int ret = 0;

	DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage,
		box->width, box->height, box->x, box->y);

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	trans = fd_transfer(ptrans);
	memset(trans, 0, sizeof(*trans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = util_format_get_nblocksx(format, slice->pitch) * rsc->cpp;
	ptrans->layer_stride = rsc->layer_first ? rsc->layer_size : slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
		realloc_bo(rsc, fd_bo_size(rsc->bo));
		if (rsc->stencil)
			realloc_bo(rsc->stencil, fd_bo_size(rsc->stencil->bo));
		fd_invalidate_resource(ctx, prsc);
	} else if ((usage & PIPE_TRANSFER_WRITE) &&
			   prsc->target == PIPE_BUFFER &&
			   !util_ranges_intersect(&rsc->valid_buffer_range,
									  box->x, box->x + box->width)) {
		/* We are trying to write to a previously uninitialized range. No need
		 * to wait.
		 */
	} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		/* If the GPU is writing to the resource, or if it is reading from the
		 * resource and we're trying to write to it, flush the renders.
		 */
		if (((ptrans->usage & PIPE_TRANSFER_WRITE) &&
					pending(rsc, FD_PENDING_READ | FD_PENDING_WRITE)) ||
				pending(rsc, FD_PENDING_WRITE))
			fd_context_render(pctx);

		/* The GPU keeps track of how the various bo's are being used, and
		 * will wait if necessary for the proper operation to have
		 * completed.
		 */
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf)
		goto fail;

	offset = slice->offset +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp +
		fd_resource_layer_offset(rsc, slice, box->z);

	if (prsc->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT ||
		prsc->format == PIPE_FORMAT_X32_S8X24_UINT) {
		assert(trans->base.box.depth == 1);

		trans->base.stride = trans->base.box.width * rsc->cpp * 2;
		trans->staging = malloc(trans->base.stride * trans->base.box.height);
		if (!trans->staging)
			goto fail;

		/* if we're not discarding the whole range (or resource), we must copy
		 * the real data in.
		 */
		if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
					   PIPE_TRANSFER_DISCARD_RANGE))) {
			struct fd_resource_slice *sslice =
				fd_resource_slice(rsc->stencil, level);
			void *sbuf = fd_bo_map(rsc->stencil->bo);
			if (!sbuf)
				goto fail;

			float *depth = (float *)(buf + slice->offset +
				fd_resource_layer_offset(rsc, slice, box->z) +
				box->y * slice->pitch * 4 + box->x * 4);
			uint8_t *stencil = sbuf + sslice->offset +
				fd_resource_layer_offset(rsc->stencil, sslice, box->z) +
				box->y * sslice->pitch + box->x;

			if (format != PIPE_FORMAT_X32_S8X24_UINT)
				util_format_z32_float_s8x24_uint_pack_z_float(
						trans->staging, trans->base.stride,
						depth, slice->pitch * 4,
						box->width, box->height);

			util_format_z32_float_s8x24_uint_pack_s_8uint(
					trans->staging, trans->base.stride,
					stencil, sslice->pitch,
					box->width, box->height);
		}

		buf = trans->staging;
		offset = 0;
	} else if (rsc->internal_format != format &&
			   util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC) {
		assert(trans->base.box.depth == 1);

		trans->base.stride = util_format_get_stride(
				format, trans->base.box.width);
		trans->staging = malloc(
				util_format_get_2d_size(format, trans->base.stride,
										trans->base.box.height));
		if (!trans->staging)
			goto fail;

		/* if we're not discarding the whole range (or resource), we must copy
		 * the real data in.
		 */
		if (!(usage & (PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE |
					   PIPE_TRANSFER_DISCARD_RANGE))) {
			uint8_t *rgba8 = (uint8_t *)buf + slice->offset +
				fd_resource_layer_offset(rsc, slice, box->z) +
				box->y * slice->pitch * rsc->cpp + box->x * rsc->cpp;

			switch (format) {
			case PIPE_FORMAT_RGTC1_UNORM:
			case PIPE_FORMAT_RGTC1_SNORM:
			case PIPE_FORMAT_LATC1_UNORM:
			case PIPE_FORMAT_LATC1_SNORM:
				util_format_rgtc1_unorm_pack_rgba_8unorm(
					trans->staging, trans->base.stride,
					rgba8, slice->pitch * rsc->cpp,
					box->width, box->height);
				break;
			case PIPE_FORMAT_RGTC2_UNORM:
			case PIPE_FORMAT_RGTC2_SNORM:
			case PIPE_FORMAT_LATC2_UNORM:
			case PIPE_FORMAT_LATC2_SNORM:
				util_format_rgtc2_unorm_pack_rgba_8unorm(
					trans->staging, trans->base.stride,
					rgba8, slice->pitch * rsc->cpp,
					box->width, box->height);
				break;
			default:
				assert(!"Unexpected format");
				break;
			}
		}

		buf = trans->staging;
		offset = 0;
	}

	*pptrans = ptrans;

	return buf + offset;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}
Example #9
0
static void
emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs,
		struct pipe_surface **bufs, struct fd_gmem_stateobj *gmem)
{
	enum a5xx_tile_mode tile_mode;
	unsigned i;

	if (gmem) {
		tile_mode = TILE5_2;
	} else {
		tile_mode = TILE5_LINEAR;
	}

	for (i = 0; i < A5XX_MAX_RENDER_TARGETS; i++) {
		enum a5xx_color_fmt format = 0;
		enum a3xx_color_swap swap = WZYX;
		bool srgb = false;
		struct fd_resource *rsc = NULL;
		struct fd_resource_slice *slice = NULL;
		uint32_t stride = 0;
		uint32_t size = 0;
		uint32_t base = 0;
		uint32_t offset = 0;

		if ((i < nr_bufs) && bufs[i]) {
			struct pipe_surface *psurf = bufs[i];
			enum pipe_format pformat = psurf->format;

			rsc = fd_resource(psurf->texture);

			slice = fd_resource_slice(rsc, psurf->u.tex.level);
			format = fd5_pipe2color(pformat);
			swap = fd5_pipe2swap(pformat);
			srgb = util_format_is_srgb(pformat);

			debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer);

			offset = fd_resource_offset(rsc, psurf->u.tex.level,
					psurf->u.tex.first_layer);

			if (gmem) {
				stride = gmem->bin_w * rsc->cpp;
				size = stride * gmem->bin_h;
				base = gmem->cbuf_base[i];
			} else {
				stride = slice->pitch * rsc->cpp;
				size = slice->size0;
			}
		}

		OUT_PKT4(ring, REG_A5XX_RB_MRT_BUF_INFO(i), 5);
		OUT_RING(ring, A5XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format) |
				A5XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) |
				A5XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap) |
				0x800 | /* XXX 0x1000 for RECTLIST clear, 0x0 for BLIT.. */
				COND(srgb, A5XX_RB_MRT_BUF_INFO_COLOR_SRGB));
		OUT_RING(ring, A5XX_RB_MRT_PITCH(stride));
		OUT_RING(ring, A5XX_RB_MRT_ARRAY_PITCH(size));
		if (gmem || (i >= nr_bufs) || !bufs[i]) {
			OUT_RING(ring, base);           /* RB_MRT[i].BASE_LO */
			OUT_RING(ring, 0x00000000);     /* RB_MRT[i].BASE_HI */
		} else {
			debug_assert((offset + size) <= fd_bo_size(rsc->bo));
			OUT_RELOCW(ring, rsc->bo, offset, 0, 0);  /* BASE_LO/HI */
		}

		OUT_PKT4(ring, REG_A5XX_SP_FS_MRT_REG(i), 1);
		OUT_RING(ring, A5XX_SP_FS_MRT_REG_COLOR_FORMAT(format));

		/* when we support UBWC, these would be the system memory
		 * addr/pitch/etc:
		 */
		OUT_PKT4(ring, REG_A5XX_RB_MRT_FLAG_BUFFER(i), 4);
		OUT_RING(ring, 0x00000000);    /* RB_MRT_FLAG_BUFFER[i].ADDR_LO */
		OUT_RING(ring, 0x00000000);    /* RB_MRT_FLAG_BUFFER[i].ADDR_HI */
		OUT_RING(ring, A5XX_RB_MRT_FLAG_BUFFER_PITCH(0));
		OUT_RING(ring, A5XX_RB_MRT_FLAG_BUFFER_ARRAY_PITCH(0));
	}
}
Example #10
0
static void
emit_zs(struct fd_ringbuffer *ring, struct pipe_surface *zsbuf,
		struct fd_gmem_stateobj *gmem)
{
	if (zsbuf) {
		struct fd_resource *rsc = fd_resource(zsbuf->texture);
		enum a5xx_depth_format fmt = fd5_pipe2depth(zsbuf->format);
		uint32_t cpp = rsc->cpp;
		uint32_t stride = 0;
		uint32_t size = 0;

		if (gmem) {
			stride = cpp * gmem->bin_w;
			size = stride * gmem->bin_h;
		} else {
			struct fd_resource_slice *slice = fd_resource_slice(rsc, 0);
			stride = slice->pitch * rsc->cpp;
			size = slice->size0;
		}

		OUT_PKT4(ring, REG_A5XX_RB_DEPTH_BUFFER_INFO, 5);
		OUT_RING(ring, A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT(fmt));
		if (gmem) {
			OUT_RING(ring, gmem->zsbuf_base[0]); /* RB_DEPTH_BUFFER_BASE_LO */
			OUT_RING(ring, 0x00000000);          /* RB_DEPTH_BUFFER_BASE_HI */
		} else {
			OUT_RELOCW(ring, rsc->bo, 0, 0, 0);  /* RB_DEPTH_BUFFER_BASE_LO/HI */
		}
		OUT_RING(ring, A5XX_RB_DEPTH_BUFFER_PITCH(stride));
		OUT_RING(ring, A5XX_RB_DEPTH_BUFFER_ARRAY_PITCH(size));

		OUT_PKT4(ring, REG_A5XX_GRAS_SU_DEPTH_BUFFER_INFO, 1);
		OUT_RING(ring, A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT(fmt));

		OUT_PKT4(ring, REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_LO, 3);
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_BASE_LO */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_BASE_HI */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_PITCH */

		if (rsc->stencil) {
			if (gmem) {
				stride = 1 * gmem->bin_w;
				size = stride * gmem->bin_h;
			} else {
				struct fd_resource_slice *slice = fd_resource_slice(rsc->stencil, 0);
				stride = slice->pitch * rsc->cpp;
				size = slice->size0;
			}

			OUT_PKT4(ring, REG_A5XX_RB_STENCIL_INFO, 5);
			OUT_RING(ring, A5XX_RB_STENCIL_INFO_SEPARATE_STENCIL);
			if (gmem) {
				OUT_RING(ring, gmem->zsbuf_base[1]);  /* RB_STENCIL_BASE_LO */
				OUT_RING(ring, 0x00000000);           /* RB_STENCIL_BASE_HI */
			} else {
				OUT_RELOCW(ring, rsc->stencil->bo, 0, 0, 0);  /* RB_STENCIL_BASE_LO/HI */
			}
			OUT_RING(ring, A5XX_RB_STENCIL_PITCH(stride));
			OUT_RING(ring, A5XX_RB_STENCIL_ARRAY_PITCH(size));
		} else {
			OUT_PKT4(ring, REG_A5XX_RB_STENCIL_INFO, 1);
			OUT_RING(ring, 0x00000000);     /* RB_STENCIL_INFO */
		}
	} else {
		OUT_PKT4(ring, REG_A5XX_RB_DEPTH_BUFFER_INFO, 5);
		OUT_RING(ring, A5XX_RB_DEPTH_BUFFER_INFO_DEPTH_FORMAT(DEPTH5_NONE));
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_BUFFER_BASE_LO */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_BUFFER_BASE_HI */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_BUFFER_PITCH */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_BUFFER_ARRAY_PITCH */

		OUT_PKT4(ring, REG_A5XX_GRAS_SU_DEPTH_BUFFER_INFO, 1);
		OUT_RING(ring, A5XX_GRAS_SU_DEPTH_BUFFER_INFO_DEPTH_FORMAT(DEPTH5_NONE));

		OUT_PKT4(ring, REG_A5XX_RB_DEPTH_FLAG_BUFFER_BASE_LO, 3);
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_BASE_LO */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_BASE_HI */
		OUT_RING(ring, 0x00000000);    /* RB_DEPTH_FLAG_BUFFER_PITCH */

		OUT_PKT4(ring, REG_A5XX_RB_STENCIL_INFO, 1);
		OUT_RING(ring, 0x00000000);     /* RB_STENCIL_INFO */
	}
}
Example #11
0
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 fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	char *buf;
	int ret = 0;

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	memset(ptrans, 0, sizeof(*ptrans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = slice->pitch * rsc->cpp;
	ptrans->layer_stride = slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)
		op |= DRM_FREEDRENO_PREP_NOSYNC;

	/* some state trackers (at least XA) don't do this.. */
	if (!(usage & (PIPE_TRANSFER_FLUSH_EXPLICIT | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)))
		fd_resource_transfer_flush_region(pctx, ptrans, box);

	if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if ((ret == -EBUSY) && (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))
			realloc_bo(rsc, fd_bo_size(rsc->bo));
		else if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf) {
		fd_resource_transfer_unmap(pctx, ptrans);
		return NULL;
	}

	*pptrans = ptrans;

	return buf + slice->offset +
		box->y / util_format_get_blockheight(format) * ptrans->stride +
		box->x / util_format_get_blockwidth(format) * rsc->cpp +
		box->z * slice->size0;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}
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 fd_resource_slice *slice = fd_resource_slice(rsc, level);
	struct pipe_transfer *ptrans;
	enum pipe_format format = prsc->format;
	uint32_t op = 0;
	uint32_t offset;
	char *buf;
	int ret = 0;

	DBG("prsc=%p, level=%u, usage=%x", prsc, level, usage);

	ptrans = util_slab_alloc(&ctx->transfer_pool);
	if (!ptrans)
		return NULL;

	/* util_slab_alloc() doesn't zero: */
	memset(ptrans, 0, sizeof(*ptrans));

	pipe_resource_reference(&ptrans->resource, prsc);
	ptrans->level = level;
	ptrans->usage = usage;
	ptrans->box = *box;
	ptrans->stride = slice->pitch * rsc->cpp;
	ptrans->layer_stride = slice->size0;

	if (usage & PIPE_TRANSFER_READ)
		op |= DRM_FREEDRENO_PREP_READ;

	if (usage & PIPE_TRANSFER_WRITE)
		op |= DRM_FREEDRENO_PREP_WRITE;

	if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
		realloc_bo(rsc, fd_bo_size(rsc->bo));
		fd_invalidate_resource(ctx, prsc);
	} else if ((usage & PIPE_TRANSFER_WRITE) &&
			   prsc->target == PIPE_BUFFER &&
			   !util_ranges_intersect(&rsc->valid_buffer_range,
									  box->x, box->x + box->width)) {
		/* We are trying to write to a previously uninitialized range. No need
		 * to wait.
		 */
	} else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
		/* If the GPU is writing to the resource, or if it is reading from the
		 * resource and we're trying to write to it, flush the renders.
		 */
		if (rsc->dirty ||
			((ptrans->usage & PIPE_TRANSFER_WRITE) && rsc->reading))
			fd_context_render(pctx);

		/* The GPU keeps track of how the various bo's are being used, and
		 * will wait if necessary for the proper operation to have
		 * completed.
		 */
		ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
		if (ret)
			goto fail;
	}

	buf = fd_bo_map(rsc->bo);
	if (!buf) {
		fd_resource_transfer_unmap(pctx, ptrans);
		return NULL;
	}

	*pptrans = ptrans;

	if (rsc->layer_first) {
		offset = slice->offset +
			box->y / util_format_get_blockheight(format) * ptrans->stride +
			box->x / util_format_get_blockwidth(format) * rsc->cpp +
			box->z * rsc->layer_size;
	} else {
		offset = slice->offset +
			box->y / util_format_get_blockheight(format) * ptrans->stride +
			box->x / util_format_get_blockwidth(format) * rsc->cpp +
			box->z * slice->size0;
	}

	return buf + offset;

fail:
	fd_resource_transfer_unmap(pctx, ptrans);
	return NULL;
}
Example #13
0
static void
emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs,
		struct pipe_surface **bufs, uint32_t *bases,
		uint32_t bin_w, bool decode_srgb)
{
	enum a4xx_tile_mode tile_mode;
	unsigned i;

	if (bin_w) {
		tile_mode = 2;
	} else {
		tile_mode = TILE4_LINEAR;
	}

	for (i = 0; i < A4XX_MAX_RENDER_TARGETS; i++) {
		enum a4xx_color_fmt format = 0;
		enum a3xx_color_swap swap = WZYX;
		bool srgb = false;
		struct fd_resource *rsc = NULL;
		struct fd_resource_slice *slice = NULL;
		uint32_t stride = 0;
		uint32_t base = 0;
		uint32_t offset = 0;

		if ((i < nr_bufs) && bufs[i]) {
			struct pipe_surface *psurf = bufs[i];
			enum pipe_format pformat = psurf->format;

			rsc = fd_resource(psurf->texture);

			/* In case we're drawing to Z32F_S8, the "color" actually goes to
			 * the stencil
			 */
			if (rsc->stencil) {
				rsc = rsc->stencil;
				pformat = rsc->base.b.format;
				bases++;
			}

			slice = fd_resource_slice(rsc, psurf->u.tex.level);
			format = fd4_pipe2color(pformat);
			swap = fd4_pipe2swap(pformat);

			if (decode_srgb)
				srgb = util_format_is_srgb(pformat);
			else
				pformat = util_format_linear(pformat);

			debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer);

			offset = fd_resource_offset(rsc, psurf->u.tex.level,
					psurf->u.tex.first_layer);

			if (bin_w) {
				stride = bin_w * rsc->cpp;

				if (bases) {
					base = bases[i];
				}
			} else {
				stride = slice->pitch * rsc->cpp;
			}
		} else if ((i < nr_bufs) && bases) {
			base = bases[i];
		}

		OUT_PKT0(ring, REG_A4XX_RB_MRT_BUF_INFO(i), 3);
		OUT_RING(ring, A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format) |
				A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) |
				A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(stride) |
				A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap) |
				COND(srgb, A4XX_RB_MRT_BUF_INFO_COLOR_SRGB));
		if (bin_w || (i >= nr_bufs) || !bufs[i]) {
			OUT_RING(ring, base);
			OUT_RING(ring, A4XX_RB_MRT_CONTROL3_STRIDE(stride));
		} else {
			OUT_RELOCW(ring, rsc->bo, offset, 0, 0);
			/* RB_MRT[i].CONTROL3.STRIDE not emitted by c2d..
			 * not sure if we need to skip it for bypass or
			 * not.
			 */
			OUT_RING(ring, A4XX_RB_MRT_CONTROL3_STRIDE(0));
		}
	}
}
Example #14
0
static void
emit_mrt(struct fd_ringbuffer *ring, unsigned nr_bufs,
		struct pipe_surface **bufs, uint32_t *bases, uint32_t bin_w)
{
	enum a4xx_tile_mode tile_mode;
	unsigned i;

	if (bin_w) {
		tile_mode = 2;
	} else {
		tile_mode = TILE4_LINEAR;
	}

	for (i = 0; i < 8; i++) {
		enum a4xx_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;
		uint32_t offset = 0;

		if ((i < nr_bufs) && bufs[i]) {
			struct pipe_surface *psurf = bufs[i];

			rsc = fd_resource(psurf->texture);
			slice = fd_resource_slice(rsc, psurf->u.tex.level);
			format = fd4_pipe2color(psurf->format);
			swap = fd4_pipe2swap(psurf->format);

			debug_assert(psurf->u.tex.first_layer == psurf->u.tex.last_layer);

			offset = fd_resource_offset(rsc, psurf->u.tex.level,
					psurf->u.tex.first_layer);

			if (bin_w) {
				stride = bin_w * rsc->cpp;

				if (bases) {
					base = bases[i];
				}
			} else {
				stride = slice->pitch * rsc->cpp;
			}
		}

		OUT_PKT0(ring, REG_A4XX_RB_MRT_BUF_INFO(i), 3);
		OUT_RING(ring, A4XX_RB_MRT_BUF_INFO_COLOR_FORMAT(format) |
				A4XX_RB_MRT_BUF_INFO_COLOR_TILE_MODE(tile_mode) |
				A4XX_RB_MRT_BUF_INFO_COLOR_BUF_PITCH(stride) |
				A4XX_RB_MRT_BUF_INFO_COLOR_SWAP(swap));
		if (bin_w || (i >= nr_bufs)) {
			OUT_RING(ring, base);
			OUT_RING(ring, A4XX_RB_MRT_CONTROL3_STRIDE(stride));
		} else {
			OUT_RELOCW(ring, rsc->bo, offset, 0, 0);
			/* RB_MRT[i].CONTROL3.STRIDE not emitted by c2d..
			 * not sure if we need to skip it for bypass or
			 * not.
			 */
			OUT_RING(ring, A4XX_RB_MRT_CONTROL3_STRIDE(0));
		}
	}
}