freedreno_resource.c revision 18c317b21ddc2ec4538544f9dd69dc568dcf821f
1/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
3/*
4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Authors:
26 *    Rob Clark <robclark@freedesktop.org>
27 */
28
29#include "util/u_format.h"
30#include "util/u_inlines.h"
31#include "util/u_transfer.h"
32#include "util/u_string.h"
33#include "util/u_surface.h"
34
35#include "freedreno_resource.h"
36#include "freedreno_screen.h"
37#include "freedreno_surface.h"
38#include "freedreno_context.h"
39#include "freedreno_util.h"
40
41static void fd_resource_transfer_flush_region(struct pipe_context *pctx,
42		struct pipe_transfer *ptrans,
43		const struct pipe_box *box)
44{
45	struct fd_context *ctx = fd_context(pctx);
46	struct fd_resource *rsc = fd_resource(ptrans->resource);
47
48	if (rsc->dirty)
49		fd_context_render(pctx);
50
51	if (rsc->timestamp) {
52		fd_pipe_wait(ctx->screen->pipe, rsc->timestamp);
53		rsc->timestamp = 0;
54	}
55}
56
57static void
58fd_resource_transfer_unmap(struct pipe_context *pctx,
59		struct pipe_transfer *ptrans)
60{
61	struct fd_context *ctx = fd_context(pctx);
62	pipe_resource_reference(&ptrans->resource, NULL);
63	util_slab_free(&ctx->transfer_pool, ptrans);
64}
65
66static void *
67fd_resource_transfer_map(struct pipe_context *pctx,
68		struct pipe_resource *prsc,
69		unsigned level, unsigned usage,
70		const struct pipe_box *box,
71		struct pipe_transfer **pptrans)
72{
73	struct fd_context *ctx = fd_context(pctx);
74	struct fd_resource *rsc = fd_resource(prsc);
75	struct pipe_transfer *ptrans = util_slab_alloc(&ctx->transfer_pool);
76	enum pipe_format format = prsc->format;
77	char *buf;
78
79	if (!ptrans)
80		return NULL;
81
82	/* util_slap_alloc() doesn't zero: */
83	memset(ptrans, 0, sizeof(*ptrans));
84
85	pipe_resource_reference(&ptrans->resource, prsc);
86	ptrans->level = level;
87	ptrans->usage = usage;
88	ptrans->box = *box;
89	ptrans->stride = rsc->pitch * rsc->cpp;
90	ptrans->layer_stride = ptrans->stride;
91
92	/* some state trackers (at least XA) don't do this.. */
93	fd_resource_transfer_flush_region(pctx, ptrans, box);
94
95	buf = fd_bo_map(rsc->bo);
96	if (!buf) {
97		fd_resource_transfer_unmap(pctx, ptrans);
98		return NULL;
99	}
100
101	*pptrans = ptrans;
102
103	return buf +
104		box->y / util_format_get_blockheight(format) * ptrans->stride +
105		box->x / util_format_get_blockwidth(format) * rsc->cpp;
106}
107
108static void
109fd_resource_destroy(struct pipe_screen *pscreen,
110		struct pipe_resource *prsc)
111{
112	struct fd_resource *rsc = fd_resource(prsc);
113	fd_bo_del(rsc->bo);
114	FREE(rsc);
115}
116
117static boolean
118fd_resource_get_handle(struct pipe_screen *pscreen,
119		struct pipe_resource *prsc,
120		struct winsys_handle *handle)
121{
122	struct fd_resource *rsc = fd_resource(prsc);
123
124	return fd_screen_bo_get_handle(pscreen, rsc->bo,
125			rsc->pitch * rsc->cpp, handle);
126}
127
128
129static const struct u_resource_vtbl fd_resource_vtbl = {
130		.resource_get_handle      = fd_resource_get_handle,
131		.resource_destroy         = fd_resource_destroy,
132		.transfer_map             = fd_resource_transfer_map,
133		.transfer_flush_region    = fd_resource_transfer_flush_region,
134		.transfer_unmap           = fd_resource_transfer_unmap,
135		.transfer_inline_write    = u_default_transfer_inline_write,
136};
137
138/**
139 * Create a new texture object, using the given template info.
140 */
141static struct pipe_resource *
142fd_resource_create(struct pipe_screen *pscreen,
143		const struct pipe_resource *tmpl)
144{
145	struct fd_screen *screen = fd_screen(pscreen);
146	struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
147	struct pipe_resource *prsc = &rsc->base.b;
148	uint32_t flags, size;
149
150	DBG("target=%d, format=%s, %ux%u@%u, array_size=%u, last_level=%u, "
151			"nr_samples=%u, usage=%u, bind=%x, flags=%x",
152			tmpl->target, util_format_name(tmpl->format),
153			tmpl->width0, tmpl->height0, tmpl->depth0,
154			tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
155			tmpl->usage, tmpl->bind, tmpl->flags);
156
157	if (!rsc)
158		return NULL;
159
160	*prsc = *tmpl;
161
162	pipe_reference_init(&prsc->reference, 1);
163	prsc->screen = pscreen;
164
165	rsc->base.vtbl = &fd_resource_vtbl;
166	rsc->pitch = align(tmpl->width0, 32);
167	rsc->cpp = util_format_get_blocksize(tmpl->format);
168
169	assert(rsc->cpp);
170
171	size = rsc->pitch * tmpl->height0 * rsc->cpp;
172	flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE |
173			DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */
174
175	rsc->bo = fd_bo_new(screen->dev, size, flags);
176
177	return prsc;
178}
179
180/**
181 * Create a texture from a winsys_handle. The handle is often created in
182 * another process by first creating a pipe texture and then calling
183 * resource_get_handle.
184 */
185static struct pipe_resource *
186fd_resource_from_handle(struct pipe_screen *pscreen,
187		const struct pipe_resource *tmpl,
188		struct winsys_handle *handle)
189{
190	struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
191	struct pipe_resource *prsc = &rsc->base.b;
192
193	DBG("target=%d, format=%s, %ux%u@%u, array_size=%u, last_level=%u, "
194			"nr_samples=%u, usage=%u, bind=%x, flags=%x",
195			tmpl->target, util_format_name(tmpl->format),
196			tmpl->width0, tmpl->height0, tmpl->depth0,
197			tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
198			tmpl->usage, tmpl->bind, tmpl->flags);
199
200	if (!rsc)
201		return NULL;
202
203	*prsc = *tmpl;
204
205	pipe_reference_init(&prsc->reference, 1);
206	prsc->screen = pscreen;
207
208	rsc->bo = fd_screen_bo_from_handle(pscreen, handle, &rsc->pitch);
209
210	rsc->base.vtbl = &fd_resource_vtbl;
211	rsc->cpp = util_format_get_blocksize(tmpl->format);
212	rsc->pitch /= rsc->cpp;
213
214	assert(rsc->cpp);
215
216	return prsc;
217}
218
219static bool render_blit(struct pipe_context *pctx, struct pipe_blit_info *info);
220
221/**
222 * Copy a block of pixels from one resource to another.
223 * The resource must be of the same format.
224 * Resources with nr_samples > 1 are not allowed.
225 */
226static void
227fd_resource_copy_region(struct pipe_context *pctx,
228		struct pipe_resource *dst,
229		unsigned dst_level,
230		unsigned dstx, unsigned dsty, unsigned dstz,
231		struct pipe_resource *src,
232		unsigned src_level,
233		const struct pipe_box *src_box)
234{
235	/* TODO if we have 2d core, or other DMA engine that could be used
236	 * for simple copies and reasonably easily synchronized with the 3d
237	 * core, this is where we'd plug it in..
238	 */
239	struct pipe_blit_info info = {
240		.dst = {
241			.resource = dst,
242			.box = {
243				.x      = dstx,
244				.y      = dsty,
245				.z      = dstz,
246				.width  = src_box->width,
247				.height = src_box->height,
248				.depth  = src_box->depth,
249			},
250			.format = util_format_linear(dst->format),
251		},
252		.src = {
253			.resource = src,
254			.box      = *src_box,
255			.format   = util_format_linear(src->format),
256		},
257		.mask = PIPE_MASK_RGBA,
258		.filter = PIPE_TEX_FILTER_NEAREST,
259	};
260	render_blit(pctx, &info);
261}
262
263/* Optimal hardware path for blitting pixels.
264 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
265 */
266static void
267fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
268{
269	struct pipe_blit_info info = *blit_info;
270
271	if (info.src.resource->nr_samples > 1 &&
272			info.dst.resource->nr_samples <= 1 &&
273			!util_format_is_depth_or_stencil(info.src.resource->format) &&
274			!util_format_is_pure_integer(info.src.resource->format)) {
275		DBG("color resolve unimplemented");
276		return;
277	}
278
279	if (util_try_blit_via_copy_region(pctx, &info)) {
280		return; /* done */
281	}
282
283	if (info.mask & PIPE_MASK_S) {
284		DBG("cannot blit stencil, skipping");
285		info.mask &= ~PIPE_MASK_S;
286	}
287
288	render_blit(pctx, &info);
289}
290
291static bool
292render_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
293{
294	struct fd_context *ctx = fd_context(pctx);
295
296	if (!util_blitter_is_blit_supported(ctx->blitter, info)) {
297		DBG("blit unsupported %s -> %s",
298				util_format_short_name(info->src.resource->format),
299				util_format_short_name(info->dst.resource->format));
300		return false;
301	}
302
303	util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertexbuf.vb);
304	util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx);
305	util_blitter_save_vertex_shader(ctx->blitter, ctx->prog.vp);
306	util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer);
307	util_blitter_save_viewport(ctx->blitter, &ctx->viewport);
308	util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
309	util_blitter_save_fragment_shader(ctx->blitter, ctx->prog.fp);
310	util_blitter_save_blend(ctx->blitter, ctx->blend);
311	util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa);
312	util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
313	util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask);
314	util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer);
315	util_blitter_save_fragment_sampler_states(ctx->blitter,
316			ctx->fragtex.num_samplers,
317			(void **)ctx->fragtex.samplers);
318	util_blitter_save_fragment_sampler_views(ctx->blitter,
319			ctx->fragtex.num_textures, ctx->fragtex.textures);
320
321	util_blitter_blit(ctx->blitter, info);
322
323	return true;
324}
325
326void
327fd_resource_screen_init(struct pipe_screen *pscreen)
328{
329	pscreen->resource_create = fd_resource_create;
330	pscreen->resource_from_handle = fd_resource_from_handle;
331	pscreen->resource_get_handle = u_resource_get_handle_vtbl;
332	pscreen->resource_destroy = u_resource_destroy_vtbl;
333}
334
335void
336fd_resource_context_init(struct pipe_context *pctx)
337{
338	pctx->transfer_map = u_transfer_map_vtbl;
339	pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
340	pctx->transfer_unmap = u_transfer_unmap_vtbl;
341	pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
342	pctx->create_surface = fd_create_surface;
343	pctx->surface_destroy = fd_surface_destroy;
344	pctx->resource_copy_region = fd_resource_copy_region;
345	pctx->blit = fd_blit;
346}
347