Rev 4358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 1 | /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ |
2 | |||
3 | /* |
||
4 | * Copyright (C) 2012 Rob Clark |
||
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 |
||
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); |
||
4401 | Serge | 62 | struct fd_resource *rsc = fd_resource(ptrans->resource); |
63 | if (!(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED)) |
||
64 | fd_bo_cpu_fini(rsc->bo); |
||
4358 | Serge | 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; |
||
4401 | Serge | 80 | uint32_t op = 0; |
4358 | Serge | 81 | char *buf; |
82 | |||
83 | if (!ptrans) |
||
84 | return NULL; |
||
85 | |||
4401 | Serge | 86 | /* util_slab_alloc() doesn't zero: */ |
4358 | Serge | 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.. */ |
||
4401 | Serge | 97 | if (!(usage & PIPE_TRANSFER_FLUSH_EXPLICIT)) |
98 | fd_resource_transfer_flush_region(pctx, ptrans, box); |
||
4358 | Serge | 99 | |
100 | buf = fd_bo_map(rsc->bo); |
||
101 | if (!buf) { |
||
102 | fd_resource_transfer_unmap(pctx, ptrans); |
||
103 | return NULL; |
||
104 | } |
||
105 | |||
4401 | Serge | 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 | |||
4358 | Serge | 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 | }=> |