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