vc4_resource.c revision 848b8605
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
37static void
38vc4_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
47static void *
48vc4_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_for_bo(pctx, rsc->bo);
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
93fail:
94        vc4_resource_transfer_unmap(pctx, ptrans);
95        return NULL;
96}
97
98static void
99vc4_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
107static boolean
108vc4_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
118static 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
127static void
128vc4_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
151        /* The texture base pointer that has to point to level 0 doesn't have
152         * intra-page bits, so we have to align it, and thus shift up all the
153         * smaller slices.
154         */
155        uint32_t page_align_offset = (align(rsc->slices[0].offset, 4096) -
156                                      rsc->slices[0].offset);
157        if (page_align_offset) {
158                for (int i = 0; i <= prsc->last_level; i++)
159                        rsc->slices[i].offset += page_align_offset;
160        }
161}
162
163static struct vc4_resource *
164vc4_resource_setup(struct pipe_screen *pscreen,
165                   const struct pipe_resource *tmpl)
166{
167        struct vc4_resource *rsc = CALLOC_STRUCT(vc4_resource);
168        if (!rsc)
169                return NULL;
170        struct pipe_resource *prsc = &rsc->base.b;
171
172        *prsc = *tmpl;
173
174        pipe_reference_init(&prsc->reference, 1);
175        prsc->screen = pscreen;
176
177        rsc->base.vtbl = &vc4_resource_vtbl;
178        rsc->cpp = util_format_get_blocksize(tmpl->format);
179
180        assert(rsc->cpp);
181
182        return rsc;
183}
184
185static struct pipe_resource *
186vc4_resource_create(struct pipe_screen *pscreen,
187                    const struct pipe_resource *tmpl)
188{
189        struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
190        struct pipe_resource *prsc = &rsc->base.b;
191
192        vc4_setup_slices(rsc);
193
194        rsc->tiling = VC4_TILING_FORMAT_LINEAR;
195        rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
196                               rsc->slices[0].offset +
197                               rsc->slices[0].size0 * prsc->depth0,
198                               "resource");
199        if (!rsc->bo)
200                goto fail;
201
202        return prsc;
203fail:
204        vc4_resource_destroy(pscreen, prsc);
205        return NULL;
206}
207
208static struct pipe_resource *
209vc4_resource_from_handle(struct pipe_screen *pscreen,
210                         const struct pipe_resource *tmpl,
211                         struct winsys_handle *handle)
212{
213        struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
214        struct pipe_resource *prsc = &rsc->base.b;
215        struct vc4_resource_slice *slice = &rsc->slices[0];
216
217        if (!rsc)
218                return NULL;
219
220        rsc->tiling = VC4_TILING_FORMAT_LINEAR;
221        rsc->bo = vc4_screen_bo_from_handle(pscreen, handle, &slice->stride);
222        if (!rsc->bo)
223                goto fail;
224
225#ifdef USE_VC4_SIMULATOR
226        slice->stride = align(prsc->width0 * rsc->cpp, 16);
227#endif
228
229        return prsc;
230
231fail:
232        vc4_resource_destroy(pscreen, prsc);
233        return NULL;
234}
235
236static struct pipe_surface *
237vc4_create_surface(struct pipe_context *pctx,
238                   struct pipe_resource *ptex,
239                   const struct pipe_surface *surf_tmpl)
240{
241        struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);
242        struct vc4_resource *rsc = vc4_resource(ptex);
243
244        if (!surface)
245                return NULL;
246
247        assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
248
249        struct pipe_surface *psurf = &surface->base;
250        unsigned level = surf_tmpl->u.tex.level;
251
252        pipe_reference_init(&psurf->reference, 1);
253        pipe_resource_reference(&psurf->texture, ptex);
254
255        psurf->context = pctx;
256        psurf->format = surf_tmpl->format;
257        psurf->width = u_minify(ptex->width0, level);
258        psurf->height = u_minify(ptex->height0, level);
259        psurf->u.tex.level = level;
260        psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
261        psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
262        surface->offset = rsc->slices[level].offset;
263
264        return &surface->base;
265}
266
267static void
268vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
269{
270        pipe_resource_reference(&psurf->texture, NULL);
271        FREE(psurf);
272}
273
274static void
275vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
276{
277        struct vc4_context *vc4 = vc4_context(pctx);
278
279        /* XXX: Skip this if we don't have any queued drawing to it. */
280        vc4->base.flush(pctx, NULL, 0);
281}
282static bool
283render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
284{
285        struct vc4_context *vc4 = vc4_context(ctx);
286
287        if (!util_blitter_is_blit_supported(vc4->blitter, info)) {
288                fprintf(stderr, "blit unsupported %s -> %s",
289                    util_format_short_name(info->src.resource->format),
290                    util_format_short_name(info->dst.resource->format));
291                return false;
292        }
293
294        util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
295        util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
296        util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.vs);
297        util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
298        util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
299        util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
300        util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.fs);
301        util_blitter_save_blend(vc4->blitter, vc4->blend);
302        util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
303        util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
304        util_blitter_save_sample_mask(vc4->blitter, vc4->sample_mask);
305        util_blitter_save_framebuffer(vc4->blitter, &vc4->framebuffer);
306        util_blitter_save_fragment_sampler_states(vc4->blitter,
307                        vc4->fragtex.num_samplers,
308                        (void **)vc4->fragtex.samplers);
309        util_blitter_save_fragment_sampler_views(vc4->blitter,
310                        vc4->fragtex.num_textures, vc4->fragtex.textures);
311
312        util_blitter_blit(vc4->blitter, info);
313
314        return true;
315}
316
317/* Optimal hardware path for blitting pixels.
318 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
319 */
320static void
321vc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
322{
323        struct pipe_blit_info info = *blit_info;
324
325        if (info.src.resource->nr_samples > 1 &&
326            info.dst.resource->nr_samples <= 1 &&
327            !util_format_is_depth_or_stencil(info.src.resource->format) &&
328            !util_format_is_pure_integer(info.src.resource->format)) {
329                fprintf(stderr, "color resolve unimplemented");
330                return;
331        }
332
333        if (util_try_blit_via_copy_region(pctx, &info)) {
334                return; /* done */
335        }
336
337        if (info.mask & PIPE_MASK_S) {
338                fprintf(stderr, "cannot blit stencil, skipping");
339                info.mask &= ~PIPE_MASK_S;
340        }
341
342        render_blit(pctx, &info);
343}
344
345void
346vc4_resource_screen_init(struct pipe_screen *pscreen)
347{
348        pscreen->resource_create = vc4_resource_create;
349        pscreen->resource_from_handle = vc4_resource_from_handle;
350        pscreen->resource_get_handle = u_resource_get_handle_vtbl;
351        pscreen->resource_destroy = u_resource_destroy_vtbl;
352}
353
354void
355vc4_resource_context_init(struct pipe_context *pctx)
356{
357        pctx->transfer_map = u_transfer_map_vtbl;
358        pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
359        pctx->transfer_unmap = u_transfer_unmap_vtbl;
360        pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
361        pctx->create_surface = vc4_create_surface;
362        pctx->surface_destroy = vc4_surface_destroy;
363        pctx->resource_copy_region = util_resource_copy_region;
364        pctx->blit = vc4_blit;
365        pctx->flush_resource = vc4_flush_resource;
366}
367