freedreno: updates for msm drm/kms driver
[mesa.git] / src / gallium / drivers / freedreno / freedreno_resource.c
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
41 static 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
57 static void
58 fd_resource_transfer_unmap(struct pipe_context *pctx,
59 struct pipe_transfer *ptrans)
60 {
61 struct fd_context *ctx = fd_context(pctx);
62 struct fd_resource *rsc = fd_resource(ptrans->resource);
63 if (!(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED))
64 fd_bo_cpu_fini(rsc->bo);
65 pipe_resource_reference(&ptrans->resource, NULL);
66 util_slab_free(&ctx->transfer_pool, ptrans);
67 }
68
69 static void *
70 fd_resource_transfer_map(struct pipe_context *pctx,
71 struct pipe_resource *prsc,
72 unsigned level, unsigned usage,
73 const struct pipe_box *box,
74 struct pipe_transfer **pptrans)
75 {
76 struct fd_context *ctx = fd_context(pctx);
77 struct fd_resource *rsc = fd_resource(prsc);
78 struct pipe_transfer *ptrans = util_slab_alloc(&ctx->transfer_pool);
79 enum pipe_format format = prsc->format;
80 uint32_t op = 0;
81 char *buf;
82
83 if (!ptrans)
84 return NULL;
85
86 /* util_slab_alloc() doesn't zero: */
87 memset(ptrans, 0, sizeof(*ptrans));
88
89 pipe_resource_reference(&ptrans->resource, prsc);
90 ptrans->level = level;
91 ptrans->usage = usage;
92 ptrans->box = *box;
93 ptrans->stride = rsc->pitch * rsc->cpp;
94 ptrans->layer_stride = ptrans->stride;
95
96 /* some state trackers (at least XA) don't do this.. */
97 if (!(usage & PIPE_TRANSFER_FLUSH_EXPLICIT))
98 fd_resource_transfer_flush_region(pctx, ptrans, box);
99
100 buf = fd_bo_map(rsc->bo);
101 if (!buf) {
102 fd_resource_transfer_unmap(pctx, ptrans);
103 return NULL;
104 }
105
106 if (usage & PIPE_TRANSFER_READ)
107 op |= DRM_FREEDRENO_PREP_READ;
108
109 if (usage & PIPE_TRANSFER_WRITE)
110 op |= DRM_FREEDRENO_PREP_WRITE;
111
112 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED))
113 fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op);
114
115 *pptrans = ptrans;
116
117 return buf +
118 box->y / util_format_get_blockheight(format) * ptrans->stride +
119 box->x / util_format_get_blockwidth(format) * rsc->cpp;
120 }
121
122 static void
123 fd_resource_destroy(struct pipe_screen *pscreen,
124 struct pipe_resource *prsc)
125 {
126 struct fd_resource *rsc = fd_resource(prsc);
127 fd_bo_del(rsc->bo);
128 FREE(rsc);
129 }
130
131 static boolean
132 fd_resource_get_handle(struct pipe_screen *pscreen,
133 struct pipe_resource *prsc,
134 struct winsys_handle *handle)
135 {
136 struct fd_resource *rsc = fd_resource(prsc);
137
138 return fd_screen_bo_get_handle(pscreen, rsc->bo,
139 rsc->pitch * rsc->cpp, handle);
140 }
141
142
143 static const struct u_resource_vtbl fd_resource_vtbl = {
144 .resource_get_handle = fd_resource_get_handle,
145 .resource_destroy = fd_resource_destroy,
146 .transfer_map = fd_resource_transfer_map,
147 .transfer_flush_region = fd_resource_transfer_flush_region,
148 .transfer_unmap = fd_resource_transfer_unmap,
149 .transfer_inline_write = u_default_transfer_inline_write,
150 };
151
152 /**
153 * Create a new texture object, using the given template info.
154 */
155 static struct pipe_resource *
156 fd_resource_create(struct pipe_screen *pscreen,
157 const struct pipe_resource *tmpl)
158 {
159 struct fd_screen *screen = fd_screen(pscreen);
160 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
161 struct pipe_resource *prsc = &rsc->base.b;
162 uint32_t flags, size;
163
164 DBG("target=%d, format=%s, %ux%u@%u, array_size=%u, last_level=%u, "
165 "nr_samples=%u, usage=%u, bind=%x, flags=%x",
166 tmpl->target, util_format_name(tmpl->format),
167 tmpl->width0, tmpl->height0, tmpl->depth0,
168 tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
169 tmpl->usage, tmpl->bind, tmpl->flags);
170
171 if (!rsc)
172 return NULL;
173
174 *prsc = *tmpl;
175
176 pipe_reference_init(&prsc->reference, 1);
177 prsc->screen = pscreen;
178
179 rsc->base.vtbl = &fd_resource_vtbl;
180 rsc->pitch = align(tmpl->width0, 32);
181 rsc->cpp = util_format_get_blocksize(tmpl->format);
182
183 assert(rsc->cpp);
184
185 size = rsc->pitch * tmpl->height0 * rsc->cpp;
186 flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE |
187 DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */
188
189 rsc->bo = fd_bo_new(screen->dev, size, flags);
190
191 return prsc;
192 }
193
194 /**
195 * Create a texture from a winsys_handle. The handle is often created in
196 * another process by first creating a pipe texture and then calling
197 * resource_get_handle.
198 */
199 static struct pipe_resource *
200 fd_resource_from_handle(struct pipe_screen *pscreen,
201 const struct pipe_resource *tmpl,
202 struct winsys_handle *handle)
203 {
204 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
205 struct pipe_resource *prsc = &rsc->base.b;
206
207 DBG("target=%d, format=%s, %ux%u@%u, array_size=%u, last_level=%u, "
208 "nr_samples=%u, usage=%u, bind=%x, flags=%x",
209 tmpl->target, util_format_name(tmpl->format),
210 tmpl->width0, tmpl->height0, tmpl->depth0,
211 tmpl->array_size, tmpl->last_level, tmpl->nr_samples,
212 tmpl->usage, tmpl->bind, tmpl->flags);
213
214 if (!rsc)
215 return NULL;
216
217 *prsc = *tmpl;
218
219 pipe_reference_init(&prsc->reference, 1);
220 prsc->screen = pscreen;
221
222 rsc->bo = fd_screen_bo_from_handle(pscreen, handle, &rsc->pitch);
223
224 rsc->base.vtbl = &fd_resource_vtbl;
225 rsc->cpp = util_format_get_blocksize(tmpl->format);
226 rsc->pitch /= rsc->cpp;
227
228 assert(rsc->cpp);
229
230 return prsc;
231 }
232
233 static bool render_blit(struct pipe_context *pctx, struct pipe_blit_info *info);
234
235 /**
236 * Copy a block of pixels from one resource to another.
237 * The resource must be of the same format.
238 * Resources with nr_samples > 1 are not allowed.
239 */
240 static void
241 fd_resource_copy_region(struct pipe_context *pctx,
242 struct pipe_resource *dst,
243 unsigned dst_level,
244 unsigned dstx, unsigned dsty, unsigned dstz,
245 struct pipe_resource *src,
246 unsigned src_level,
247 const struct pipe_box *src_box)
248 {
249 /* TODO if we have 2d core, or other DMA engine that could be used
250 * for simple copies and reasonably easily synchronized with the 3d
251 * core, this is where we'd plug it in..
252 */
253 struct pipe_blit_info info = {
254 .dst = {
255 .resource = dst,
256 .box = {
257 .x = dstx,
258 .y = dsty,
259 .z = dstz,
260 .width = src_box->width,
261 .height = src_box->height,
262 .depth = src_box->depth,
263 },
264 .format = util_format_linear(dst->format),
265 },
266 .src = {
267 .resource = src,
268 .box = *src_box,
269 .format = util_format_linear(src->format),
270 },
271 .mask = PIPE_MASK_RGBA,
272 .filter = PIPE_TEX_FILTER_NEAREST,
273 };
274 render_blit(pctx, &info);
275 }
276
277 /* Optimal hardware path for blitting pixels.
278 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
279 */
280 static void
281 fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
282 {
283 struct pipe_blit_info info = *blit_info;
284
285 if (info.src.resource->nr_samples > 1 &&
286 info.dst.resource->nr_samples <= 1 &&
287 !util_format_is_depth_or_stencil(info.src.resource->format) &&
288 !util_format_is_pure_integer(info.src.resource->format)) {
289 DBG("color resolve unimplemented");
290 return;
291 }
292
293 if (util_try_blit_via_copy_region(pctx, &info)) {
294 return; /* done */
295 }
296
297 if (info.mask & PIPE_MASK_S) {
298 DBG("cannot blit stencil, skipping");
299 info.mask &= ~PIPE_MASK_S;
300 }
301
302 render_blit(pctx, &info);
303 }
304
305 static bool
306 render_blit(struct pipe_context *pctx, struct pipe_blit_info *info)
307 {
308 struct fd_context *ctx = fd_context(pctx);
309
310 if (!util_blitter_is_blit_supported(ctx->blitter, info)) {
311 DBG("blit unsupported %s -> %s",
312 util_format_short_name(info->src.resource->format),
313 util_format_short_name(info->dst.resource->format));
314 return false;
315 }
316
317 util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertexbuf.vb);
318 util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx);
319 util_blitter_save_vertex_shader(ctx->blitter, ctx->prog.vp);
320 util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer);
321 util_blitter_save_viewport(ctx->blitter, &ctx->viewport);
322 util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
323 util_blitter_save_fragment_shader(ctx->blitter, ctx->prog.fp);
324 util_blitter_save_blend(ctx->blitter, ctx->blend);
325 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa);
326 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
327 util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask);
328 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer);
329 util_blitter_save_fragment_sampler_states(ctx->blitter,
330 ctx->fragtex.num_samplers,
331 (void **)ctx->fragtex.samplers);
332 util_blitter_save_fragment_sampler_views(ctx->blitter,
333 ctx->fragtex.num_textures, ctx->fragtex.textures);
334
335 util_blitter_blit(ctx->blitter, info);
336
337 return true;
338 }
339
340 void
341 fd_resource_screen_init(struct pipe_screen *pscreen)
342 {
343 pscreen->resource_create = fd_resource_create;
344 pscreen->resource_from_handle = fd_resource_from_handle;
345 pscreen->resource_get_handle = u_resource_get_handle_vtbl;
346 pscreen->resource_destroy = u_resource_destroy_vtbl;
347 }
348
349 void
350 fd_resource_context_init(struct pipe_context *pctx)
351 {
352 pctx->transfer_map = u_transfer_map_vtbl;
353 pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
354 pctx->transfer_unmap = u_transfer_unmap_vtbl;
355 pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
356 pctx->create_surface = fd_create_surface;
357 pctx->surface_destroy = fd_surface_destroy;
358 pctx->resource_copy_region = fd_resource_copy_region;
359 pctx->blit = fd_blit;
360 }