vc4: Store the (currently always linear) tiling format in the resource.
[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_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
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->tiling = VC4_TILING_FORMAT_LINEAR;
185 rsc->bo = vc4_bo_alloc(vc4_screen(pscreen),
186 rsc->slices[0].offset +
187 rsc->slices[0].size0 * prsc->depth0,
188 "resource");
189 if (!rsc->bo)
190 goto fail;
191
192 return prsc;
193 fail:
194 vc4_resource_destroy(pscreen, prsc);
195 return NULL;
196 }
197
198 static struct pipe_resource *
199 vc4_resource_from_handle(struct pipe_screen *pscreen,
200 const struct pipe_resource *tmpl,
201 struct winsys_handle *handle)
202 {
203 struct vc4_resource *rsc = vc4_resource_setup(pscreen, tmpl);
204 struct pipe_resource *prsc = &rsc->base.b;
205 struct vc4_resource_slice *slice = &rsc->slices[0];
206
207 if (!rsc)
208 return NULL;
209
210 rsc->tiling = VC4_TILING_FORMAT_LINEAR;
211 rsc->bo = vc4_screen_bo_from_handle(pscreen, handle, &slice->stride);
212 if (!rsc->bo)
213 goto fail;
214
215 #ifdef USE_VC4_SIMULATOR
216 slice->stride = align(prsc->width0 * rsc->cpp, 16);
217 #endif
218
219 return prsc;
220
221 fail:
222 vc4_resource_destroy(pscreen, prsc);
223 return NULL;
224 }
225
226 static struct pipe_surface *
227 vc4_create_surface(struct pipe_context *pctx,
228 struct pipe_resource *ptex,
229 const struct pipe_surface *surf_tmpl)
230 {
231 struct vc4_surface *surface = CALLOC_STRUCT(vc4_surface);
232
233 if (!surface)
234 return NULL;
235
236 assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
237
238 struct pipe_surface *psurf = &surface->base;
239 unsigned level = surf_tmpl->u.tex.level;
240
241 pipe_reference_init(&psurf->reference, 1);
242 pipe_resource_reference(&psurf->texture, ptex);
243
244 psurf->context = pctx;
245 psurf->format = surf_tmpl->format;
246 psurf->width = u_minify(ptex->width0, level);
247 psurf->height = u_minify(ptex->height0, level);
248 psurf->u.tex.level = level;
249 psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
250 psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
251
252 return &surface->base;
253 }
254
255 static void
256 vc4_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
257 {
258 pipe_resource_reference(&psurf->texture, NULL);
259 FREE(psurf);
260 }
261
262 static void
263 vc4_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
264 {
265 struct vc4_context *vc4 = vc4_context(pctx);
266
267 /* XXX: Skip this if we don't have any queued drawing to it. */
268 vc4->base.flush(pctx, NULL, 0);
269 }
270 static bool
271 render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
272 {
273 struct vc4_context *vc4 = vc4_context(ctx);
274
275 if (!util_blitter_is_blit_supported(vc4->blitter, info)) {
276 fprintf(stderr, "blit unsupported %s -> %s",
277 util_format_short_name(info->src.resource->format),
278 util_format_short_name(info->dst.resource->format));
279 return false;
280 }
281
282 util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
283 util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
284 util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.vs);
285 util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
286 util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
287 util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
288 util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.fs);
289 util_blitter_save_blend(vc4->blitter, vc4->blend);
290 util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
291 util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
292 util_blitter_save_sample_mask(vc4->blitter, vc4->sample_mask);
293 util_blitter_save_framebuffer(vc4->blitter, &vc4->framebuffer);
294 util_blitter_save_fragment_sampler_states(vc4->blitter,
295 vc4->fragtex.num_samplers,
296 (void **)vc4->fragtex.samplers);
297 util_blitter_save_fragment_sampler_views(vc4->blitter,
298 vc4->fragtex.num_textures, vc4->fragtex.textures);
299
300 util_blitter_blit(vc4->blitter, info);
301
302 return true;
303 }
304
305 /* Optimal hardware path for blitting pixels.
306 * Scaling, format conversion, up- and downsampling (resolve) are allowed.
307 */
308 static void
309 vc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
310 {
311 struct pipe_blit_info info = *blit_info;
312
313 if (info.src.resource->nr_samples > 1 &&
314 info.dst.resource->nr_samples <= 1 &&
315 !util_format_is_depth_or_stencil(info.src.resource->format) &&
316 !util_format_is_pure_integer(info.src.resource->format)) {
317 fprintf(stderr, "color resolve unimplemented");
318 return;
319 }
320
321 if (util_try_blit_via_copy_region(pctx, &info)) {
322 return; /* done */
323 }
324
325 if (info.mask & PIPE_MASK_S) {
326 fprintf(stderr, "cannot blit stencil, skipping");
327 info.mask &= ~PIPE_MASK_S;
328 }
329
330 render_blit(pctx, &info);
331 }
332
333 void
334 vc4_resource_screen_init(struct pipe_screen *pscreen)
335 {
336 pscreen->resource_create = vc4_resource_create;
337 pscreen->resource_from_handle = vc4_resource_from_handle;
338 pscreen->resource_get_handle = u_resource_get_handle_vtbl;
339 pscreen->resource_destroy = u_resource_destroy_vtbl;
340 }
341
342 void
343 vc4_resource_context_init(struct pipe_context *pctx)
344 {
345 pctx->transfer_map = u_transfer_map_vtbl;
346 pctx->transfer_flush_region = u_transfer_flush_region_vtbl;
347 pctx->transfer_unmap = u_transfer_unmap_vtbl;
348 pctx->transfer_inline_write = u_transfer_inline_write_vtbl;
349 pctx->create_surface = vc4_create_surface;
350 pctx->surface_destroy = vc4_surface_destroy;
351 pctx->resource_copy_region = util_resource_copy_region;
352 pctx->blit = vc4_blit;
353 pctx->flush_resource = vc4_flush_resource;
354 }