vc4: Drop the flush at the end of the draw
[mesa.git] / src / gallium / drivers / vc4 / vc4_resource.c
1 /*
2 * Copyright © 2014 Broadcom
3 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25 #include <stdio.h>
26
27 #include "util/u_memory.h"
28 #include "util/u_format.h"
29 #include "util/u_inlines.h"
30 #include "util/u_surface.h"
31 #include "util/u_blitter.h"
32
33 #include "vc4_screen.h"
34 #include "vc4_context.h"
35 #include "vc4_resource.h"
36
37 static void
38 vc4_resource_transfer_unmap(struct pipe_context *pctx,
39 struct pipe_transfer *ptrans)
40 {
41 struct vc4_context *vc4 = vc4_context(pctx);
42
43 pipe_resource_reference(&ptrans->resource, NULL);
44 util_slab_free(&vc4->transfer_pool, ptrans);
45 }
46
47 static void *
48 vc4_resource_transfer_map(struct pipe_context *pctx,
49 struct pipe_resource *prsc,
50 unsigned level, unsigned usage,
51 const struct pipe_box *box,
52 struct pipe_transfer **pptrans)
53 {
54 struct vc4_context *vc4 = vc4_context(pctx);
55 struct vc4_resource *rsc = vc4_resource(prsc);
56 struct pipe_transfer *ptrans;
57 enum pipe_format format = prsc->format;
58 char *buf;
59
60 vc4_flush(pctx);
61
62 ptrans = util_slab_alloc(&vc4->transfer_pool);
63 if (!ptrans)
64 return NULL;
65
66 /* util_slab_alloc() doesn't zero: */
67 memset(ptrans, 0, sizeof(*ptrans));
68
69 pipe_resource_reference(&ptrans->resource, prsc);
70 ptrans->level = level;
71 ptrans->usage = usage;
72 ptrans->box = *box;
73 ptrans->stride = rsc->slices[level].stride;
74 ptrans->layer_stride = ptrans->stride;
75
76 /* Note that the current kernel implementation is synchronous, so no
77 * need to do syncing stuff here yet.
78 */
79
80 buf = vc4_bo_map(rsc->bo);
81 if (!buf) {
82 fprintf(stderr, "Failed to map bo\n");
83 goto fail;
84 }
85
86 *pptrans = ptrans;
87
88 return buf + rsc->slices[level].offset +
89 box->y / util_format_get_blockheight(format) * ptrans->stride +
90 box->x / util_format_get_blockwidth(format) * rsc->cpp +
91 box->z * rsc->slices[level].size0;
92
93 fail:
94 vc4_resource_transfer_unmap(pctx, ptrans);
95 return NULL;
96 }
97
98 static void
99 vc4_resource_destroy(struct pipe_screen *pscreen,
100 struct pipe_resource *prsc)
101 {
102 struct vc4_resource *rsc = vc4_resource(prsc);
103 vc4_bo_unreference(&rsc->bo);
104 free(rsc);
105 }
106
107 static boolean
108 vc4_resource_get_handle(struct pipe_screen *pscreen,
109 struct pipe_resource *prsc,
110 struct winsys_handle *handle)
111 {
112 struct vc4_resource *rsc = vc4_resource(prsc);
113
114 return vc4_screen_bo_get_handle(pscreen, rsc->bo, rsc->slices[0].stride,
115 handle);
116 }
117
118 static const struct u_resource_vtbl vc4_resource_vtbl = {
119 .resource_get_handle = vc4_resource_get_handle,
120 .resource_destroy = vc4_resource_destroy,
121 .transfer_map = vc4_resource_transfer_map,
122 .transfer_flush_region = u_default_transfer_flush_region,
123 .transfer_unmap = vc4_resource_transfer_unmap,
124 .transfer_inline_write = u_default_transfer_inline_write,
125 };
126
127 static void
128 vc4_setup_slices(struct vc4_resource *rsc)
129 {
130 struct pipe_resource *prsc = &rsc->base.b;
131 uint32_t width = prsc->width0;
132 uint32_t height = prsc->height0;
133 uint32_t depth = prsc->depth0;
134 uint32_t offset = 0;
135
136 for (int i = prsc->last_level; i >= 0; i--) {
137 struct vc4_resource_slice *slice = &rsc->slices[i];
138 uint32_t level_width = u_minify(width, i);
139 uint32_t level_height = u_minify(height, i);
140
141 slice->offset = offset;
142 slice->stride = align(level_width * rsc->cpp, 16);
143 slice->size0 = level_height * slice->stride;
144
145 /* Note, since we have cubes but no 3D, depth is invariant
146 * with miplevel.
147 */
148 offset += slice->size0 * depth;
149 }
150 /* XXX: align level 0 offset? */
151 }
152
153 static struct vc4_resource *
154 vc4_resource_setup(struct pipe_screen *pscreen,
155 const struct pipe_resource *tmpl)
156 {
157 struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource);
158 if (!rsc)
159 return NULL;
160 struct pipe_resource *prsc = &rsc->base.b;
161
162 *prsc = *tmpl;
163
164 pipe_reference_init(&prsc->reference, 1);
165 prsc->screen = pscreen;
166
167 rsc->base.vtbl = &vc4_resource_vtbl;
168 rsc->cpp = util_format_get_blocksize(tmpl->format);
169
170 assert(rsc->cpp);
171
172 return rsc;
173 }
174
175 static struct pipe_resource *
176 vc4_resource_create(struct pipe_screen *pscreen,
177 const struct pipe_resource *tmpl)
178 {
179 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
180 struct pipe_resource *prsc = &rsc->base.b;
181
182 vc4_setup_slices(rsc);
183
184 rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
185 rsc->slices[0].offset +
186 rsc->slices[0].size0 * prsc->depth0,
187 "resource");
188 if (!rsc->bo)
189 goto fail;
190
191 return prsc;
192 fail:
193 vc4_resource_destroy(pscreen, prsc);
194 return NULL;
195 }
196
197 static struct pipe_resource *
198 vc4_resource_from_handle(struct pipe_screen *pscreen,
199 const struct pipe_resource *tmpl,
200 struct winsys_handle *handle)
201 {
202 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
203 struct pipe_resource *prsc = &rsc->base.b;
204 struct vc4_resource_slice *slice = &rsc->slices[0];
205
206 if (!rsc)
207 return NULL;
208
209 rsc->bo = vc4_screen_bo_from_handle(pscreen, handle, &slice->stride);
210 if (!rsc->bo)
211 goto fail;
212
213 #ifdef USE_VC4_SIMULATOR
214 slice->stride = align(prsc->width0 * rsc->cpp, 16);
215 #endif
216
217 return prsc;
218
219 fail:
220 vc4_resource_destroy(pscreen, prsc);
221 return NULL;
222 }
223
224 static struct pipe_surface *
225 vc4_create_surface(struct pipe_context *pctx,
226 struct pipe_resource *ptex,
227 const struct pipe_surface *surf_tmpl)
228 {
229 struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);
230
231 if (!surface)
232 return NULL;
233
234 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
235
236 struct pipe_surface *psurf = &surface->base;
237 unsigned level = surf_tmpl->u.tex.level;
238
239 pipe_reference_init(&psurf->reference, 1);
240 pipe_resource_reference(&psurf->texture, ptex);
241
242 psurf->context = pctx;
243 psurf->format = surf_tmpl->format;
244 psurf->width = u_minify(ptex->width0, level);
245 psurf->height = u_minify(ptex->height0, level);
246 psurf->u.tex.level = level;
247 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
248 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
249
250 return &surface->base;
251 }
252
253 static void
254 vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
255 {
256 pipe_resource_reference(&psurf->texture, NULL);
257 FREE(psurf);
258 }
259
260 static void
261 vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
262 {
263 struct vc4_context *vc4 = vc4_context(pctx);
264
265 /* XXX: Skip this if we don't have any queued drawing to it. */
266 vc4->base.flush(pctx, NULL, 0);
267 }
268 static bool
269 render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
270 {
271 struct vc4_context *vc4 = vc4_context(ctx);
272
273 if (!util_blitter_is_blit_supported(vc4->blitter, info)) {
274 fprintf(stderr, "blit unsupported %s -> %s",
275 util_format_short_name(info->src.resource->format),
276 util_format_short_name(info->dst.resource->format));
277 return false;
278 }
279
280 util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
281 util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
282 util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.vs);
283 util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
284 util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
285 util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
286 util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.fs);
287 util_blitter_save_blend(vc4->blitter, vc4->blend);
288 util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
289 util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
290 util_blitter_save_sample_mask(vc4->blitter, vc4->sample_mask);
291 util_blitter_save_framebuffer(vc4->blitter, &vc4->framebuffer);
292 util_blitter_save_fragment_sampler_states(vc4->blitter,
293 vc4->fragtex.num_samplers,
294 (void **)vc4->fragtex.samplers);
295 util_blitter_save_fragment_sampler_views(vc4->blitter,
296 vc4->fragtex.num_textures, vc4->fragtex.textures);
297
298 util_blitter_blit(vc4->blitter, info);
299
300 return true;
301 }
302
303 /* Optimal hardware path for blitting pixels.
304 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
305 */
306 static void
307 vc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
308 {
309 struct pipe_blit_info info = *blit_info;
310
311 if (info.src.resource->nr_samples > 1 &&
312 info.dst.resource->nr_samples <= 1 &&
313 !util_format_is_depth_or_stencil(info.src.resource->format) &&
314 !util_format_is_pure_integer(info.src.resource->format)) {
315 fprintf(stderr, "color resolve unimplemented");
316 return;
317 }
318
319 if (util_try_blit_via_copy_region(pctx, &info)) {
320 return; /* done */
321 }
322
323 if (info.mask & PIPE_MASK_S) {
324 fprintf(stderr, "cannot blit stencil, skipping");
325 info.mask &= ~PIPE_MASK_S;
326 }
327
328 render_blit(pctx, &info);
329 }
330
331 void
332 vc4_resource_screen_init(struct pipe_screen *pscreen)
333 {
334 pscreen->resource_create = vc4_resource_create;
335 pscreen->resource_from_handle = vc4_resource_from_handle;
336 pscreen->resource_get_handle = u_resource_get_handle_vtbl;
337 pscreen->resource_destroy = u_resource_destroy_vtbl;
338 }
339
340 void
341 vc4_resource_context_init(struct pipe_context *pctx)
342 {
343 pctx->transfer_map = u_transfer_map_vtbl;
344 pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
345 pctx->transfer_unmap = u_transfer_unmap_vtbl;
346 pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
347 pctx->create_surface = vc4_create_surface;
348 pctx->surface_destroy = vc4_surface_destroy;
349 pctx->resource_copy_region = util_resource_copy_region;
350 pctx->blit = vc4_blit;
351 pctx->flush_resource = vc4_flush_resource;
352 }