/**
 * Create a new texture object, using the given template info.
 */
static struct pipe_resource *
fd_resource_create(struct pipe_screen *pscreen,
		const struct pipe_resource *tmpl)
{
	struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
	struct pipe_resource *prsc = &rsc->base.b;
	uint32_t size;

	DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
			"nr_samples=%u, usage=%u, bind=%x, flags=%x",
			tmpl->target, util_format_name(tmpl->format),
			tmpl->width0, tmpl->height0, tmpl->depth0,
			tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
			tmpl->usage, tmpl->bind, tmpl->flags);

	if (!rsc)
		return NULL;

	*prsc = *tmpl;

	pipe_reference_init(&prsc->reference, 1);
	list_inithead(&rsc->list);
	prsc->screen = pscreen;

	util_range_init(&rsc->valid_buffer_range);

	rsc->base.vtbl = &fd_resource_vtbl;
	rsc->cpp = util_format_get_blocksize(tmpl->format);

	assert(rsc->cpp);

	if (is_a4xx(fd_screen(pscreen))) {
		switch (tmpl->target) {
		case PIPE_TEXTURE_3D:
			/* TODO 3D_ARRAY? */
			rsc->layer_first = false;
			break;
		default:
			rsc->layer_first = true;
			break;
		}
	}

	size = setup_slices(rsc, slice_alignment(pscreen, tmpl));

	if (rsc->layer_first) {
		rsc->layer_size = align(size, 4096);
		size = rsc->layer_size * prsc->array_size;
	}

	realloc_bo(rsc, size);
	if (!rsc->bo)
		goto fail;

	return prsc;
fail:
	fd_resource_destroy(pscreen, prsc);
	return NULL;
}
/**
 * Create a new texture object, using the given template info.
 */
static struct pipe_resource *
fd_resource_create(struct pipe_screen *pscreen,
		const struct pipe_resource *tmpl)
{
	struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
	struct pipe_resource *prsc = &rsc->base.b;
	enum pipe_format format = tmpl->format;
	uint32_t size, alignment;

	DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
			"nr_samples=%u, usage=%u, bind=%x, flags=%x",
			tmpl->target, util_format_name(format),
			tmpl->width0, tmpl->height0, tmpl->depth0,
			tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
			tmpl->usage, tmpl->bind, tmpl->flags);

	if (!rsc)
		return NULL;

	*prsc = *tmpl;

	pipe_reference_init(&prsc->reference, 1);
	list_inithead(&rsc->list);
	prsc->screen = pscreen;

	util_range_init(&rsc->valid_buffer_range);

	rsc->base.vtbl = &fd_resource_vtbl;

	if (format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)
		format = PIPE_FORMAT_Z32_FLOAT;
	else if (fd_screen(pscreen)->gpu_id < 400 &&
			 util_format_description(format)->layout == UTIL_FORMAT_LAYOUT_RGTC)
		format = PIPE_FORMAT_R8G8B8A8_UNORM;
	rsc->internal_format = format;
	rsc->cpp = util_format_get_blocksize(format);

	assert(rsc->cpp);

	alignment = slice_alignment(pscreen, tmpl);
	if (is_a4xx(fd_screen(pscreen))) {
		switch (tmpl->target) {
		case PIPE_TEXTURE_3D:
			rsc->layer_first = false;
			break;
		default:
			rsc->layer_first = true;
			alignment = 1;
			break;
		}
	}

	size = setup_slices(rsc, alignment, format);

	if (rsc->layer_first) {
		rsc->layer_size = align(size, 4096);
		size = rsc->layer_size * prsc->array_size;
	}

	realloc_bo(rsc, size);
	if (!rsc->bo)
		goto fail;

	/* There is no native Z32F_S8 sampling or rendering format, so this must
	 * be emulated via two separate textures. The depth texture still keeps
	 * its Z32F_S8 format though, and we also keep a reference to a separate
	 * S8 texture.
	 */
	if (tmpl->format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) {
		struct pipe_resource stencil = *tmpl;
		stencil.format = PIPE_FORMAT_S8_UINT;
		rsc->stencil = fd_resource(fd_resource_create(pscreen, &stencil));
		if (!rsc->stencil)
			goto fail;
	}

	return prsc;
fail:
	fd_resource_destroy(pscreen, prsc);
	return NULL;
}