freedreno_resource.c revision ca29c4c3b0e779909467c0739fc176c64a829142
1/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2 3/* 4 * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Rob Clark <robclark@freedesktop.org> 27 */ 28 29#include "util/u_format.h" 30#include "util/u_inlines.h" 31#include "util/u_transfer.h" 32#include "util/u_string.h" 33#include "util/u_surface.h" 34 35#include "freedreno_resource.h" 36#include "freedreno_screen.h" 37#include "freedreno_surface.h" 38#include "freedreno_context.h" 39#include "freedreno_query_hw.h" 40#include "freedreno_util.h" 41 42#include <errno.h> 43 44static void 45realloc_bo(struct fd_resource *rsc, uint32_t size) 46{ 47 struct fd_screen *screen = fd_screen(rsc->base.b.screen); 48 uint32_t flags = DRM_FREEDRENO_GEM_CACHE_WCOMBINE | 49 DRM_FREEDRENO_GEM_TYPE_KMEM; /* TODO */ 50 51 /* if we start using things other than write-combine, 52 * be sure to check for PIPE_RESOURCE_FLAG_MAP_COHERENT 53 */ 54 55 if (rsc->bo) 56 fd_bo_del(rsc->bo); 57 58 rsc->bo = fd_bo_new(screen->dev, size, flags); 59 rsc->timestamp = 0; 60 rsc->dirty = false; 61} 62 63static void fd_resource_transfer_flush_region(struct pipe_context *pctx, 64 struct pipe_transfer *ptrans, 65 const struct pipe_box *box) 66{ 67 struct fd_context *ctx = fd_context(pctx); 68 struct fd_resource *rsc = fd_resource(ptrans->resource); 69 70 if (rsc->dirty) 71 fd_context_render(pctx); 72 73 if (rsc->timestamp) { 74 fd_pipe_wait(ctx->screen->pipe, rsc->timestamp); 75 rsc->timestamp = 0; 76 } 77} 78 79static void 80fd_resource_transfer_unmap(struct pipe_context *pctx, 81 struct pipe_transfer *ptrans) 82{ 83 struct fd_context *ctx = fd_context(pctx); 84 struct fd_resource *rsc = fd_resource(ptrans->resource); 85 if (!(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED)) 86 fd_bo_cpu_fini(rsc->bo); 87 pipe_resource_reference(&ptrans->resource, NULL); 88 util_slab_free(&ctx->transfer_pool, ptrans); 89} 90 91static void * 92fd_resource_transfer_map(struct pipe_context *pctx, 93 struct pipe_resource *prsc, 94 unsigned level, unsigned usage, 95 const struct pipe_box *box, 96 struct pipe_transfer **pptrans) 97{ 98 struct fd_context *ctx = fd_context(pctx); 99 struct fd_resource *rsc = fd_resource(prsc); 100 struct fd_resource_slice *slice = fd_resource_slice(rsc, level); 101 struct pipe_transfer *ptrans; 102 enum pipe_format format = prsc->format; 103 uint32_t op = 0; 104 char *buf; 105 int ret = 0; 106 107 ptrans = util_slab_alloc(&ctx->transfer_pool); 108 if (!ptrans) 109 return NULL; 110 111 /* util_slab_alloc() doesn't zero: */ 112 memset(ptrans, 0, sizeof(*ptrans)); 113 114 pipe_resource_reference(&ptrans->resource, prsc); 115 ptrans->level = level; 116 ptrans->usage = usage; 117 ptrans->box = *box; 118 ptrans->stride = slice->pitch * rsc->cpp; 119 ptrans->layer_stride = ptrans->stride; 120 121 if (usage & PIPE_TRANSFER_READ) 122 op |= DRM_FREEDRENO_PREP_READ; 123 124 if (usage & PIPE_TRANSFER_WRITE) 125 op |= DRM_FREEDRENO_PREP_WRITE; 126 127 if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) 128 op |= DRM_FREEDRENO_PREP_NOSYNC; 129 130 /* some state trackers (at least XA) don't do this.. */ 131 if (!(usage & (PIPE_TRANSFER_FLUSH_EXPLICIT | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))) 132 fd_resource_transfer_flush_region(pctx, ptrans, box); 133 134 if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 135 ret = fd_bo_cpu_prep(rsc->bo, ctx->screen->pipe, op); 136 if ((ret == -EBUSY) && (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE)) 137 realloc_bo(rsc, fd_bo_size(rsc->bo)); 138 else if (ret) 139 goto fail; 140 } 141 142 buf = fd_bo_map(rsc->bo); 143 if (!buf) { 144 fd_resource_transfer_unmap(pctx, ptrans); 145 return NULL; 146 } 147 148 *pptrans = ptrans; 149 150 return buf + slice->offset + 151 box->y / util_format_get_blockheight(format) * ptrans->stride + 152 box->x / util_format_get_blockwidth(format) * rsc->cpp + 153 box->z * slice->size0; 154 155fail: 156 fd_resource_transfer_unmap(pctx, ptrans); 157 return NULL; 158} 159 160static void 161fd_resource_destroy(struct pipe_screen *pscreen, 162 struct pipe_resource *prsc) 163{ 164 struct fd_resource *rsc = fd_resource(prsc); 165 if (rsc->bo) 166 fd_bo_del(rsc->bo); 167 FREE(rsc); 168} 169 170static boolean 171fd_resource_get_handle(struct pipe_screen *pscreen, 172 struct pipe_resource *prsc, 173 struct winsys_handle *handle) 174{ 175 struct fd_resource *rsc = fd_resource(prsc); 176 177 return fd_screen_bo_get_handle(pscreen, rsc->bo, 178 rsc->slices[0].pitch * rsc->cpp, handle); 179} 180 181 182static const struct u_resource_vtbl fd_resource_vtbl = { 183 .resource_get_handle = fd_resource_get_handle, 184 .resource_destroy = fd_resource_destroy, 185 .transfer_map = fd_resource_transfer_map, 186 .transfer_flush_region = fd_resource_transfer_flush_region, 187 .transfer_unmap = fd_resource_transfer_unmap, 188 .transfer_inline_write = u_default_transfer_inline_write, 189}; 190 191static uint32_t 192setup_slices(struct fd_resource *rsc) 193{ 194 struct pipe_resource *prsc = &rsc->base.b; 195 uint32_t level, size = 0; 196 uint32_t width = prsc->width0; 197 uint32_t height = prsc->height0; 198 uint32_t depth = prsc->depth0; 199 200 for (level = 0; level <= prsc->last_level; level++) { 201 struct fd_resource_slice *slice = fd_resource_slice(rsc, level); 202 uint32_t aligned_width = align(width, 32); 203 204 slice->pitch = aligned_width; 205 slice->offset = size; 206 slice->size0 = slice->pitch * height * rsc->cpp; 207 208 size += slice->size0 * depth * prsc->array_size; 209 210 width = u_minify(width, 1); 211 height = u_minify(height, 1); 212 depth = u_minify(depth, 1); 213 } 214 215 return size; 216} 217 218/* 2d array and 3d textures seem to want their layers aligned to 219 * page boundaries 220 */ 221static uint32_t 222setup_slices_array(struct fd_resource *rsc) 223{ 224 struct pipe_resource *prsc = &rsc->base.b; 225 uint32_t level, size = 0; 226 uint32_t width = prsc->width0; 227 uint32_t height = prsc->height0; 228 uint32_t depth = prsc->depth0; 229 230 for (level = 0; level <= prsc->last_level; level++) { 231 struct fd_resource_slice *slice = fd_resource_slice(rsc, level); 232 uint32_t aligned_width = align(width, 32); 233 234 slice->pitch = aligned_width; 235 slice->offset = size; 236 slice->size0 = align(slice->pitch * height * rsc->cpp, 4096); 237 238 size += slice->size0 * depth * prsc->array_size; 239 240 width = u_minify(width, 1); 241 height = u_minify(height, 1); 242 depth = u_minify(depth, 1); 243 } 244 245 return size; 246} 247 248/** 249 * Create a new texture object, using the given template info. 250 */ 251static struct pipe_resource * 252fd_resource_create(struct pipe_screen *pscreen, 253 const struct pipe_resource *tmpl) 254{ 255 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); 256 struct pipe_resource *prsc = &rsc->base.b; 257 uint32_t size; 258 259 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 260 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 261 tmpl->target, util_format_name(tmpl->format), 262 tmpl->width0, tmpl->height0, tmpl->depth0, 263 tmpl->array_size, tmpl->last_level, tmpl->nr_samples, 264 tmpl->usage, tmpl->bind, tmpl->flags); 265 266 if (!rsc) 267 return NULL; 268 269 *prsc = *tmpl; 270 271 pipe_reference_init(&prsc->reference, 1); 272 prsc->screen = pscreen; 273 274 rsc->base.vtbl = &fd_resource_vtbl; 275 rsc->cpp = util_format_get_blocksize(tmpl->format); 276 277 assert(rsc->cpp); 278 279 switch (tmpl->target) { 280 case PIPE_TEXTURE_3D: 281 case PIPE_TEXTURE_1D_ARRAY: 282 case PIPE_TEXTURE_2D_ARRAY: 283 size = setup_slices_array(rsc); 284 break; 285 default: 286 size = setup_slices(rsc); 287 break; 288 } 289 290 realloc_bo(rsc, size); 291 if (!rsc->bo) 292 goto fail; 293 294 return prsc; 295fail: 296 fd_resource_destroy(pscreen, prsc); 297 return NULL; 298} 299 300/** 301 * Create a texture from a winsys_handle. The handle is often created in 302 * another process by first creating a pipe texture and then calling 303 * resource_get_handle. 304 */ 305static struct pipe_resource * 306fd_resource_from_handle(struct pipe_screen *pscreen, 307 const struct pipe_resource *tmpl, 308 struct winsys_handle *handle) 309{ 310 struct fd_resource *rsc = CALLOC_STRUCT(fd_resource); 311 struct fd_resource_slice *slice = &rsc->slices[0]; 312 struct pipe_resource *prsc = &rsc->base.b; 313 314 DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, " 315 "nr_samples=%u, usage=%u, bind=%x, flags=%x", 316 tmpl->target, util_format_name(tmpl->format), 317 tmpl->width0, tmpl->height0, tmpl->depth0, 318 tmpl->array_size, tmpl->last_level, tmpl->nr_samples, 319 tmpl->usage, tmpl->bind, tmpl->flags); 320 321 if (!rsc) 322 return NULL; 323 324 *prsc = *tmpl; 325 326 pipe_reference_init(&prsc->reference, 1); 327 prsc->screen = pscreen; 328 329 rsc->bo = fd_screen_bo_from_handle(pscreen, handle, &slice->pitch); 330 if (!rsc->bo) 331 goto fail; 332 333 rsc->base.vtbl = &fd_resource_vtbl; 334 rsc->cpp = util_format_get_blocksize(tmpl->format); 335 slice->pitch /= rsc->cpp; 336 337 assert(rsc->cpp); 338 339 return prsc; 340 341fail: 342 fd_resource_destroy(pscreen, prsc); 343 return NULL; 344} 345 346static void fd_blitter_pipe_begin(struct fd_context *ctx); 347static void fd_blitter_pipe_end(struct fd_context *ctx); 348 349/** 350 * _copy_region using pipe (3d engine) 351 */ 352static bool 353fd_blitter_pipe_copy_region(struct fd_context *ctx, 354 struct pipe_resource *dst, 355 unsigned dst_level, 356 unsigned dstx, unsigned dsty, unsigned dstz, 357 struct pipe_resource *src, 358 unsigned src_level, 359 const struct pipe_box *src_box) 360{ 361 /* not until we allow rendertargets to be buffers */ 362 if (dst->target == PIPE_BUFFER || src->target == PIPE_BUFFER) 363 return false; 364 365 if (!util_blitter_is_copy_supported(ctx->blitter, dst, src)) 366 return false; 367 368 fd_blitter_pipe_begin(ctx); 369 util_blitter_copy_texture(ctx->blitter, 370 dst, dst_level, dstx, dsty, dstz, 371 src, src_level, src_box); 372 fd_blitter_pipe_end(ctx); 373 374 return true; 375} 376 377/** 378 * Copy a block of pixels from one resource to another. 379 * The resource must be of the same format. 380 * Resources with nr_samples > 1 are not allowed. 381 */ 382static void 383fd_resource_copy_region(struct pipe_context *pctx, 384 struct pipe_resource *dst, 385 unsigned dst_level, 386 unsigned dstx, unsigned dsty, unsigned dstz, 387 struct pipe_resource *src, 388 unsigned src_level, 389 const struct pipe_box *src_box) 390{ 391 struct fd_context *ctx = fd_context(pctx); 392 393 /* TODO if we have 2d core, or other DMA engine that could be used 394 * for simple copies and reasonably easily synchronized with the 3d 395 * core, this is where we'd plug it in.. 396 */ 397 398 /* try blit on 3d pipe: */ 399 if (fd_blitter_pipe_copy_region(ctx, 400 dst, dst_level, dstx, dsty, dstz, 401 src, src_level, src_box)) 402 return; 403 404 /* else fallback to pure sw: */ 405 util_resource_copy_region(pctx, 406 dst, dst_level, dstx, dsty, dstz, 407 src, src_level, src_box); 408} 409 410/** 411 * Optimal hardware path for blitting pixels. 412 * Scaling, format conversion, up- and downsampling (resolve) are allowed. 413 */ 414static void 415fd_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) 416{ 417 struct fd_context *ctx = fd_context(pctx); 418 struct pipe_blit_info info = *blit_info; 419 420 if (info.src.resource->nr_samples > 1 && 421 info.dst.resource->nr_samples <= 1 && 422 !util_format_is_depth_or_stencil(info.src.resource->format) && 423 !util_format_is_pure_integer(info.src.resource->format)) { 424 DBG("color resolve unimplemented"); 425 return; 426 } 427 428 if (util_try_blit_via_copy_region(pctx, &info)) { 429 return; /* done */ 430 } 431 432 if (info.mask & PIPE_MASK_S) { 433 DBG("cannot blit stencil, skipping"); 434 info.mask &= ~PIPE_MASK_S; 435 } 436 437 if (!util_blitter_is_blit_supported(ctx->blitter, &info)) { 438 DBG("blit unsupported %s -> %s", 439 util_format_short_name(info.src.resource->format), 440 util_format_short_name(info.dst.resource->format)); 441 return; 442 } 443 444 fd_blitter_pipe_begin(ctx); 445 util_blitter_blit(ctx->blitter, &info); 446 fd_blitter_pipe_end(ctx); 447} 448 449static void 450fd_blitter_pipe_begin(struct fd_context *ctx) 451{ 452 util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertexbuf.vb); 453 util_blitter_save_vertex_elements(ctx->blitter, ctx->vtx); 454 util_blitter_save_vertex_shader(ctx->blitter, ctx->prog.vp); 455 util_blitter_save_rasterizer(ctx->blitter, ctx->rasterizer); 456 util_blitter_save_viewport(ctx->blitter, &ctx->viewport); 457 util_blitter_save_scissor(ctx->blitter, &ctx->scissor); 458 util_blitter_save_fragment_shader(ctx->blitter, ctx->prog.fp); 459 util_blitter_save_blend(ctx->blitter, ctx->blend); 460 util_blitter_save_depth_stencil_alpha(ctx->blitter, ctx->zsa); 461 util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref); 462 util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask); 463 util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer); 464 util_blitter_save_fragment_sampler_states(ctx->blitter, 465 ctx->fragtex.num_samplers, 466 (void **)ctx->fragtex.samplers); 467 util_blitter_save_fragment_sampler_views(ctx->blitter, 468 ctx->fragtex.num_textures, ctx->fragtex.textures); 469 470 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_BLIT); 471} 472 473static void 474fd_blitter_pipe_end(struct fd_context *ctx) 475{ 476 fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_NULL); 477} 478 479static void 480fd_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 481{ 482 struct fd_resource *rsc = fd_resource(prsc); 483 484 if (rsc->dirty) 485 fd_context_render(pctx); 486} 487 488void 489fd_resource_screen_init(struct pipe_screen *pscreen) 490{ 491 pscreen->resource_create = fd_resource_create; 492 pscreen->resource_from_handle = fd_resource_from_handle; 493 pscreen->resource_get_handle = u_resource_get_handle_vtbl; 494 pscreen->resource_destroy = u_resource_destroy_vtbl; 495} 496 497void 498fd_resource_context_init(struct pipe_context *pctx) 499{ 500 pctx->transfer_map = u_transfer_map_vtbl; 501 pctx->transfer_flush_region = u_transfer_flush_region_vtbl; 502 pctx->transfer_unmap = u_transfer_unmap_vtbl; 503 pctx->transfer_inline_write = u_transfer_inline_write_vtbl; 504 pctx->create_surface = fd_create_surface; 505 pctx->surface_destroy = fd_surface_destroy; 506 pctx->resource_copy_region = fd_resource_copy_region; 507 pctx->blit = fd_blit; 508 pctx->flush_resource = fd_flush_resource; 509} 510