vc4: Rename the slice's size0.
[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 "util/u_memory.h"
26 #include "util/u_format.h"
27 #include "util/u_inlines.h"
28 #include "util/u_surface.h"
29 #include "util/u_blitter.h"
30
31 #include "vc4_screen.h"
32 #include "vc4_context.h"
33 #include "vc4_resource.h"
34 #include "vc4_tiling.h"
35
36 static void
37 vc4_resource_transfer_unmap(struct pipe_context *pctx,
38 struct pipe_transfer *ptrans)
39 {
40 struct vc4_context *vc4 = vc4_context(pctx);
41 struct vc4_transfer *trans = vc4_transfer(ptrans);
42 struct pipe_resource *prsc = ptrans->resource;
43 struct vc4_resource *rsc = vc4_resource(prsc);
44 struct vc4_resource_slice *slice = &rsc->slices[ptrans->level];
45
46 if (trans->map) {
47 if (ptrans->usage & PIPE_TRANSFER_WRITE) {
48 vc4_store_tiled_image(rsc->bo->map + slice->offset,
49 slice->stride,
50 trans->map, ptrans->stride,
51 slice->tiling, rsc->cpp,
52 &ptrans->box);
53 }
54 free(trans->map);
55 }
56
57 pipe_resource_reference(&ptrans->resource, NULL);
58 util_slab_free(&vc4->transfer_pool, ptrans);
59 }
60
61 static void *
62 vc4_resource_transfer_map(struct pipe_context *pctx,
63 struct pipe_resource *prsc,
64 unsigned level, unsigned usage,
65 const struct pipe_box *box,
66 struct pipe_transfer **pptrans)
67 {
68 struct vc4_context *vc4 = vc4_context(pctx);
69 struct vc4_resource *rsc = vc4_resource(prsc);
70 struct vc4_resource_slice *slice = &rsc->slices[level];
71 struct vc4_transfer *trans;
72 struct pipe_transfer *ptrans;
73 enum pipe_format format = prsc->format;
74 char *buf;
75
76 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
77 uint32_t size = rsc->bo->size;
78 vc4_bo_unreference(&rsc->bo);
79 rsc->bo = vc4_bo_alloc(vc4->screen, size, "resource");
80 }
81
82 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED))
83 vc4_flush_for_bo(pctx, rsc->bo);
84
85 trans = util_slab_alloc(&vc4->transfer_pool);
86 if (!trans)
87 return NULL;
88
89 /* XXX: Handle DONTBLOCK, DISCARD_RANGE, PERSISTENT, COHERENT. */
90
91 /* util_slab_alloc() doesn't zero: */
92 memset(trans, 0, sizeof(*trans));
93 ptrans = &trans->base;
94
95 pipe_resource_reference(&ptrans->resource, prsc);
96 ptrans->level = level;
97 ptrans->usage = usage;
98 ptrans->box = *box;
99
100 /* Note that the current kernel implementation is synchronous, so no
101 * need to do syncing stuff here yet.
102 */
103
104 buf = vc4_bo_map(rsc->bo);
105 if (!buf) {
106 fprintf(stderr, "Failed to map bo\n");
107 goto fail;
108 }
109
110 *pptrans = ptrans;
111
112 if (rsc->tiled) {
113 uint32_t utile_w = vc4_utile_width(rsc->cpp);
114 uint32_t utile_h = vc4_utile_height(rsc->cpp);
115
116 /* No direct mappings of tiled, since we need to manually
117 * tile/untile.
118 */
119 if (usage & PIPE_TRANSFER_MAP_DIRECTLY)
120 return NULL;
121
122 /* We need to align the box to utile boundaries, since that's
123 * what load/store operate on.
124 */
125 uint32_t box_start_x = ptrans->box.x & (utile_w - 1);
126 uint32_t box_start_y = ptrans->box.y & (utile_h - 1);
127 ptrans->box.width += box_start_x;
128 ptrans->box.x -= box_start_x;
129 ptrans->box.height += box_start_y;
130 ptrans->box.y -= box_start_y;
131 ptrans->box.width = align(ptrans->box.width, utile_w);
132 ptrans->box.height = align(ptrans->box.height, utile_h);
133
134 ptrans->stride = ptrans->box.width * rsc->cpp;
135 ptrans->layer_stride = ptrans->stride;
136
137 trans->map = malloc(ptrans->stride * ptrans->box.height);
138 if (usage & PIPE_TRANSFER_READ) {
139 vc4_load_tiled_image(trans->map, ptrans->stride,
140 buf + slice->offset,
141 slice->stride,
142 slice->tiling, rsc->cpp,
143 &ptrans->box);
144 }
145 return (trans->map +
146 box_start_x * rsc->cpp +
147 box_start_y * ptrans->stride);
148 } else {
149 ptrans->stride = slice->stride;
150 ptrans->layer_stride = ptrans->stride;
151
152 return buf + slice->offset +
153 box->y / util_format_get_blockheight(format) * ptrans->stride +
154 box->x / util_format_get_blockwidth(format) * rsc->cpp +
155 box->z * slice->size;
156 }
157
158
159 fail:
160 vc4_resource_transfer_unmap(pctx, ptrans);
161 return NULL;
162 }
163
164 static void
165 vc4_resource_destroy(struct pipe_screen *pscreen,
166 struct pipe_resource *prsc)
167 {
168 struct vc4_resource *rsc = vc4_resource(prsc);
169 vc4_bo_unreference(&rsc->bo);
170 free(rsc);
171 }
172
173 static boolean
174 vc4_resource_get_handle(struct pipe_screen *pscreen,
175 struct pipe_resource *prsc,
176 struct winsys_handle *handle)
177 {
178 struct vc4_resource *rsc = vc4_resource(prsc);
179
180 return vc4_screen_bo_get_handle(pscreen, rsc->bo, rsc->slices[0].stride,
181 handle);
182 }
183
184 static const struct u_resource_vtbl vc4_resource_vtbl = {
185 .resource_get_handle = vc4_resource_get_handle,
186 .resource_destroy = vc4_resource_destroy,
187 .transfer_map = vc4_resource_transfer_map,
188 .transfer_flush_region = u_default_transfer_flush_region,
189 .transfer_unmap = vc4_resource_transfer_unmap,
190 .transfer_inline_write = u_default_transfer_inline_write,
191 };
192
193 static void
194 vc4_setup_slices(struct vc4_resource *rsc)
195 {
196 struct pipe_resource *prsc = &rsc->base.b;
197 uint32_t width = prsc->width0;
198 uint32_t height = prsc->height0;
199 uint32_t depth = prsc->depth0;
200 uint32_t offset = 0;
201 uint32_t utile_w = vc4_utile_width(rsc->cpp);
202 uint32_t utile_h = vc4_utile_height(rsc->cpp);
203
204 for (int i = prsc->last_level; i >= 0; i--) {
205 struct vc4_resource_slice *slice = &rsc->slices[i];
206 uint32_t level_width = u_minify(width, i);
207 uint32_t level_height = u_minify(height, i);
208
209 if (rsc->tiled == VC4_TILING_FORMAT_LINEAR) {
210 slice->tiling = VC4_TILING_FORMAT_LINEAR;
211 level_width = align(level_width, 16);
212 } else {
213 if (vc4_size_is_lt(level_width, level_height,
214 rsc->cpp)) {
215 slice->tiling = VC4_TILING_FORMAT_LT;
216 level_width = align(level_width, utile_w);
217 level_height = align(level_height, utile_h);
218 } else {
219 slice->tiling = VC4_TILING_FORMAT_T;
220 level_width = align(level_width,
221 4 * 2 * utile_w);
222 level_height = align(level_height,
223 4 * 2 * utile_h);
224 }
225 }
226
227 slice->offset = offset;
228 slice->stride = level_width * rsc->cpp;
229 slice->size = level_height * slice->stride;
230
231 /* Note, since we have cubes but no 3D, depth is invariant
232 * with miplevel.
233 */
234 offset += slice->size * depth;
235 }
236
237 /* The texture base pointer that has to point to level 0 doesn't have
238 * intra-page bits, so we have to align it, and thus shift up all the
239 * smaller slices.
240 */
241 uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
242 rsc->slices[0].offset);
243 if (page_align_offset) {
244 for (int i = 0; i <= prsc->last_level; i++)
245 rsc->slices[i].offset += page_align_offset;
246 }
247 }
248
249 static struct vc4_resource *
250 vc4_resource_setup(struct pipe_screen *pscreen,
251 const struct pipe_resource *tmpl)
252 {
253 struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource);
254 if (!rsc)
255 return NULL;
256 struct pipe_resource *prsc = &rsc->base.b;
257
258 *prsc = *tmpl;
259
260 pipe_reference_init(&prsc->reference, 1);
261 prsc->screen = pscreen;
262
263 rsc->base.vtbl = &vc4_resource_vtbl;
264 rsc->cpp = util_format_get_blocksize(tmpl->format);
265
266 assert(rsc->cpp);
267
268 return rsc;
269 }
270
271 static enum vc4_texture_data_type
272 get_resource_texture_format(struct pipe_resource *prsc)
273 {
274 struct vc4_resource *rsc = vc4_resource(prsc);
275 uint8_t format = vc4_get_tex_format(prsc->format);
276
277 if (!rsc->tiled) {
278 assert(format == VC4_TEXTURE_TYPE_RGBA8888);
279 return VC4_TEXTURE_TYPE_RGBA32R;
280 }
281
282 return format;
283 }
284
285 static struct pipe_resource *
286 vc4_resource_create(struct pipe_screen *pscreen,
287 const struct pipe_resource *tmpl)
288 {
289 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
290 struct pipe_resource *prsc = &rsc->base.b;
291
292 /* We have to make shared be untiled, since we don't have any way to
293 * communicate metadata about tiling currently.
294 */
295 if (tmpl->target == PIPE_BUFFER ||
296 (tmpl->bind & (PIPE_BIND_SCANOUT |
297 PIPE_BIND_LINEAR |
298 PIPE_BIND_SHARED |
299 PIPE_BIND_CURSOR))) {
300 rsc->tiled = false;
301 } else {
302 rsc->tiled = true;
303 }
304
305 vc4_setup_slices(rsc);
306
307 rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
308 rsc->slices[0].offset +
309 rsc->slices[0].size * prsc->depth0,
310 "resource");
311 if (!rsc->bo)
312 goto fail;
313
314 if (tmpl->target != PIPE_BUFFER)
315 rsc->vc4_format = get_resource_texture_format(prsc);
316
317 return prsc;
318 fail:
319 vc4_resource_destroy(pscreen, prsc);
320 return NULL;
321 }
322
323 static struct pipe_resource *
324 vc4_resource_from_handle(struct pipe_screen *pscreen,
325 const struct pipe_resource *tmpl,
326 struct winsys_handle *handle)
327 {
328 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
329 struct pipe_resource *prsc = &rsc->base.b;
330 struct vc4_resource_slice *slice = &rsc->slices[0];
331
332 if (!rsc)
333 return NULL;
334
335 rsc->tiled = false;
336 rsc->bo = vc4_screen_bo_from_handle(pscreen, handle, &slice->stride);
337 if (!rsc->bo)
338 goto fail;
339
340 #ifdef USE_VC4_SIMULATOR
341 slice->stride = align(prsc->width0 * rsc->cpp, 16);
342 #endif
343 slice->tiling = VC4_TILING_FORMAT_LINEAR;
344
345 rsc->vc4_format = get_resource_texture_format(prsc);
346
347 return prsc;
348
349 fail:
350 vc4_resource_destroy(pscreen, prsc);
351 return NULL;
352 }
353
354 static struct pipe_surface *
355 vc4_create_surface(struct pipe_context *pctx,
356 struct pipe_resource *ptex,
357 const struct pipe_surface *surf_tmpl)
358 {
359 struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);
360 struct vc4_resource *rsc = vc4_resource(ptex);
361
362 if (!surface)
363 return NULL;
364
365 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
366
367 struct pipe_surface *psurf = &surface->base;
368 unsigned level = surf_tmpl->u.tex.level;
369
370 pipe_reference_init(&psurf->reference, 1);
371 pipe_resource_reference(&psurf->texture, ptex);
372
373 psurf->context = pctx;
374 psurf->format = surf_tmpl->format;
375 psurf->width = u_minify(ptex->width0, level);
376 psurf->height = u_minify(ptex->height0, level);
377 psurf->u.tex.level = level;
378 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
379 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
380 surface->offset = rsc->slices[level].offset;
381 surface->tiling = rsc->slices[level].tiling;
382
383 return &surface->base;
384 }
385
386 static void
387 vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
388 {
389 pipe_resource_reference(&psurf->texture, NULL);
390 FREE(psurf);
391 }
392
393 static void
394 vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
395 {
396 struct vc4_context *vc4 = vc4_context(pctx);
397
398 /* XXX: Skip this if we don't have any queued drawing to it. */
399 vc4->base.flush(pctx, NULL, 0);
400 }
401 static bool
402 render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
403 {
404 struct vc4_context *vc4 = vc4_context(ctx);
405
406 if (!util_blitter_is_blit_supported(vc4->blitter, info)) {
407 fprintf(stderr, "blit unsupported %s -> %s",
408 util_format_short_name(info->src.resource->format),
409 util_format_short_name(info->dst.resource->format));
410 return false;
411 }
412
413 util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
414 util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
415 util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.bind_vs);
416 util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
417 util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
418 util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
419 util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.bind_fs);
420 util_blitter_save_blend(vc4->blitter, vc4->blend);
421 util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
422 util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
423 util_blitter_save_sample_mask(vc4->blitter, vc4->sample_mask);
424 util_blitter_save_framebuffer(vc4->blitter, &vc4->framebuffer);
425 util_blitter_save_fragment_sampler_states(vc4->blitter,
426 vc4->fragtex.num_samplers,
427 (void **)vc4->fragtex.samplers);
428 util_blitter_save_fragment_sampler_views(vc4->blitter,
429 vc4->fragtex.num_textures, vc4->fragtex.textures);
430
431 util_blitter_blit(vc4->blitter, info);
432
433 return true;
434 }
435
436 /* Optimal hardware path for blitting pixels.
437 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
438 */
439 static void
440 vc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
441 {
442 struct pipe_blit_info info = *blit_info;
443
444 if (info.src.resource->nr_samples > 1 &&
445 info.dst.resource->nr_samples <= 1 &&
446 !util_format_is_depth_or_stencil(info.src.resource->format) &&
447 !util_format_is_pure_integer(info.src.resource->format)) {
448 fprintf(stderr, "color resolve unimplemented");
449 return;
450 }
451
452 if (util_try_blit_via_copy_region(pctx, &info)) {
453 return; /* done */
454 }
455
456 if (info.mask & PIPE_MASK_S) {
457 fprintf(stderr, "cannot blit stencil, skipping");
458 info.mask &= ~PIPE_MASK_S;
459 }
460
461 render_blit(pctx, &info);
462 }
463
464 void
465 vc4_resource_screen_init(struct pipe_screen *pscreen)
466 {
467 pscreen->resource_create = vc4_resource_create;
468 pscreen->resource_from_handle = vc4_resource_from_handle;
469 pscreen->resource_get_handle = u_resource_get_handle_vtbl;
470 pscreen->resource_destroy = u_resource_destroy_vtbl;
471 }
472
473 void
474 vc4_resource_context_init(struct pipe_context *pctx)
475 {
476 pctx->transfer_map = u_transfer_map_vtbl;
477 pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
478 pctx->transfer_unmap = u_transfer_unmap_vtbl;
479 pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
480 pctx->create_surface = vc4_create_surface;
481 pctx->surface_destroy = vc4_surface_destroy;
482 pctx->resource_copy_region = util_resource_copy_region;
483 pctx->blit = vc4_blit;
484 pctx->flush_resource = vc4_flush_resource;
485 }