1b8e80941Smrg/************************************************************************** 2b8e80941Smrg * 3b8e80941Smrg * Copyright 2008 VMware, Inc. 4b8e80941Smrg * Copyright 2014 Broadcom 5b8e80941Smrg * Copyright 2018 Alyssa Rosenzweig 6b8e80941Smrg * All Rights Reserved. 7b8e80941Smrg * 8b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9b8e80941Smrg * copy of this software and associated documentation files (the 10b8e80941Smrg * "Software"), to deal in the Software without restriction, including 11b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish, 12b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to 13b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to 14b8e80941Smrg * the following conditions: 15b8e80941Smrg * 16b8e80941Smrg * The above copyright notice and this permission notice (including the 17b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions 18b8e80941Smrg * of the Software. 19b8e80941Smrg * 20b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 21b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22b8e80941Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 23b8e80941Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 24b8e80941Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 25b8e80941Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26b8e80941Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27b8e80941Smrg * 28b8e80941Smrg **************************************************************************/ 29b8e80941Smrg 30b8e80941Smrg#include <xf86drm.h> 31b8e80941Smrg#include <fcntl.h> 32b8e80941Smrg#include "drm-uapi/drm_fourcc.h" 33b8e80941Smrg 34b8e80941Smrg#include "state_tracker/winsys_handle.h" 35b8e80941Smrg#include "util/u_format.h" 36b8e80941Smrg#include "util/u_memory.h" 37b8e80941Smrg#include "util/u_surface.h" 38b8e80941Smrg#include "util/u_transfer.h" 39b8e80941Smrg#include "util/u_transfer_helper.h" 40b8e80941Smrg 41b8e80941Smrg#include "pan_context.h" 42b8e80941Smrg#include "pan_screen.h" 43b8e80941Smrg#include "pan_resource.h" 44b8e80941Smrg#include "pan_swizzle.h" 45b8e80941Smrg#include "pan_util.h" 46b8e80941Smrg 47b8e80941Smrgstatic struct pipe_resource * 48b8e80941Smrgpanfrost_resource_from_handle(struct pipe_screen *pscreen, 49b8e80941Smrg const struct pipe_resource *templat, 50b8e80941Smrg struct winsys_handle *whandle, 51b8e80941Smrg unsigned usage) 52b8e80941Smrg{ 53b8e80941Smrg struct panfrost_screen *screen = pan_screen(pscreen); 54b8e80941Smrg struct panfrost_resource *rsc; 55b8e80941Smrg struct pipe_resource *prsc; 56b8e80941Smrg 57b8e80941Smrg assert(whandle->type == WINSYS_HANDLE_TYPE_FD); 58b8e80941Smrg 59b8e80941Smrg rsc = CALLOC_STRUCT(panfrost_resource); 60b8e80941Smrg if (!rsc) 61b8e80941Smrg return NULL; 62b8e80941Smrg 63b8e80941Smrg prsc = &rsc->base; 64b8e80941Smrg 65b8e80941Smrg *prsc = *templat; 66b8e80941Smrg 67b8e80941Smrg pipe_reference_init(&prsc->reference, 1); 68b8e80941Smrg prsc->screen = pscreen; 69b8e80941Smrg 70b8e80941Smrg rsc->bo = screen->driver->import_bo(screen, whandle); 71b8e80941Smrg rsc->bo->slices[0].stride = whandle->stride; 72b8e80941Smrg 73b8e80941Smrg if (screen->ro) { 74b8e80941Smrg rsc->scanout = 75b8e80941Smrg renderonly_create_gpu_import_for_resource(prsc, screen->ro, NULL); 76b8e80941Smrg /* failure is expected in some cases.. */ 77b8e80941Smrg } 78b8e80941Smrg 79b8e80941Smrg return prsc; 80b8e80941Smrg} 81b8e80941Smrg 82b8e80941Smrgstatic boolean 83b8e80941Smrgpanfrost_resource_get_handle(struct pipe_screen *pscreen, 84b8e80941Smrg struct pipe_context *ctx, 85b8e80941Smrg struct pipe_resource *pt, 86b8e80941Smrg struct winsys_handle *handle, 87b8e80941Smrg unsigned usage) 88b8e80941Smrg{ 89b8e80941Smrg struct panfrost_screen *screen = pan_screen(pscreen); 90b8e80941Smrg struct panfrost_resource *rsrc = (struct panfrost_resource *) pt; 91b8e80941Smrg struct renderonly_scanout *scanout = rsrc->scanout; 92b8e80941Smrg 93b8e80941Smrg handle->modifier = DRM_FORMAT_MOD_INVALID; 94b8e80941Smrg 95b8e80941Smrg if (handle->type == WINSYS_HANDLE_TYPE_SHARED) { 96b8e80941Smrg return FALSE; 97b8e80941Smrg } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) { 98b8e80941Smrg if (renderonly_get_handle(scanout, handle)) 99b8e80941Smrg return TRUE; 100b8e80941Smrg 101b8e80941Smrg handle->handle = rsrc->bo->gem_handle; 102b8e80941Smrg handle->stride = rsrc->bo->slices[0].stride; 103b8e80941Smrg return TRUE; 104b8e80941Smrg } else if (handle->type == WINSYS_HANDLE_TYPE_FD) { 105b8e80941Smrg if (scanout) { 106b8e80941Smrg struct drm_prime_handle args = { 107b8e80941Smrg .handle = scanout->handle, 108b8e80941Smrg .flags = DRM_CLOEXEC, 109b8e80941Smrg }; 110b8e80941Smrg 111b8e80941Smrg int ret = drmIoctl(screen->ro->kms_fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); 112b8e80941Smrg if (ret == -1) 113b8e80941Smrg return FALSE; 114b8e80941Smrg 115b8e80941Smrg handle->stride = scanout->stride; 116b8e80941Smrg handle->handle = args.fd; 117b8e80941Smrg 118b8e80941Smrg return TRUE; 119b8e80941Smrg } else 120b8e80941Smrg return screen->driver->export_bo(screen, rsrc->bo->gem_handle, rsrc->bo->slices[0].stride, handle); 121b8e80941Smrg } 122b8e80941Smrg 123b8e80941Smrg return FALSE; 124b8e80941Smrg} 125b8e80941Smrg 126b8e80941Smrgstatic void 127b8e80941Smrgpanfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 128b8e80941Smrg{ 129b8e80941Smrg //DBG("TODO %s\n", __func__); 130b8e80941Smrg} 131b8e80941Smrg 132b8e80941Smrgstatic void 133b8e80941Smrgpanfrost_blit(struct pipe_context *pipe, 134b8e80941Smrg const struct pipe_blit_info *info) 135b8e80941Smrg{ 136b8e80941Smrg if (util_try_blit_via_copy_region(pipe, info)) 137b8e80941Smrg return; 138b8e80941Smrg 139b8e80941Smrg /* TODO */ 140b8e80941Smrg DBG("Unhandled blit.\n"); 141b8e80941Smrg 142b8e80941Smrg return; 143b8e80941Smrg} 144b8e80941Smrg 145b8e80941Smrgstatic struct pipe_surface * 146b8e80941Smrgpanfrost_create_surface(struct pipe_context *pipe, 147b8e80941Smrg struct pipe_resource *pt, 148b8e80941Smrg const struct pipe_surface *surf_tmpl) 149b8e80941Smrg{ 150b8e80941Smrg struct pipe_surface *ps = NULL; 151b8e80941Smrg 152b8e80941Smrg ps = CALLOC_STRUCT(pipe_surface); 153b8e80941Smrg 154b8e80941Smrg if (ps) { 155b8e80941Smrg pipe_reference_init(&ps->reference, 1); 156b8e80941Smrg pipe_resource_reference(&ps->texture, pt); 157b8e80941Smrg ps->context = pipe; 158b8e80941Smrg ps->format = surf_tmpl->format; 159b8e80941Smrg 160b8e80941Smrg if (pt->target != PIPE_BUFFER) { 161b8e80941Smrg assert(surf_tmpl->u.tex.level <= pt->last_level); 162b8e80941Smrg ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level); 163b8e80941Smrg ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level); 164b8e80941Smrg ps->u.tex.level = surf_tmpl->u.tex.level; 165b8e80941Smrg ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 166b8e80941Smrg ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 167b8e80941Smrg } else { 168b8e80941Smrg /* setting width as number of elements should get us correct renderbuffer width */ 169b8e80941Smrg ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1; 170b8e80941Smrg ps->height = pt->height0; 171b8e80941Smrg ps->u.buf.first_element = surf_tmpl->u.buf.first_element; 172b8e80941Smrg ps->u.buf.last_element = surf_tmpl->u.buf.last_element; 173b8e80941Smrg assert(ps->u.buf.first_element <= ps->u.buf.last_element); 174b8e80941Smrg assert(ps->u.buf.last_element < ps->width); 175b8e80941Smrg } 176b8e80941Smrg } 177b8e80941Smrg 178b8e80941Smrg return ps; 179b8e80941Smrg} 180b8e80941Smrg 181b8e80941Smrgstatic void 182b8e80941Smrgpanfrost_surface_destroy(struct pipe_context *pipe, 183b8e80941Smrg struct pipe_surface *surf) 184b8e80941Smrg{ 185b8e80941Smrg assert(surf->texture); 186b8e80941Smrg pipe_resource_reference(&surf->texture, NULL); 187b8e80941Smrg free(surf); 188b8e80941Smrg} 189b8e80941Smrg 190b8e80941Smrgstatic void 191b8e80941Smrgpanfrost_setup_slices(const struct pipe_resource *tmpl, struct panfrost_bo *bo) 192b8e80941Smrg{ 193b8e80941Smrg unsigned width = tmpl->width0; 194b8e80941Smrg unsigned height = tmpl->height0; 195b8e80941Smrg unsigned bytes_per_pixel = util_format_get_blocksize(tmpl->format); 196b8e80941Smrg 197b8e80941Smrg unsigned offset = 0; 198b8e80941Smrg 199b8e80941Smrg for (unsigned l = 0; l <= tmpl->last_level; ++l) { 200b8e80941Smrg struct panfrost_slice *slice = &bo->slices[l]; 201b8e80941Smrg 202b8e80941Smrg unsigned effective_width = width; 203b8e80941Smrg unsigned effective_height = height; 204b8e80941Smrg 205b8e80941Smrg /* Tiled operates blockwise; linear is packed */ 206b8e80941Smrg 207b8e80941Smrg if (bo->layout == PAN_TILED) { 208b8e80941Smrg effective_width = ALIGN(effective_width, 16); 209b8e80941Smrg effective_height = ALIGN(effective_height, 16); 210b8e80941Smrg } 211b8e80941Smrg 212b8e80941Smrg slice->offset = offset; 213b8e80941Smrg slice->stride = bytes_per_pixel * effective_width; 214b8e80941Smrg 215b8e80941Smrg offset += slice->stride * effective_height; 216b8e80941Smrg 217b8e80941Smrg width = u_minify(width, 1); 218b8e80941Smrg height = u_minify(height, 1); 219b8e80941Smrg } 220b8e80941Smrg 221b8e80941Smrg assert(tmpl->array_size); 222b8e80941Smrg 223b8e80941Smrg bo->cubemap_stride = ALIGN(offset, 64); 224b8e80941Smrg bo->size = ALIGN(bo->cubemap_stride * tmpl->array_size, 4096); 225b8e80941Smrg} 226b8e80941Smrg 227b8e80941Smrgstatic struct panfrost_bo * 228b8e80941Smrgpanfrost_create_bo(struct panfrost_screen *screen, const struct pipe_resource *template) 229b8e80941Smrg{ 230b8e80941Smrg struct panfrost_bo *bo = CALLOC_STRUCT(panfrost_bo); 231b8e80941Smrg pipe_reference_init(&bo->reference, 1); 232b8e80941Smrg 233b8e80941Smrg /* Based on the usage, figure out what storing will be used. There are 234b8e80941Smrg * various tradeoffs: 235b8e80941Smrg * 236b8e80941Smrg * Linear: the basic format, bad for memory bandwidth, bad for cache 237b8e80941Smrg * use. Zero-copy, though. Renderable. 238b8e80941Smrg * 239b8e80941Smrg * Tiled: Not compressed, but cache-optimized. Expensive to write into 240b8e80941Smrg * (due to software tiling), but cheap to sample from. Ideal for most 241b8e80941Smrg * textures. 242b8e80941Smrg * 243b8e80941Smrg * AFBC: Compressed and renderable (so always desirable for non-scanout 244b8e80941Smrg * rendertargets). Cheap to sample from. The format is black box, so we 245b8e80941Smrg * can't read/write from software. 246b8e80941Smrg */ 247b8e80941Smrg 248b8e80941Smrg /* Tiling textures is almost always faster, unless we only use it once */ 249b8e80941Smrg bool should_tile = (template->usage != PIPE_USAGE_STREAM) && (template->bind & PIPE_BIND_SAMPLER_VIEW); 250b8e80941Smrg 251b8e80941Smrg /* For unclear reasons, depth/stencil is faster linear than AFBC, so 252b8e80941Smrg * make sure it's linear */ 253b8e80941Smrg 254b8e80941Smrg if (template->bind & PIPE_BIND_DEPTH_STENCIL) 255b8e80941Smrg should_tile = false; 256b8e80941Smrg 257b8e80941Smrg /* Set the layout appropriately */ 258b8e80941Smrg bo->layout = should_tile ? PAN_TILED : PAN_LINEAR; 259b8e80941Smrg 260b8e80941Smrg panfrost_setup_slices(template, bo); 261b8e80941Smrg 262b8e80941Smrg if (bo->layout == PAN_TILED || bo->layout == PAN_LINEAR) { 263b8e80941Smrg struct panfrost_memory mem; 264b8e80941Smrg 265b8e80941Smrg screen->driver->allocate_slab(screen, &mem, bo->size / 4096, true, 0, 0, 0); 266b8e80941Smrg 267b8e80941Smrg bo->cpu = mem.cpu; 268b8e80941Smrg bo->gpu = mem.gpu; 269b8e80941Smrg bo->gem_handle = mem.gem_handle; 270b8e80941Smrg } 271b8e80941Smrg 272b8e80941Smrg return bo; 273b8e80941Smrg} 274b8e80941Smrg 275b8e80941Smrgstatic struct pipe_resource * 276b8e80941Smrgpanfrost_resource_create(struct pipe_screen *screen, 277b8e80941Smrg const struct pipe_resource *template) 278b8e80941Smrg{ 279b8e80941Smrg struct panfrost_resource *so = CALLOC_STRUCT(panfrost_resource); 280b8e80941Smrg struct panfrost_screen *pscreen = (struct panfrost_screen *) screen; 281b8e80941Smrg 282b8e80941Smrg so->base = *template; 283b8e80941Smrg so->base.screen = screen; 284b8e80941Smrg 285b8e80941Smrg pipe_reference_init(&so->base.reference, 1); 286b8e80941Smrg 287b8e80941Smrg /* Make sure we're familiar */ 288b8e80941Smrg switch (template->target) { 289b8e80941Smrg case PIPE_BUFFER: 290b8e80941Smrg case PIPE_TEXTURE_1D: 291b8e80941Smrg case PIPE_TEXTURE_2D: 292b8e80941Smrg case PIPE_TEXTURE_3D: 293b8e80941Smrg case PIPE_TEXTURE_CUBE: 294b8e80941Smrg case PIPE_TEXTURE_RECT: 295b8e80941Smrg break; 296b8e80941Smrg default: 297b8e80941Smrg DBG("Unknown texture target %d\n", template->target); 298b8e80941Smrg assert(0); 299b8e80941Smrg } 300b8e80941Smrg 301b8e80941Smrg util_range_init(&so->valid_buffer_range); 302b8e80941Smrg 303b8e80941Smrg if (template->bind & PIPE_BIND_DISPLAY_TARGET || 304b8e80941Smrg template->bind & PIPE_BIND_SCANOUT || 305b8e80941Smrg template->bind & PIPE_BIND_SHARED) { 306b8e80941Smrg struct pipe_resource scanout_templat = *template; 307b8e80941Smrg struct renderonly_scanout *scanout; 308b8e80941Smrg struct winsys_handle handle; 309b8e80941Smrg 310b8e80941Smrg scanout = renderonly_scanout_for_resource(&scanout_templat, 311b8e80941Smrg pscreen->ro, &handle); 312b8e80941Smrg if (!scanout) 313b8e80941Smrg return NULL; 314b8e80941Smrg 315b8e80941Smrg assert(handle.type == WINSYS_HANDLE_TYPE_FD); 316b8e80941Smrg /* TODO: handle modifiers? */ 317b8e80941Smrg so = pan_resource(screen->resource_from_handle(screen, template, 318b8e80941Smrg &handle, 319b8e80941Smrg PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)); 320b8e80941Smrg close(handle.handle); 321b8e80941Smrg if (!so) 322b8e80941Smrg return NULL; 323b8e80941Smrg 324b8e80941Smrg so->scanout = scanout; 325b8e80941Smrg pscreen->display_target = so; 326b8e80941Smrg } else { 327b8e80941Smrg so->bo = panfrost_create_bo(pscreen, template); 328b8e80941Smrg } 329b8e80941Smrg 330b8e80941Smrg return (struct pipe_resource *)so; 331b8e80941Smrg} 332b8e80941Smrg 333b8e80941Smrgstatic void 334b8e80941Smrgpanfrost_destroy_bo(struct panfrost_screen *screen, struct panfrost_bo *pbo) 335b8e80941Smrg{ 336b8e80941Smrg struct panfrost_bo *bo = (struct panfrost_bo *)pbo; 337b8e80941Smrg 338b8e80941Smrg if ((bo->layout == PAN_LINEAR || bo->layout == PAN_TILED) && 339b8e80941Smrg !bo->imported) { 340b8e80941Smrg struct panfrost_memory mem = { 341b8e80941Smrg .cpu = bo->cpu, 342b8e80941Smrg .gpu = bo->gpu, 343b8e80941Smrg .size = bo->size, 344b8e80941Smrg .gem_handle = bo->gem_handle, 345b8e80941Smrg }; 346b8e80941Smrg 347b8e80941Smrg screen->driver->free_slab(screen, &mem); 348b8e80941Smrg } 349b8e80941Smrg 350b8e80941Smrg if (bo->layout == PAN_AFBC) { 351b8e80941Smrg /* TODO */ 352b8e80941Smrg DBG("--leaking afbc (%d bytes)--\n", bo->afbc_metadata_size); 353b8e80941Smrg } 354b8e80941Smrg 355b8e80941Smrg if (bo->has_checksum) { 356b8e80941Smrg /* TODO */ 357b8e80941Smrg DBG("--leaking checksum (%zd bytes)--\n", bo->checksum_slab.size); 358b8e80941Smrg } 359b8e80941Smrg 360b8e80941Smrg if (bo->imported) { 361b8e80941Smrg screen->driver->free_imported_bo(screen, bo); 362b8e80941Smrg } 363b8e80941Smrg} 364b8e80941Smrg 365b8e80941Smrgvoid 366b8e80941Smrgpanfrost_bo_reference(struct panfrost_bo *bo) 367b8e80941Smrg{ 368b8e80941Smrg pipe_reference(NULL, &bo->reference); 369b8e80941Smrg} 370b8e80941Smrg 371b8e80941Smrgvoid 372b8e80941Smrgpanfrost_bo_unreference(struct pipe_screen *screen, struct panfrost_bo *bo) 373b8e80941Smrg{ 374b8e80941Smrg /* When the reference count goes to zero, we need to cleanup */ 375b8e80941Smrg 376b8e80941Smrg if (pipe_reference(&bo->reference, NULL)) { 377b8e80941Smrg panfrost_destroy_bo(pan_screen(screen), bo); 378b8e80941Smrg } 379b8e80941Smrg} 380b8e80941Smrg 381b8e80941Smrgstatic void 382b8e80941Smrgpanfrost_resource_destroy(struct pipe_screen *screen, 383b8e80941Smrg struct pipe_resource *pt) 384b8e80941Smrg{ 385b8e80941Smrg struct panfrost_screen *pscreen = pan_screen(screen); 386b8e80941Smrg struct panfrost_resource *rsrc = (struct panfrost_resource *) pt; 387b8e80941Smrg 388b8e80941Smrg if (rsrc->scanout) 389b8e80941Smrg renderonly_scanout_destroy(rsrc->scanout, pscreen->ro); 390b8e80941Smrg 391b8e80941Smrg if (rsrc->bo) 392b8e80941Smrg panfrost_bo_unreference(screen, rsrc->bo); 393b8e80941Smrg 394b8e80941Smrg util_range_destroy(&rsrc->valid_buffer_range); 395b8e80941Smrg FREE(rsrc); 396b8e80941Smrg} 397b8e80941Smrg 398b8e80941Smrgstatic void * 399b8e80941Smrgpanfrost_transfer_map(struct pipe_context *pctx, 400b8e80941Smrg struct pipe_resource *resource, 401b8e80941Smrg unsigned level, 402b8e80941Smrg unsigned usage, /* a combination of PIPE_TRANSFER_x */ 403b8e80941Smrg const struct pipe_box *box, 404b8e80941Smrg struct pipe_transfer **out_transfer) 405b8e80941Smrg{ 406b8e80941Smrg int bytes_per_pixel = util_format_get_blocksize(resource->format); 407b8e80941Smrg struct panfrost_resource *rsrc = pan_resource(resource); 408b8e80941Smrg struct panfrost_bo *bo = rsrc->bo; 409b8e80941Smrg 410b8e80941Smrg struct panfrost_gtransfer *transfer = CALLOC_STRUCT(panfrost_gtransfer); 411b8e80941Smrg transfer->base.level = level; 412b8e80941Smrg transfer->base.usage = usage; 413b8e80941Smrg transfer->base.box = *box; 414b8e80941Smrg 415b8e80941Smrg pipe_resource_reference(&transfer->base.resource, resource); 416b8e80941Smrg 417b8e80941Smrg *out_transfer = &transfer->base; 418b8e80941Smrg 419b8e80941Smrg /* Check if we're bound for rendering and this is a read pixels. If so, 420b8e80941Smrg * we need to flush */ 421b8e80941Smrg 422b8e80941Smrg struct panfrost_context *ctx = pan_context(pctx); 423b8e80941Smrg struct pipe_framebuffer_state *fb = &ctx->pipe_framebuffer; 424b8e80941Smrg 425b8e80941Smrg bool is_bound = false; 426b8e80941Smrg 427b8e80941Smrg for (unsigned c = 0; c < fb->nr_cbufs; ++c) { 428b8e80941Smrg is_bound |= fb->cbufs[c]->texture == resource; 429b8e80941Smrg } 430b8e80941Smrg 431b8e80941Smrg if (is_bound && (usage & PIPE_TRANSFER_READ)) { 432b8e80941Smrg assert(level == 0); 433b8e80941Smrg panfrost_flush(pctx, NULL, PIPE_FLUSH_END_OF_FRAME); 434b8e80941Smrg } 435b8e80941Smrg 436b8e80941Smrg /* TODO: Respect usage flags */ 437b8e80941Smrg 438b8e80941Smrg if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) { 439b8e80941Smrg /* TODO: reallocate */ 440b8e80941Smrg //printf("debug: Missed reallocate\n"); 441b8e80941Smrg } else if ((usage & PIPE_TRANSFER_WRITE) 442b8e80941Smrg && resource->target == PIPE_BUFFER 443b8e80941Smrg && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) { 444b8e80941Smrg /* No flush for writes to uninitialized */ 445b8e80941Smrg } else if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { 446b8e80941Smrg if (usage & PIPE_TRANSFER_WRITE) { 447b8e80941Smrg /* STUB: flush reading */ 448b8e80941Smrg //printf("debug: missed reading flush %d\n", resource->target); 449b8e80941Smrg } else if (usage & PIPE_TRANSFER_READ) { 450b8e80941Smrg /* STUB: flush writing */ 451b8e80941Smrg //printf("debug: missed writing flush %d (%d-%d)\n", resource->target, box->x, box->x + box->width); 452b8e80941Smrg } else { 453b8e80941Smrg /* Why are you even mapping?! */ 454b8e80941Smrg } 455b8e80941Smrg } 456b8e80941Smrg 457b8e80941Smrg if (bo->layout != PAN_LINEAR) { 458b8e80941Smrg /* Non-linear resources need to be indirectly mapped */ 459b8e80941Smrg 460b8e80941Smrg if (usage & PIPE_TRANSFER_MAP_DIRECTLY) 461b8e80941Smrg return NULL; 462b8e80941Smrg 463b8e80941Smrg transfer->base.stride = box->width * bytes_per_pixel; 464b8e80941Smrg transfer->base.layer_stride = transfer->base.stride * box->height; 465b8e80941Smrg 466b8e80941Smrg /* TODO: Reads */ 467b8e80941Smrg transfer->map = malloc(transfer->base.layer_stride * box->depth); 468b8e80941Smrg 469b8e80941Smrg return transfer->map; 470b8e80941Smrg } else { 471b8e80941Smrg transfer->base.stride = bo->slices[level].stride; 472b8e80941Smrg transfer->base.layer_stride = bo->cubemap_stride; 473b8e80941Smrg 474b8e80941Smrg return bo->cpu 475b8e80941Smrg + bo->slices[level].offset 476b8e80941Smrg + transfer->base.box.z * bo->cubemap_stride 477b8e80941Smrg + transfer->base.box.y * bo->slices[level].stride 478b8e80941Smrg + transfer->base.box.x * bytes_per_pixel; 479b8e80941Smrg } 480b8e80941Smrg} 481b8e80941Smrg 482b8e80941Smrgstatic void 483b8e80941Smrgpanfrost_tile_texture(struct panfrost_screen *screen, struct panfrost_resource *rsrc, struct panfrost_gtransfer *trans) 484b8e80941Smrg{ 485b8e80941Smrg struct panfrost_bo *bo = (struct panfrost_bo *)rsrc->bo; 486b8e80941Smrg 487b8e80941Smrg unsigned level = trans->base.level; 488b8e80941Smrg 489b8e80941Smrg panfrost_texture_swizzle( 490b8e80941Smrg trans->base.box.x, 491b8e80941Smrg trans->base.box.y, 492b8e80941Smrg trans->base.box.width, 493b8e80941Smrg trans->base.box.height, 494b8e80941Smrg util_format_get_blocksize(rsrc->base.format), 495b8e80941Smrg u_minify(rsrc->base.width0, level), 496b8e80941Smrg trans->map, 497b8e80941Smrg bo->cpu 498b8e80941Smrg + bo->slices[level].offset 499b8e80941Smrg + bo->cubemap_stride * trans->base.box.z 500b8e80941Smrg ); 501b8e80941Smrg} 502b8e80941Smrg 503b8e80941Smrgstatic void 504b8e80941Smrgpanfrost_transfer_unmap(struct pipe_context *pctx, 505b8e80941Smrg struct pipe_transfer *transfer) 506b8e80941Smrg{ 507b8e80941Smrg struct panfrost_context *ctx = pan_context(pctx); 508b8e80941Smrg 509b8e80941Smrg /* Gallium expects writeback here, so we tile */ 510b8e80941Smrg 511b8e80941Smrg struct panfrost_gtransfer *trans = pan_transfer(transfer); 512b8e80941Smrg struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource; 513b8e80941Smrg 514b8e80941Smrg if (trans->map) { 515b8e80941Smrg struct panfrost_bo *bo = prsrc->bo; 516b8e80941Smrg 517b8e80941Smrg if (transfer->usage & PIPE_TRANSFER_WRITE) { 518b8e80941Smrg 519b8e80941Smrg if (bo->layout == PAN_AFBC) { 520b8e80941Smrg DBG("Unimplemented: writes to AFBC\n"); 521b8e80941Smrg } else if (bo->layout == PAN_TILED) { 522b8e80941Smrg struct pipe_context *gallium = (struct pipe_context *) ctx; 523b8e80941Smrg struct panfrost_screen *screen = pan_screen(gallium->screen); 524b8e80941Smrg assert(transfer->box.depth == 1); 525b8e80941Smrg panfrost_tile_texture(screen, prsrc, trans); 526b8e80941Smrg } 527b8e80941Smrg } 528b8e80941Smrg 529b8e80941Smrg free(trans->map); 530b8e80941Smrg } 531b8e80941Smrg 532b8e80941Smrg 533b8e80941Smrg util_range_add(&prsrc->valid_buffer_range, 534b8e80941Smrg transfer->box.x, 535b8e80941Smrg transfer->box.x + transfer->box.width); 536b8e80941Smrg 537b8e80941Smrg /* Derefence the resource */ 538b8e80941Smrg pipe_resource_reference(&transfer->resource, NULL); 539b8e80941Smrg 540b8e80941Smrg /* Transfer itself is CALLOCed at the moment */ 541b8e80941Smrg free(transfer); 542b8e80941Smrg} 543b8e80941Smrg 544b8e80941Smrgstatic void 545b8e80941Smrgpanfrost_transfer_flush_region(struct pipe_context *pctx, 546b8e80941Smrg struct pipe_transfer *transfer, 547b8e80941Smrg const struct pipe_box *box) 548b8e80941Smrg{ 549b8e80941Smrg struct panfrost_resource *rsc = pan_resource(transfer->resource); 550b8e80941Smrg 551b8e80941Smrg if (transfer->resource->target == PIPE_BUFFER) { 552b8e80941Smrg util_range_add(&rsc->valid_buffer_range, 553b8e80941Smrg transfer->box.x + box->x, 554b8e80941Smrg transfer->box.x + box->x + box->width); 555b8e80941Smrg } 556b8e80941Smrg} 557b8e80941Smrg 558b8e80941Smrgstatic struct pb_slab * 559b8e80941Smrgpanfrost_slab_alloc(void *priv, unsigned heap, unsigned entry_size, unsigned group_index) 560b8e80941Smrg{ 561b8e80941Smrg struct panfrost_screen *screen = (struct panfrost_screen *) priv; 562b8e80941Smrg struct panfrost_memory *mem = CALLOC_STRUCT(panfrost_memory); 563b8e80941Smrg 564b8e80941Smrg size_t slab_size = (1 << (MAX_SLAB_ENTRY_SIZE + 1)); 565b8e80941Smrg 566b8e80941Smrg mem->slab.num_entries = slab_size / entry_size; 567b8e80941Smrg mem->slab.num_free = mem->slab.num_entries; 568b8e80941Smrg 569b8e80941Smrg LIST_INITHEAD(&mem->slab.free); 570b8e80941Smrg for (unsigned i = 0; i < mem->slab.num_entries; ++i) { 571b8e80941Smrg /* Create a slab entry */ 572b8e80941Smrg struct panfrost_memory_entry *entry = CALLOC_STRUCT(panfrost_memory_entry); 573b8e80941Smrg entry->offset = entry_size * i; 574b8e80941Smrg 575b8e80941Smrg entry->base.slab = &mem->slab; 576b8e80941Smrg entry->base.group_index = group_index; 577b8e80941Smrg 578b8e80941Smrg LIST_ADDTAIL(&entry->base.head, &mem->slab.free); 579b8e80941Smrg } 580b8e80941Smrg 581b8e80941Smrg /* Actually allocate the memory from kernel-space. Mapped, same_va, no 582b8e80941Smrg * special flags */ 583b8e80941Smrg 584b8e80941Smrg screen->driver->allocate_slab(screen, mem, slab_size / 4096, true, 0, 0, 0); 585b8e80941Smrg 586b8e80941Smrg return &mem->slab; 587b8e80941Smrg} 588b8e80941Smrg 589b8e80941Smrgstatic bool 590b8e80941Smrgpanfrost_slab_can_reclaim(void *priv, struct pb_slab_entry *entry) 591b8e80941Smrg{ 592b8e80941Smrg struct panfrost_memory_entry *p_entry = (struct panfrost_memory_entry *) entry; 593b8e80941Smrg return p_entry->freed; 594b8e80941Smrg} 595b8e80941Smrg 596b8e80941Smrgstatic void 597b8e80941Smrgpanfrost_slab_free(void *priv, struct pb_slab *slab) 598b8e80941Smrg{ 599b8e80941Smrg struct panfrost_memory *mem = (struct panfrost_memory *) slab; 600b8e80941Smrg struct panfrost_screen *screen = (struct panfrost_screen *) priv; 601b8e80941Smrg 602b8e80941Smrg screen->driver->free_slab(screen, mem); 603b8e80941Smrg} 604b8e80941Smrg 605b8e80941Smrgstatic void 606b8e80941Smrgpanfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 607b8e80941Smrg{ 608b8e80941Smrg //DBG("TODO %s\n", __func__); 609b8e80941Smrg} 610b8e80941Smrg 611b8e80941Smrgstatic enum pipe_format 612b8e80941Smrgpanfrost_resource_get_internal_format(struct pipe_resource *prsrc) 613b8e80941Smrg{ 614b8e80941Smrg return prsrc->format; 615b8e80941Smrg} 616b8e80941Smrg 617b8e80941Smrgstatic void 618b8e80941Smrgpanfrost_resource_set_stencil(struct pipe_resource *prsrc, 619b8e80941Smrg struct pipe_resource *stencil) 620b8e80941Smrg{ 621b8e80941Smrg pan_resource(prsrc)->separate_stencil = pan_resource(stencil); 622b8e80941Smrg} 623b8e80941Smrg 624b8e80941Smrgstatic struct pipe_resource * 625b8e80941Smrgpanfrost_resource_get_stencil(struct pipe_resource *prsrc) 626b8e80941Smrg{ 627b8e80941Smrg return &pan_resource(prsrc)->separate_stencil->base; 628b8e80941Smrg} 629b8e80941Smrg 630b8e80941Smrgstatic const struct u_transfer_vtbl transfer_vtbl = { 631b8e80941Smrg .resource_create = panfrost_resource_create, 632b8e80941Smrg .resource_destroy = panfrost_resource_destroy, 633b8e80941Smrg .transfer_map = panfrost_transfer_map, 634b8e80941Smrg .transfer_unmap = panfrost_transfer_unmap, 635b8e80941Smrg .transfer_flush_region = panfrost_transfer_flush_region, 636b8e80941Smrg .get_internal_format = panfrost_resource_get_internal_format, 637b8e80941Smrg .set_stencil = panfrost_resource_set_stencil, 638b8e80941Smrg .get_stencil = panfrost_resource_get_stencil, 639b8e80941Smrg}; 640b8e80941Smrg 641b8e80941Smrgvoid 642b8e80941Smrgpanfrost_resource_screen_init(struct panfrost_screen *pscreen) 643b8e80941Smrg{ 644b8e80941Smrg //pscreen->base.resource_create_with_modifiers = 645b8e80941Smrg // panfrost_resource_create_with_modifiers; 646b8e80941Smrg pscreen->base.resource_create = u_transfer_helper_resource_create; 647b8e80941Smrg pscreen->base.resource_destroy = u_transfer_helper_resource_destroy; 648b8e80941Smrg pscreen->base.resource_from_handle = panfrost_resource_from_handle; 649b8e80941Smrg pscreen->base.resource_get_handle = panfrost_resource_get_handle; 650b8e80941Smrg pscreen->base.transfer_helper = u_transfer_helper_create(&transfer_vtbl, 651b8e80941Smrg true, false, 652b8e80941Smrg true, true); 653b8e80941Smrg 654b8e80941Smrg pb_slabs_init(&pscreen->slabs, 655b8e80941Smrg MIN_SLAB_ENTRY_SIZE, 656b8e80941Smrg MAX_SLAB_ENTRY_SIZE, 657b8e80941Smrg 658b8e80941Smrg 3, /* Number of heaps */ 659b8e80941Smrg 660b8e80941Smrg pscreen, 661b8e80941Smrg 662b8e80941Smrg panfrost_slab_can_reclaim, 663b8e80941Smrg panfrost_slab_alloc, 664b8e80941Smrg panfrost_slab_free); 665b8e80941Smrg} 666b8e80941Smrg 667b8e80941Smrgvoid 668b8e80941Smrgpanfrost_resource_context_init(struct pipe_context *pctx) 669b8e80941Smrg{ 670b8e80941Smrg pctx->transfer_map = u_transfer_helper_transfer_map; 671b8e80941Smrg pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 672b8e80941Smrg pctx->transfer_unmap = u_transfer_helper_transfer_unmap; 673b8e80941Smrg pctx->buffer_subdata = u_default_buffer_subdata; 674b8e80941Smrg pctx->create_surface = panfrost_create_surface; 675b8e80941Smrg pctx->surface_destroy = panfrost_surface_destroy; 676b8e80941Smrg pctx->resource_copy_region = util_resource_copy_region; 677b8e80941Smrg pctx->blit = panfrost_blit; 678b8e80941Smrg pctx->flush_resource = panfrost_flush_resource; 679b8e80941Smrg pctx->invalidate_resource = panfrost_invalidate_resource; 680b8e80941Smrg pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 681b8e80941Smrg pctx->buffer_subdata = u_default_buffer_subdata; 682b8e80941Smrg pctx->texture_subdata = u_default_texture_subdata; 683b8e80941Smrg} 684