1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2008 VMware, Inc. 3bf215546Sopenharmony_ci * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 4bf215546Sopenharmony_ci * Copyright (C) 2014-2017 Broadcom 5bf215546Sopenharmony_ci * Copyright (C) 2018-2019 Alyssa Rosenzweig 6bf215546Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd. 7bf215546Sopenharmony_ci * 8bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 9bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 10bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 11bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 13bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 16bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 17bf215546Sopenharmony_ci * Software. 18bf215546Sopenharmony_ci * 19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25bf215546Sopenharmony_ci * SOFTWARE. 26bf215546Sopenharmony_ci * 27bf215546Sopenharmony_ci * Authors (Collabora): 28bf215546Sopenharmony_ci * Tomeu Vizoso <tomeu.vizoso@collabora.com> 29bf215546Sopenharmony_ci * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com> 30bf215546Sopenharmony_ci * 31bf215546Sopenharmony_ci */ 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include <xf86drm.h> 34bf215546Sopenharmony_ci#include <fcntl.h> 35bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci#include "frontend/winsys_handle.h" 38bf215546Sopenharmony_ci#include "util/format/u_format.h" 39bf215546Sopenharmony_ci#include "util/u_memory.h" 40bf215546Sopenharmony_ci#include "util/u_surface.h" 41bf215546Sopenharmony_ci#include "util/u_transfer.h" 42bf215546Sopenharmony_ci#include "util/u_transfer_helper.h" 43bf215546Sopenharmony_ci#include "util/u_gen_mipmap.h" 44bf215546Sopenharmony_ci#include "util/u_drm.h" 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#include "pan_bo.h" 47bf215546Sopenharmony_ci#include "pan_context.h" 48bf215546Sopenharmony_ci#include "pan_screen.h" 49bf215546Sopenharmony_ci#include "pan_resource.h" 50bf215546Sopenharmony_ci#include "pan_util.h" 51bf215546Sopenharmony_ci#include "pan_tiling.h" 52bf215546Sopenharmony_ci#include "decode.h" 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic bool 55bf215546Sopenharmony_cipanfrost_should_checksum(const struct panfrost_device *dev, const struct panfrost_resource *pres); 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_cistatic struct pipe_resource * 58bf215546Sopenharmony_cipanfrost_resource_from_handle(struct pipe_screen *pscreen, 59bf215546Sopenharmony_ci const struct pipe_resource *templat, 60bf215546Sopenharmony_ci struct winsys_handle *whandle, 61bf215546Sopenharmony_ci unsigned usage) 62bf215546Sopenharmony_ci{ 63bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(pscreen); 64bf215546Sopenharmony_ci struct panfrost_resource *rsc; 65bf215546Sopenharmony_ci struct pipe_resource *prsc; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci assert(whandle->type == WINSYS_HANDLE_TYPE_FD); 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci rsc = CALLOC_STRUCT(panfrost_resource); 70bf215546Sopenharmony_ci if (!rsc) 71bf215546Sopenharmony_ci return NULL; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci prsc = &rsc->base; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci *prsc = *templat; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci pipe_reference_init(&prsc->reference, 1); 78bf215546Sopenharmony_ci prsc->screen = pscreen; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci uint64_t mod = whandle->modifier == DRM_FORMAT_MOD_INVALID ? 81bf215546Sopenharmony_ci DRM_FORMAT_MOD_LINEAR : whandle->modifier; 82bf215546Sopenharmony_ci enum mali_texture_dimension dim = 83bf215546Sopenharmony_ci panfrost_translate_texture_dimension(templat->target); 84bf215546Sopenharmony_ci enum pan_image_crc_mode crc_mode = 85bf215546Sopenharmony_ci panfrost_should_checksum(dev, rsc) ? 86bf215546Sopenharmony_ci PAN_IMAGE_CRC_OOB : PAN_IMAGE_CRC_NONE; 87bf215546Sopenharmony_ci struct pan_image_explicit_layout explicit_layout = { 88bf215546Sopenharmony_ci .offset = whandle->offset, 89bf215546Sopenharmony_ci .row_stride = panfrost_from_legacy_stride(whandle->stride, templat->format, mod) 90bf215546Sopenharmony_ci }; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci rsc->image.layout = (struct pan_image_layout) { 93bf215546Sopenharmony_ci .modifier = mod, 94bf215546Sopenharmony_ci .format = templat->format, 95bf215546Sopenharmony_ci .dim = dim, 96bf215546Sopenharmony_ci .width = prsc->width0, 97bf215546Sopenharmony_ci .height = prsc->height0, 98bf215546Sopenharmony_ci .depth = prsc->depth0, 99bf215546Sopenharmony_ci .array_size = prsc->array_size, 100bf215546Sopenharmony_ci .nr_samples = MAX2(prsc->nr_samples, 1), 101bf215546Sopenharmony_ci .nr_slices = 1, 102bf215546Sopenharmony_ci .crc_mode = crc_mode 103bf215546Sopenharmony_ci }; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci bool valid = pan_image_layout_init(&rsc->image.layout, &explicit_layout); 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_ci if (!valid) { 108bf215546Sopenharmony_ci FREE(rsc); 109bf215546Sopenharmony_ci return NULL; 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci rsc->image.data.bo = panfrost_bo_import(dev, whandle->handle); 113bf215546Sopenharmony_ci /* Sometimes an import can fail e.g. on an invalid buffer fd, out of 114bf215546Sopenharmony_ci * memory space to mmap it etc. 115bf215546Sopenharmony_ci */ 116bf215546Sopenharmony_ci if (!rsc->image.data.bo) { 117bf215546Sopenharmony_ci FREE(rsc); 118bf215546Sopenharmony_ci return NULL; 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci if (rsc->image.layout.crc_mode == PAN_IMAGE_CRC_OOB) 121bf215546Sopenharmony_ci rsc->image.crc.bo = panfrost_bo_create(dev, rsc->image.layout.crc_size, 0, "CRC data"); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci rsc->modifier_constant = true; 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci BITSET_SET(rsc->valid.data, 0); 126bf215546Sopenharmony_ci panfrost_resource_set_damage_region(pscreen, &rsc->base, 0, NULL); 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci if (dev->ro) { 129bf215546Sopenharmony_ci rsc->scanout = 130bf215546Sopenharmony_ci renderonly_create_gpu_import_for_resource(prsc, dev->ro, NULL); 131bf215546Sopenharmony_ci /* failure is expected in some cases.. */ 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci return prsc; 135bf215546Sopenharmony_ci} 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_cistatic bool 138bf215546Sopenharmony_cipanfrost_resource_get_handle(struct pipe_screen *pscreen, 139bf215546Sopenharmony_ci struct pipe_context *ctx, 140bf215546Sopenharmony_ci struct pipe_resource *pt, 141bf215546Sopenharmony_ci struct winsys_handle *handle, 142bf215546Sopenharmony_ci unsigned usage) 143bf215546Sopenharmony_ci{ 144bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(pscreen); 145bf215546Sopenharmony_ci struct panfrost_resource *rsrc; 146bf215546Sopenharmony_ci struct renderonly_scanout *scanout; 147bf215546Sopenharmony_ci struct pipe_resource *cur = pt; 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci /* Even though panfrost doesn't support multi-planar formats, we 150bf215546Sopenharmony_ci * can get here through GBM, which does. Walk the list of planes 151bf215546Sopenharmony_ci * to find the right one. 152bf215546Sopenharmony_ci */ 153bf215546Sopenharmony_ci for (int i = 0; i < handle->plane; i++) { 154bf215546Sopenharmony_ci cur = cur->next; 155bf215546Sopenharmony_ci if (!cur) 156bf215546Sopenharmony_ci return false; 157bf215546Sopenharmony_ci } 158bf215546Sopenharmony_ci rsrc = pan_resource(cur); 159bf215546Sopenharmony_ci scanout = rsrc->scanout; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci handle->modifier = rsrc->image.layout.modifier; 162bf215546Sopenharmony_ci rsrc->modifier_constant = true; 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci if (handle->type == WINSYS_HANDLE_TYPE_KMS && dev->ro) { 165bf215546Sopenharmony_ci return renderonly_get_handle(scanout, handle); 166bf215546Sopenharmony_ci } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) { 167bf215546Sopenharmony_ci handle->handle = rsrc->image.data.bo->gem_handle; 168bf215546Sopenharmony_ci } else if (handle->type == WINSYS_HANDLE_TYPE_FD) { 169bf215546Sopenharmony_ci int fd = panfrost_bo_export(rsrc->image.data.bo); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (fd < 0) 172bf215546Sopenharmony_ci return false; 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci handle->handle = fd; 175bf215546Sopenharmony_ci } else { 176bf215546Sopenharmony_ci /* Other handle types not supported */ 177bf215546Sopenharmony_ci return false; 178bf215546Sopenharmony_ci } 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci handle->stride = panfrost_get_legacy_stride(&rsrc->image.layout, 0); 181bf215546Sopenharmony_ci handle->offset = rsrc->image.layout.slices[0].offset; 182bf215546Sopenharmony_ci return true; 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_cistatic bool 186bf215546Sopenharmony_cipanfrost_resource_get_param(struct pipe_screen *pscreen, 187bf215546Sopenharmony_ci struct pipe_context *pctx, struct pipe_resource *prsc, 188bf215546Sopenharmony_ci unsigned plane, unsigned layer, unsigned level, 189bf215546Sopenharmony_ci enum pipe_resource_param param, 190bf215546Sopenharmony_ci unsigned usage, uint64_t *value) 191bf215546Sopenharmony_ci{ 192bf215546Sopenharmony_ci struct panfrost_resource *rsrc = (struct panfrost_resource *) prsc; 193bf215546Sopenharmony_ci struct pipe_resource *cur; 194bf215546Sopenharmony_ci unsigned count; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci switch (param) { 197bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_STRIDE: 198bf215546Sopenharmony_ci *value = panfrost_get_legacy_stride(&rsrc->image.layout, level); 199bf215546Sopenharmony_ci return true; 200bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_OFFSET: 201bf215546Sopenharmony_ci *value = rsrc->image.layout.slices[level].offset; 202bf215546Sopenharmony_ci return true; 203bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_MODIFIER: 204bf215546Sopenharmony_ci *value = rsrc->image.layout.modifier; 205bf215546Sopenharmony_ci return true; 206bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_NPLANES: 207bf215546Sopenharmony_ci /* Panfrost doesn't directly support multi-planar formats, 208bf215546Sopenharmony_ci * but we should still handle this case for gbm users 209bf215546Sopenharmony_ci * that might want to use resources shared with panfrost 210bf215546Sopenharmony_ci * on video processing hardware that does. 211bf215546Sopenharmony_ci */ 212bf215546Sopenharmony_ci for (count = 0, cur = prsc; cur; cur = cur->next) 213bf215546Sopenharmony_ci count++; 214bf215546Sopenharmony_ci *value = count; 215bf215546Sopenharmony_ci return true; 216bf215546Sopenharmony_ci default: 217bf215546Sopenharmony_ci return false; 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci} 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_cistatic void 222bf215546Sopenharmony_cipanfrost_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) 223bf215546Sopenharmony_ci{ 224bf215546Sopenharmony_ci /* TODO */ 225bf215546Sopenharmony_ci} 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_cistatic struct pipe_surface * 228bf215546Sopenharmony_cipanfrost_create_surface(struct pipe_context *pipe, 229bf215546Sopenharmony_ci struct pipe_resource *pt, 230bf215546Sopenharmony_ci const struct pipe_surface *surf_tmpl) 231bf215546Sopenharmony_ci{ 232bf215546Sopenharmony_ci struct panfrost_context *ctx = pan_context(pipe); 233bf215546Sopenharmony_ci struct pipe_surface *ps = NULL; 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci pan_legalize_afbc_format(ctx, pan_resource(pt), surf_tmpl->format); 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci ps = CALLOC_STRUCT(pipe_surface); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci if (ps) { 240bf215546Sopenharmony_ci pipe_reference_init(&ps->reference, 1); 241bf215546Sopenharmony_ci pipe_resource_reference(&ps->texture, pt); 242bf215546Sopenharmony_ci ps->context = pipe; 243bf215546Sopenharmony_ci ps->format = surf_tmpl->format; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci if (pt->target != PIPE_BUFFER) { 246bf215546Sopenharmony_ci assert(surf_tmpl->u.tex.level <= pt->last_level); 247bf215546Sopenharmony_ci ps->width = u_minify(pt->width0, surf_tmpl->u.tex.level); 248bf215546Sopenharmony_ci ps->height = u_minify(pt->height0, surf_tmpl->u.tex.level); 249bf215546Sopenharmony_ci ps->nr_samples = surf_tmpl->nr_samples; 250bf215546Sopenharmony_ci ps->u.tex.level = surf_tmpl->u.tex.level; 251bf215546Sopenharmony_ci ps->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 252bf215546Sopenharmony_ci ps->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 253bf215546Sopenharmony_ci } else { 254bf215546Sopenharmony_ci /* setting width as number of elements should get us correct renderbuffer width */ 255bf215546Sopenharmony_ci ps->width = surf_tmpl->u.buf.last_element - surf_tmpl->u.buf.first_element + 1; 256bf215546Sopenharmony_ci ps->height = pt->height0; 257bf215546Sopenharmony_ci ps->u.buf.first_element = surf_tmpl->u.buf.first_element; 258bf215546Sopenharmony_ci ps->u.buf.last_element = surf_tmpl->u.buf.last_element; 259bf215546Sopenharmony_ci assert(ps->u.buf.first_element <= ps->u.buf.last_element); 260bf215546Sopenharmony_ci assert(ps->u.buf.last_element < ps->width); 261bf215546Sopenharmony_ci } 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci return ps; 265bf215546Sopenharmony_ci} 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_cistatic void 268bf215546Sopenharmony_cipanfrost_surface_destroy(struct pipe_context *pipe, 269bf215546Sopenharmony_ci struct pipe_surface *surf) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci assert(surf->texture); 272bf215546Sopenharmony_ci pipe_resource_reference(&surf->texture, NULL); 273bf215546Sopenharmony_ci free(surf); 274bf215546Sopenharmony_ci} 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_cistatic inline bool 277bf215546Sopenharmony_cipanfrost_is_2d(const struct panfrost_resource *pres) 278bf215546Sopenharmony_ci{ 279bf215546Sopenharmony_ci return (pres->base.target == PIPE_TEXTURE_2D) 280bf215546Sopenharmony_ci || (pres->base.target == PIPE_TEXTURE_RECT); 281bf215546Sopenharmony_ci} 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci/* Based on the usage, determine if it makes sense to use u-inteleaved tiling. 284bf215546Sopenharmony_ci * We only have routines to tile 2D textures of sane bpps. On the hardware 285bf215546Sopenharmony_ci * level, not all usages are valid for tiling. Finally, if the app is hinting 286bf215546Sopenharmony_ci * that the contents frequently change, tiling will be a loss. 287bf215546Sopenharmony_ci * 288bf215546Sopenharmony_ci * On platforms where it is supported, AFBC is even better. */ 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_cistatic bool 291bf215546Sopenharmony_cipanfrost_should_afbc(struct panfrost_device *dev, 292bf215546Sopenharmony_ci const struct panfrost_resource *pres, 293bf215546Sopenharmony_ci enum pipe_format fmt) 294bf215546Sopenharmony_ci{ 295bf215546Sopenharmony_ci /* AFBC resources may be rendered to, textured from, or shared across 296bf215546Sopenharmony_ci * processes, but may not be used as e.g buffers */ 297bf215546Sopenharmony_ci const unsigned valid_binding = 298bf215546Sopenharmony_ci PIPE_BIND_DEPTH_STENCIL | 299bf215546Sopenharmony_ci PIPE_BIND_RENDER_TARGET | 300bf215546Sopenharmony_ci PIPE_BIND_BLENDABLE | 301bf215546Sopenharmony_ci PIPE_BIND_SAMPLER_VIEW | 302bf215546Sopenharmony_ci PIPE_BIND_DISPLAY_TARGET | 303bf215546Sopenharmony_ci PIPE_BIND_SCANOUT | 304bf215546Sopenharmony_ci PIPE_BIND_SHARED; 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_ci if (pres->base.bind & ~valid_binding) 307bf215546Sopenharmony_ci return false; 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci /* AFBC support is optional */ 310bf215546Sopenharmony_ci if (!dev->has_afbc) 311bf215546Sopenharmony_ci return false; 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci /* AFBC<-->staging is expensive */ 314bf215546Sopenharmony_ci if (pres->base.usage == PIPE_USAGE_STREAM) 315bf215546Sopenharmony_ci return false; 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci /* Only a small selection of formats are AFBC'able */ 318bf215546Sopenharmony_ci if (!panfrost_format_supports_afbc(dev, fmt)) 319bf215546Sopenharmony_ci return false; 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci /* AFBC does not support layered (GLES3 style) multisampling. Use 322bf215546Sopenharmony_ci * EXT_multisampled_render_to_texture instead */ 323bf215546Sopenharmony_ci if (pres->base.nr_samples > 1) 324bf215546Sopenharmony_ci return false; 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci switch (pres->base.target) { 327bf215546Sopenharmony_ci case PIPE_TEXTURE_2D: 328bf215546Sopenharmony_ci case PIPE_TEXTURE_2D_ARRAY: 329bf215546Sopenharmony_ci case PIPE_TEXTURE_RECT: 330bf215546Sopenharmony_ci break; 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci case PIPE_TEXTURE_3D: 333bf215546Sopenharmony_ci /* 3D AFBC is only supported on Bifrost v7+. It's supposed to 334bf215546Sopenharmony_ci * be supported on Midgard but it doesn't seem to work */ 335bf215546Sopenharmony_ci if (dev->arch != 7) 336bf215546Sopenharmony_ci return false; 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_ci break; 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci default: 341bf215546Sopenharmony_ci return false; 342bf215546Sopenharmony_ci } 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci /* For one tile, AFBC is a loss compared to u-interleaved */ 345bf215546Sopenharmony_ci if (pres->base.width0 <= 16 && pres->base.height0 <= 16) 346bf215546Sopenharmony_ci return false; 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci /* Otherwise, we'd prefer AFBC as it is dramatically more efficient 349bf215546Sopenharmony_ci * than linear or usually even u-interleaved */ 350bf215546Sopenharmony_ci return true; 351bf215546Sopenharmony_ci} 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci/* 354bf215546Sopenharmony_ci * For a resource we want to use AFBC with, should we use AFBC with tiled 355bf215546Sopenharmony_ci * headers? On GPUs that support it, this is believed to be beneficial for 356bf215546Sopenharmony_ci * images that are at least 128x128. 357bf215546Sopenharmony_ci */ 358bf215546Sopenharmony_cistatic bool 359bf215546Sopenharmony_cipanfrost_should_tile_afbc(const struct panfrost_device *dev, 360bf215546Sopenharmony_ci const struct panfrost_resource *pres) 361bf215546Sopenharmony_ci{ 362bf215546Sopenharmony_ci return panfrost_afbc_can_tile(dev) && 363bf215546Sopenharmony_ci pres->base.width0 >= 128 && 364bf215546Sopenharmony_ci pres->base.height0 >= 128; 365bf215546Sopenharmony_ci} 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_cistatic bool 368bf215546Sopenharmony_cipanfrost_should_tile(struct panfrost_device *dev, 369bf215546Sopenharmony_ci const struct panfrost_resource *pres, 370bf215546Sopenharmony_ci enum pipe_format fmt) 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci const unsigned valid_binding = 373bf215546Sopenharmony_ci PIPE_BIND_DEPTH_STENCIL | 374bf215546Sopenharmony_ci PIPE_BIND_RENDER_TARGET | 375bf215546Sopenharmony_ci PIPE_BIND_BLENDABLE | 376bf215546Sopenharmony_ci PIPE_BIND_SAMPLER_VIEW | 377bf215546Sopenharmony_ci PIPE_BIND_DISPLAY_TARGET | 378bf215546Sopenharmony_ci PIPE_BIND_SCANOUT | 379bf215546Sopenharmony_ci PIPE_BIND_SHARED; 380bf215546Sopenharmony_ci 381bf215546Sopenharmony_ci /* The purpose of tiling is improving locality in both X- and 382bf215546Sopenharmony_ci * Y-directions. If there is only a single pixel in either direction, 383bf215546Sopenharmony_ci * tiling does not make sense; using a linear layout instead is optimal 384bf215546Sopenharmony_ci * for both memory usage and performance. 385bf215546Sopenharmony_ci */ 386bf215546Sopenharmony_ci if (MIN2(pres->base.width0, pres->base.height0) < 2) 387bf215546Sopenharmony_ci return false; 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_ci bool can_tile = (pres->base.target != PIPE_BUFFER) 390bf215546Sopenharmony_ci && ((pres->base.bind & ~valid_binding) == 0); 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci return can_tile && (pres->base.usage != PIPE_USAGE_STREAM); 393bf215546Sopenharmony_ci} 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_cistatic uint64_t 396bf215546Sopenharmony_cipanfrost_best_modifier(struct panfrost_device *dev, 397bf215546Sopenharmony_ci const struct panfrost_resource *pres, 398bf215546Sopenharmony_ci enum pipe_format fmt) 399bf215546Sopenharmony_ci{ 400bf215546Sopenharmony_ci /* Force linear textures when debugging tiling/compression */ 401bf215546Sopenharmony_ci if (unlikely(dev->debug & PAN_DBG_LINEAR)) 402bf215546Sopenharmony_ci return DRM_FORMAT_MOD_LINEAR; 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ci if (panfrost_should_afbc(dev, pres, fmt)) { 405bf215546Sopenharmony_ci uint64_t afbc = 406bf215546Sopenharmony_ci AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 407bf215546Sopenharmony_ci AFBC_FORMAT_MOD_SPARSE; 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci if (panfrost_afbc_can_ytr(pres->base.format)) 410bf215546Sopenharmony_ci afbc |= AFBC_FORMAT_MOD_YTR; 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci if (panfrost_should_tile_afbc(dev, pres)) 413bf215546Sopenharmony_ci afbc |= AFBC_FORMAT_MOD_TILED | AFBC_FORMAT_MOD_SC; 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci return DRM_FORMAT_MOD_ARM_AFBC(afbc); 416bf215546Sopenharmony_ci } else if (panfrost_should_tile(dev, pres, fmt)) 417bf215546Sopenharmony_ci return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 418bf215546Sopenharmony_ci else 419bf215546Sopenharmony_ci return DRM_FORMAT_MOD_LINEAR; 420bf215546Sopenharmony_ci} 421bf215546Sopenharmony_ci 422bf215546Sopenharmony_cistatic bool 423bf215546Sopenharmony_cipanfrost_should_checksum(const struct panfrost_device *dev, const struct panfrost_resource *pres) 424bf215546Sopenharmony_ci{ 425bf215546Sopenharmony_ci /* When checksumming is enabled, the tile data must fit in the 426bf215546Sopenharmony_ci * size of the writeback buffer, so don't checksum formats 427bf215546Sopenharmony_ci * that use too much space. */ 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci unsigned bytes_per_pixel_max = (dev->arch == 6) ? 6 : 4; 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci unsigned bytes_per_pixel = MAX2(pres->base.nr_samples, 1) * 432bf215546Sopenharmony_ci util_format_get_blocksize(pres->base.format); 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci return pres->base.bind & PIPE_BIND_RENDER_TARGET && 435bf215546Sopenharmony_ci panfrost_is_2d(pres) && 436bf215546Sopenharmony_ci bytes_per_pixel <= bytes_per_pixel_max && 437bf215546Sopenharmony_ci pres->base.last_level == 0 && 438bf215546Sopenharmony_ci !(dev->debug & PAN_DBG_NO_CRC); 439bf215546Sopenharmony_ci} 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_cistatic void 442bf215546Sopenharmony_cipanfrost_resource_setup(struct panfrost_device *dev, 443bf215546Sopenharmony_ci struct panfrost_resource *pres, 444bf215546Sopenharmony_ci uint64_t modifier, enum pipe_format fmt) 445bf215546Sopenharmony_ci{ 446bf215546Sopenharmony_ci uint64_t chosen_mod = modifier != DRM_FORMAT_MOD_INVALID ? 447bf215546Sopenharmony_ci modifier : panfrost_best_modifier(dev, pres, fmt); 448bf215546Sopenharmony_ci enum pan_image_crc_mode crc_mode = 449bf215546Sopenharmony_ci panfrost_should_checksum(dev, pres) ? 450bf215546Sopenharmony_ci PAN_IMAGE_CRC_INBAND : PAN_IMAGE_CRC_NONE; 451bf215546Sopenharmony_ci enum mali_texture_dimension dim = 452bf215546Sopenharmony_ci panfrost_translate_texture_dimension(pres->base.target); 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci /* We can only switch tiled->linear if the resource isn't already 455bf215546Sopenharmony_ci * linear and if we control the modifier */ 456bf215546Sopenharmony_ci pres->modifier_constant = 457bf215546Sopenharmony_ci !(chosen_mod != DRM_FORMAT_MOD_LINEAR && 458bf215546Sopenharmony_ci modifier == DRM_FORMAT_MOD_INVALID); 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci /* Z32_S8X24 variants are actually stored in 2 planes (one per 461bf215546Sopenharmony_ci * component), we have to adjust the format on the first plane. 462bf215546Sopenharmony_ci */ 463bf215546Sopenharmony_ci if (fmt == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT) 464bf215546Sopenharmony_ci fmt = PIPE_FORMAT_Z32_FLOAT; 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci pres->image.layout = (struct pan_image_layout) { 467bf215546Sopenharmony_ci .modifier = chosen_mod, 468bf215546Sopenharmony_ci .format = fmt, 469bf215546Sopenharmony_ci .dim = dim, 470bf215546Sopenharmony_ci .width = pres->base.width0, 471bf215546Sopenharmony_ci .height = pres->base.height0, 472bf215546Sopenharmony_ci .depth = pres->base.depth0, 473bf215546Sopenharmony_ci .array_size = pres->base.array_size, 474bf215546Sopenharmony_ci .nr_samples = MAX2(pres->base.nr_samples, 1), 475bf215546Sopenharmony_ci .nr_slices = pres->base.last_level + 1, 476bf215546Sopenharmony_ci .crc_mode = crc_mode 477bf215546Sopenharmony_ci }; 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci ASSERTED bool valid = pan_image_layout_init(&pres->image.layout, NULL); 480bf215546Sopenharmony_ci assert(valid); 481bf215546Sopenharmony_ci} 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_cistatic void 484bf215546Sopenharmony_cipanfrost_resource_init_afbc_headers(struct panfrost_resource *pres) 485bf215546Sopenharmony_ci{ 486bf215546Sopenharmony_ci panfrost_bo_mmap(pres->image.data.bo); 487bf215546Sopenharmony_ci 488bf215546Sopenharmony_ci unsigned nr_samples = MAX2(pres->base.nr_samples, 1); 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci for (unsigned i = 0; i < pres->base.array_size; ++i) { 491bf215546Sopenharmony_ci for (unsigned l = 0; l <= pres->base.last_level; ++l) { 492bf215546Sopenharmony_ci struct pan_image_slice_layout *slice = &pres->image.layout.slices[l]; 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci for (unsigned s = 0; s < nr_samples; ++s) { 495bf215546Sopenharmony_ci void *ptr = pres->image.data.bo->ptr.cpu + 496bf215546Sopenharmony_ci (i * pres->image.layout.array_stride) + 497bf215546Sopenharmony_ci slice->offset + 498bf215546Sopenharmony_ci (s * slice->afbc.surface_stride); 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci /* Zero-ed AFBC headers seem to encode a plain 501bf215546Sopenharmony_ci * black. Let's use this pattern to keep the 502bf215546Sopenharmony_ci * initialization simple. 503bf215546Sopenharmony_ci */ 504bf215546Sopenharmony_ci memset(ptr, 0, slice->afbc.header_size); 505bf215546Sopenharmony_ci } 506bf215546Sopenharmony_ci } 507bf215546Sopenharmony_ci } 508bf215546Sopenharmony_ci} 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_civoid 511bf215546Sopenharmony_cipanfrost_resource_set_damage_region(struct pipe_screen *screen, 512bf215546Sopenharmony_ci struct pipe_resource *res, 513bf215546Sopenharmony_ci unsigned int nrects, 514bf215546Sopenharmony_ci const struct pipe_box *rects) 515bf215546Sopenharmony_ci{ 516bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(screen); 517bf215546Sopenharmony_ci struct panfrost_resource *pres = pan_resource(res); 518bf215546Sopenharmony_ci struct pipe_scissor_state *damage_extent = &pres->damage.extent; 519bf215546Sopenharmony_ci unsigned int i; 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_ci /* Partial updates are implemented with a tile enable map only on v5. 522bf215546Sopenharmony_ci * Later architectures have a more efficient method of implementing 523bf215546Sopenharmony_ci * partial updates (frame shaders), while earlier architectures lack 524bf215546Sopenharmony_ci * tile enable maps altogether. 525bf215546Sopenharmony_ci */ 526bf215546Sopenharmony_ci if (dev->arch == 5 && nrects > 1) { 527bf215546Sopenharmony_ci if (!pres->damage.tile_map.data) { 528bf215546Sopenharmony_ci pres->damage.tile_map.stride = 529bf215546Sopenharmony_ci ALIGN_POT(DIV_ROUND_UP(res->width0, 32 * 8), 64); 530bf215546Sopenharmony_ci pres->damage.tile_map.size = 531bf215546Sopenharmony_ci pres->damage.tile_map.stride * 532bf215546Sopenharmony_ci DIV_ROUND_UP(res->height0, 32); 533bf215546Sopenharmony_ci pres->damage.tile_map.data = 534bf215546Sopenharmony_ci malloc(pres->damage.tile_map.size); 535bf215546Sopenharmony_ci } 536bf215546Sopenharmony_ci 537bf215546Sopenharmony_ci memset(pres->damage.tile_map.data, 0, pres->damage.tile_map.size); 538bf215546Sopenharmony_ci pres->damage.tile_map.enable = true; 539bf215546Sopenharmony_ci } else { 540bf215546Sopenharmony_ci pres->damage.tile_map.enable = false; 541bf215546Sopenharmony_ci } 542bf215546Sopenharmony_ci 543bf215546Sopenharmony_ci /* Track the damage extent: the quad including all damage regions. Will 544bf215546Sopenharmony_ci * be used restrict the rendering area */ 545bf215546Sopenharmony_ci 546bf215546Sopenharmony_ci damage_extent->minx = 0xffff; 547bf215546Sopenharmony_ci damage_extent->miny = 0xffff; 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci unsigned enable_count = 0; 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci for (i = 0; i < nrects; i++) { 552bf215546Sopenharmony_ci int x = rects[i].x, w = rects[i].width, h = rects[i].height; 553bf215546Sopenharmony_ci int y = res->height0 - (rects[i].y + h); 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci damage_extent->minx = MIN2(damage_extent->minx, x); 556bf215546Sopenharmony_ci damage_extent->miny = MIN2(damage_extent->miny, y); 557bf215546Sopenharmony_ci damage_extent->maxx = MAX2(damage_extent->maxx, 558bf215546Sopenharmony_ci MIN2(x + w, res->width0)); 559bf215546Sopenharmony_ci damage_extent->maxy = MAX2(damage_extent->maxy, 560bf215546Sopenharmony_ci MIN2(y + h, res->height0)); 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci if (!pres->damage.tile_map.enable) 563bf215546Sopenharmony_ci continue; 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci unsigned t_x_start = x / 32; 566bf215546Sopenharmony_ci unsigned t_x_end = (x + w - 1) / 32; 567bf215546Sopenharmony_ci unsigned t_y_start = y / 32; 568bf215546Sopenharmony_ci unsigned t_y_end = (y + h - 1) / 32; 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci for (unsigned t_y = t_y_start; t_y <= t_y_end; t_y++) { 571bf215546Sopenharmony_ci for (unsigned t_x = t_x_start; t_x <= t_x_end; t_x++) { 572bf215546Sopenharmony_ci unsigned b = (t_y * pres->damage.tile_map.stride * 8) + t_x; 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci if (BITSET_TEST(pres->damage.tile_map.data, b)) 575bf215546Sopenharmony_ci continue; 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_ci BITSET_SET(pres->damage.tile_map.data, b); 578bf215546Sopenharmony_ci enable_count++; 579bf215546Sopenharmony_ci } 580bf215546Sopenharmony_ci } 581bf215546Sopenharmony_ci } 582bf215546Sopenharmony_ci 583bf215546Sopenharmony_ci if (nrects == 0) { 584bf215546Sopenharmony_ci damage_extent->minx = 0; 585bf215546Sopenharmony_ci damage_extent->miny = 0; 586bf215546Sopenharmony_ci damage_extent->maxx = res->width0; 587bf215546Sopenharmony_ci damage_extent->maxy = res->height0; 588bf215546Sopenharmony_ci } 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci if (pres->damage.tile_map.enable) { 591bf215546Sopenharmony_ci unsigned t_x_start = damage_extent->minx / 32; 592bf215546Sopenharmony_ci unsigned t_x_end = damage_extent->maxx / 32; 593bf215546Sopenharmony_ci unsigned t_y_start = damage_extent->miny / 32; 594bf215546Sopenharmony_ci unsigned t_y_end = damage_extent->maxy / 32; 595bf215546Sopenharmony_ci unsigned tile_count = (t_x_end - t_x_start + 1) * 596bf215546Sopenharmony_ci (t_y_end - t_y_start + 1); 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci /* Don't bother passing a tile-enable-map if the amount of 599bf215546Sopenharmony_ci * tiles to reload is to close to the total number of tiles. 600bf215546Sopenharmony_ci */ 601bf215546Sopenharmony_ci if (tile_count - enable_count < 10) 602bf215546Sopenharmony_ci pres->damage.tile_map.enable = false; 603bf215546Sopenharmony_ci } 604bf215546Sopenharmony_ci 605bf215546Sopenharmony_ci} 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_cistatic struct pipe_resource * 608bf215546Sopenharmony_cipanfrost_resource_create_with_modifier(struct pipe_screen *screen, 609bf215546Sopenharmony_ci const struct pipe_resource *template, 610bf215546Sopenharmony_ci uint64_t modifier) 611bf215546Sopenharmony_ci{ 612bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(screen); 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci struct panfrost_resource *so = CALLOC_STRUCT(panfrost_resource); 615bf215546Sopenharmony_ci so->base = *template; 616bf215546Sopenharmony_ci so->base.screen = screen; 617bf215546Sopenharmony_ci 618bf215546Sopenharmony_ci pipe_reference_init(&so->base.reference, 1); 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci util_range_init(&so->valid_buffer_range); 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_ci if (template->bind & PAN_BIND_SHARED_MASK) { 623bf215546Sopenharmony_ci /* For compatibility with older consumers that may not be 624bf215546Sopenharmony_ci * modifiers aware, treat INVALID as LINEAR for shared 625bf215546Sopenharmony_ci * resources. 626bf215546Sopenharmony_ci */ 627bf215546Sopenharmony_ci if (modifier == DRM_FORMAT_MOD_INVALID) 628bf215546Sopenharmony_ci modifier = DRM_FORMAT_MOD_LINEAR; 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci /* At any rate, we can't change the modifier later for shared 631bf215546Sopenharmony_ci * resources, since we have no way to propagate the modifier 632bf215546Sopenharmony_ci * change. 633bf215546Sopenharmony_ci */ 634bf215546Sopenharmony_ci so->modifier_constant = true; 635bf215546Sopenharmony_ci } 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci panfrost_resource_setup(dev, so, modifier, template->format); 638bf215546Sopenharmony_ci 639bf215546Sopenharmony_ci /* Guess a label based on the bind */ 640bf215546Sopenharmony_ci unsigned bind = template->bind; 641bf215546Sopenharmony_ci const char *label = 642bf215546Sopenharmony_ci (bind & PIPE_BIND_INDEX_BUFFER) ? "Index buffer" : 643bf215546Sopenharmony_ci (bind & PIPE_BIND_SCANOUT) ? "Scanout" : 644bf215546Sopenharmony_ci (bind & PIPE_BIND_DISPLAY_TARGET) ? "Display target" : 645bf215546Sopenharmony_ci (bind & PIPE_BIND_SHARED) ? "Shared resource" : 646bf215546Sopenharmony_ci (bind & PIPE_BIND_RENDER_TARGET) ? "Render target" : 647bf215546Sopenharmony_ci (bind & PIPE_BIND_DEPTH_STENCIL) ? "Depth/stencil buffer" : 648bf215546Sopenharmony_ci (bind & PIPE_BIND_SAMPLER_VIEW) ? "Texture" : 649bf215546Sopenharmony_ci (bind & PIPE_BIND_VERTEX_BUFFER) ? "Vertex buffer" : 650bf215546Sopenharmony_ci (bind & PIPE_BIND_CONSTANT_BUFFER) ? "Constant buffer" : 651bf215546Sopenharmony_ci (bind & PIPE_BIND_GLOBAL) ? "Global memory" : 652bf215546Sopenharmony_ci (bind & PIPE_BIND_SHADER_BUFFER) ? "Shader buffer" : 653bf215546Sopenharmony_ci (bind & PIPE_BIND_SHADER_IMAGE) ? "Shader image" : 654bf215546Sopenharmony_ci "Other resource"; 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci if (dev->ro && (template->bind & PIPE_BIND_SCANOUT)) { 657bf215546Sopenharmony_ci struct winsys_handle handle; 658bf215546Sopenharmony_ci struct pan_block_size blocksize = panfrost_block_size(modifier, template->format); 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci /* Block-based texture formats are only used for texture 661bf215546Sopenharmony_ci * compression (not framebuffer compression!), which doesn't 662bf215546Sopenharmony_ci * make sense to share across processes. 663bf215546Sopenharmony_ci */ 664bf215546Sopenharmony_ci assert(util_format_get_blockwidth(template->format) == 1); 665bf215546Sopenharmony_ci assert(util_format_get_blockheight(template->format) == 1); 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_ci /* Present a resource with similar dimensions that, if allocated 668bf215546Sopenharmony_ci * as a linear image, is big enough to fit the resource in the 669bf215546Sopenharmony_ci * actual layout. For linear images, this is a no-op. For 16x16 670bf215546Sopenharmony_ci * tiling, this aligns the dimensions to 16x16. 671bf215546Sopenharmony_ci * 672bf215546Sopenharmony_ci * For AFBC, this aligns the width to the superblock width (as 673bf215546Sopenharmony_ci * expected) and adds extra rows to account for the header. This 674bf215546Sopenharmony_ci * is a bit of a lie, but it's the best we can do with dumb 675bf215546Sopenharmony_ci * buffers, which are extremely not meant for AFBC. And yet this 676bf215546Sopenharmony_ci * has to work anyway... 677bf215546Sopenharmony_ci * 678bf215546Sopenharmony_ci * Moral of the story: if you're reading this comment, that 679bf215546Sopenharmony_ci * means you're working on WSI and so it's already too late for 680bf215546Sopenharmony_ci * you. I'm sorry. 681bf215546Sopenharmony_ci */ 682bf215546Sopenharmony_ci unsigned width = ALIGN_POT(template->width0, blocksize.width); 683bf215546Sopenharmony_ci unsigned stride = ALIGN_POT(template->width0, blocksize.width) * 684bf215546Sopenharmony_ci util_format_get_blocksize(template->format); 685bf215546Sopenharmony_ci unsigned size = so->image.layout.data_size; 686bf215546Sopenharmony_ci unsigned effective_rows = DIV_ROUND_UP(size, stride); 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci struct pipe_resource scanout_tmpl = { 689bf215546Sopenharmony_ci .target = so->base.target, 690bf215546Sopenharmony_ci .format = template->format, 691bf215546Sopenharmony_ci .width0 = width, 692bf215546Sopenharmony_ci .height0 = effective_rows, 693bf215546Sopenharmony_ci .depth0 = 1, 694bf215546Sopenharmony_ci .array_size = 1, 695bf215546Sopenharmony_ci }; 696bf215546Sopenharmony_ci 697bf215546Sopenharmony_ci so->scanout = 698bf215546Sopenharmony_ci renderonly_scanout_for_resource(&scanout_tmpl, 699bf215546Sopenharmony_ci dev->ro, 700bf215546Sopenharmony_ci &handle); 701bf215546Sopenharmony_ci 702bf215546Sopenharmony_ci if (!so->scanout) { 703bf215546Sopenharmony_ci fprintf(stderr, "Failed to create scanout resource\n"); 704bf215546Sopenharmony_ci free(so); 705bf215546Sopenharmony_ci return NULL; 706bf215546Sopenharmony_ci } 707bf215546Sopenharmony_ci assert(handle.type == WINSYS_HANDLE_TYPE_FD); 708bf215546Sopenharmony_ci so->image.data.bo = panfrost_bo_import(dev, handle.handle); 709bf215546Sopenharmony_ci close(handle.handle); 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci if (!so->image.data.bo) { 712bf215546Sopenharmony_ci free(so); 713bf215546Sopenharmony_ci return NULL; 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci } else { 716bf215546Sopenharmony_ci /* We create a BO immediately but don't bother mapping, since we don't 717bf215546Sopenharmony_ci * care to map e.g. FBOs which the CPU probably won't touch */ 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci so->image.data.bo = 720bf215546Sopenharmony_ci panfrost_bo_create(dev, so->image.layout.data_size, PAN_BO_DELAY_MMAP, label); 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci so->constant_stencil = true; 723bf215546Sopenharmony_ci } 724bf215546Sopenharmony_ci 725bf215546Sopenharmony_ci if (drm_is_afbc(so->image.layout.modifier)) 726bf215546Sopenharmony_ci panfrost_resource_init_afbc_headers(so); 727bf215546Sopenharmony_ci 728bf215546Sopenharmony_ci panfrost_resource_set_damage_region(screen, &so->base, 0, NULL); 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_ci if (template->bind & PIPE_BIND_INDEX_BUFFER) 731bf215546Sopenharmony_ci so->index_cache = CALLOC_STRUCT(panfrost_minmax_cache); 732bf215546Sopenharmony_ci 733bf215546Sopenharmony_ci return (struct pipe_resource *)so; 734bf215546Sopenharmony_ci} 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci/* Default is to create a resource as don't care */ 737bf215546Sopenharmony_ci 738bf215546Sopenharmony_cistatic struct pipe_resource * 739bf215546Sopenharmony_cipanfrost_resource_create(struct pipe_screen *screen, 740bf215546Sopenharmony_ci const struct pipe_resource *template) 741bf215546Sopenharmony_ci{ 742bf215546Sopenharmony_ci return panfrost_resource_create_with_modifier(screen, template, 743bf215546Sopenharmony_ci DRM_FORMAT_MOD_INVALID); 744bf215546Sopenharmony_ci} 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci/* If no modifier is specified, we'll choose. Otherwise, the order of 747bf215546Sopenharmony_ci * preference is compressed, tiled, linear. */ 748bf215546Sopenharmony_ci 749bf215546Sopenharmony_cistatic struct pipe_resource * 750bf215546Sopenharmony_cipanfrost_resource_create_with_modifiers(struct pipe_screen *screen, 751bf215546Sopenharmony_ci const struct pipe_resource *template, 752bf215546Sopenharmony_ci const uint64_t *modifiers, int count) 753bf215546Sopenharmony_ci{ 754bf215546Sopenharmony_ci for (unsigned i = 0; i < PAN_MODIFIER_COUNT; ++i) { 755bf215546Sopenharmony_ci if (drm_find_modifier(pan_best_modifiers[i], modifiers, count)) { 756bf215546Sopenharmony_ci return panfrost_resource_create_with_modifier(screen, template, 757bf215546Sopenharmony_ci pan_best_modifiers[i]); 758bf215546Sopenharmony_ci } 759bf215546Sopenharmony_ci } 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci /* If we didn't find one, app specified invalid */ 762bf215546Sopenharmony_ci assert(count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID); 763bf215546Sopenharmony_ci return panfrost_resource_create(screen, template); 764bf215546Sopenharmony_ci} 765bf215546Sopenharmony_ci 766bf215546Sopenharmony_cistatic void 767bf215546Sopenharmony_cipanfrost_resource_destroy(struct pipe_screen *screen, 768bf215546Sopenharmony_ci struct pipe_resource *pt) 769bf215546Sopenharmony_ci{ 770bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(screen); 771bf215546Sopenharmony_ci struct panfrost_resource *rsrc = (struct panfrost_resource *) pt; 772bf215546Sopenharmony_ci 773bf215546Sopenharmony_ci if (rsrc->scanout) 774bf215546Sopenharmony_ci renderonly_scanout_destroy(rsrc->scanout, dev->ro); 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_ci if (rsrc->image.data.bo) 777bf215546Sopenharmony_ci panfrost_bo_unreference(rsrc->image.data.bo); 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci if (rsrc->image.crc.bo) 780bf215546Sopenharmony_ci panfrost_bo_unreference(rsrc->image.crc.bo); 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci free(rsrc->index_cache); 783bf215546Sopenharmony_ci free(rsrc->damage.tile_map.data); 784bf215546Sopenharmony_ci 785bf215546Sopenharmony_ci util_range_destroy(&rsrc->valid_buffer_range); 786bf215546Sopenharmony_ci free(rsrc); 787bf215546Sopenharmony_ci} 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_ci/* Most of the time we can do CPU-side transfers, but sometimes we need to use 790bf215546Sopenharmony_ci * the 3D pipe for this. Let's wrap u_blitter to blit to/from staging textures. 791bf215546Sopenharmony_ci * Code adapted from freedreno */ 792bf215546Sopenharmony_ci 793bf215546Sopenharmony_cistatic struct panfrost_resource * 794bf215546Sopenharmony_cipan_alloc_staging(struct panfrost_context *ctx, struct panfrost_resource *rsc, 795bf215546Sopenharmony_ci unsigned level, const struct pipe_box *box) 796bf215546Sopenharmony_ci{ 797bf215546Sopenharmony_ci struct pipe_context *pctx = &ctx->base; 798bf215546Sopenharmony_ci struct pipe_resource tmpl = rsc->base; 799bf215546Sopenharmony_ci 800bf215546Sopenharmony_ci tmpl.width0 = box->width; 801bf215546Sopenharmony_ci tmpl.height0 = box->height; 802bf215546Sopenharmony_ci /* for array textures, box->depth is the array_size, otherwise 803bf215546Sopenharmony_ci * for 3d textures, it is the depth: 804bf215546Sopenharmony_ci */ 805bf215546Sopenharmony_ci if (tmpl.array_size > 1) { 806bf215546Sopenharmony_ci if (tmpl.target == PIPE_TEXTURE_CUBE) 807bf215546Sopenharmony_ci tmpl.target = PIPE_TEXTURE_2D_ARRAY; 808bf215546Sopenharmony_ci tmpl.array_size = box->depth; 809bf215546Sopenharmony_ci tmpl.depth0 = 1; 810bf215546Sopenharmony_ci } else { 811bf215546Sopenharmony_ci tmpl.array_size = 1; 812bf215546Sopenharmony_ci tmpl.depth0 = box->depth; 813bf215546Sopenharmony_ci } 814bf215546Sopenharmony_ci tmpl.last_level = 0; 815bf215546Sopenharmony_ci tmpl.bind |= PIPE_BIND_LINEAR; 816bf215546Sopenharmony_ci tmpl.bind &= ~PAN_BIND_SHARED_MASK; 817bf215546Sopenharmony_ci 818bf215546Sopenharmony_ci struct pipe_resource *pstaging = 819bf215546Sopenharmony_ci pctx->screen->resource_create(pctx->screen, &tmpl); 820bf215546Sopenharmony_ci if (!pstaging) 821bf215546Sopenharmony_ci return NULL; 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci return pan_resource(pstaging); 824bf215546Sopenharmony_ci} 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_cistatic enum pipe_format 827bf215546Sopenharmony_cipan_blit_format(enum pipe_format fmt) 828bf215546Sopenharmony_ci{ 829bf215546Sopenharmony_ci const struct util_format_description *desc; 830bf215546Sopenharmony_ci desc = util_format_description(fmt); 831bf215546Sopenharmony_ci 832bf215546Sopenharmony_ci /* This must be an emulated format (using u_transfer_helper) as if it 833bf215546Sopenharmony_ci * was real RGTC we wouldn't have used AFBC and needed a blit. */ 834bf215546Sopenharmony_ci if (desc->layout == UTIL_FORMAT_LAYOUT_RGTC) 835bf215546Sopenharmony_ci fmt = PIPE_FORMAT_R8G8B8A8_UNORM; 836bf215546Sopenharmony_ci 837bf215546Sopenharmony_ci return fmt; 838bf215546Sopenharmony_ci} 839bf215546Sopenharmony_ci 840bf215546Sopenharmony_cistatic void 841bf215546Sopenharmony_cipan_blit_from_staging(struct pipe_context *pctx, struct panfrost_transfer *trans) 842bf215546Sopenharmony_ci{ 843bf215546Sopenharmony_ci struct pipe_resource *dst = trans->base.resource; 844bf215546Sopenharmony_ci struct pipe_blit_info blit = {0}; 845bf215546Sopenharmony_ci 846bf215546Sopenharmony_ci blit.dst.resource = dst; 847bf215546Sopenharmony_ci blit.dst.format = pan_blit_format(dst->format); 848bf215546Sopenharmony_ci blit.dst.level = trans->base.level; 849bf215546Sopenharmony_ci blit.dst.box = trans->base.box; 850bf215546Sopenharmony_ci blit.src.resource = trans->staging.rsrc; 851bf215546Sopenharmony_ci blit.src.format = pan_blit_format(trans->staging.rsrc->format); 852bf215546Sopenharmony_ci blit.src.level = 0; 853bf215546Sopenharmony_ci blit.src.box = trans->staging.box; 854bf215546Sopenharmony_ci blit.mask = util_format_get_mask(blit.src.format); 855bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_ci panfrost_blit(pctx, &blit); 858bf215546Sopenharmony_ci} 859bf215546Sopenharmony_ci 860bf215546Sopenharmony_cistatic void 861bf215546Sopenharmony_cipan_blit_to_staging(struct pipe_context *pctx, struct panfrost_transfer *trans) 862bf215546Sopenharmony_ci{ 863bf215546Sopenharmony_ci struct pipe_resource *src = trans->base.resource; 864bf215546Sopenharmony_ci struct pipe_blit_info blit = {0}; 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_ci blit.src.resource = src; 867bf215546Sopenharmony_ci blit.src.format = pan_blit_format(src->format); 868bf215546Sopenharmony_ci blit.src.level = trans->base.level; 869bf215546Sopenharmony_ci blit.src.box = trans->base.box; 870bf215546Sopenharmony_ci blit.dst.resource = trans->staging.rsrc; 871bf215546Sopenharmony_ci blit.dst.format = pan_blit_format(trans->staging.rsrc->format); 872bf215546Sopenharmony_ci blit.dst.level = 0; 873bf215546Sopenharmony_ci blit.dst.box = trans->staging.box; 874bf215546Sopenharmony_ci blit.mask = util_format_get_mask(blit.dst.format); 875bf215546Sopenharmony_ci blit.filter = PIPE_TEX_FILTER_NEAREST; 876bf215546Sopenharmony_ci 877bf215546Sopenharmony_ci panfrost_blit(pctx, &blit); 878bf215546Sopenharmony_ci} 879bf215546Sopenharmony_ci 880bf215546Sopenharmony_cistatic void 881bf215546Sopenharmony_cipanfrost_load_tiled_images(struct panfrost_transfer *transfer, 882bf215546Sopenharmony_ci struct panfrost_resource *rsrc) 883bf215546Sopenharmony_ci{ 884bf215546Sopenharmony_ci struct pipe_transfer *ptrans = &transfer->base; 885bf215546Sopenharmony_ci unsigned level = ptrans->level; 886bf215546Sopenharmony_ci 887bf215546Sopenharmony_ci /* If the requested level of the image is uninitialized, it's not 888bf215546Sopenharmony_ci * necessary to copy it. Leave the result unintiialized too. 889bf215546Sopenharmony_ci */ 890bf215546Sopenharmony_ci if (!BITSET_TEST(rsrc->valid.data, level)) 891bf215546Sopenharmony_ci return; 892bf215546Sopenharmony_ci 893bf215546Sopenharmony_ci struct panfrost_bo *bo = rsrc->image.data.bo; 894bf215546Sopenharmony_ci unsigned stride = panfrost_get_layer_stride(&rsrc->image.layout, level); 895bf215546Sopenharmony_ci 896bf215546Sopenharmony_ci /* Otherwise, load each layer separately, required to load from 3D and 897bf215546Sopenharmony_ci * array textures. 898bf215546Sopenharmony_ci */ 899bf215546Sopenharmony_ci for (unsigned z = 0; z < ptrans->box.depth; ++z) { 900bf215546Sopenharmony_ci void *dst = transfer->map + (ptrans->layer_stride * z); 901bf215546Sopenharmony_ci uint8_t *map = bo->ptr.cpu + 902bf215546Sopenharmony_ci rsrc->image.layout.slices[level].offset + 903bf215546Sopenharmony_ci (z + ptrans->box.z) * stride; 904bf215546Sopenharmony_ci 905bf215546Sopenharmony_ci panfrost_load_tiled_image(dst, map, ptrans->box.x, 906bf215546Sopenharmony_ci ptrans->box.y, ptrans->box.width, 907bf215546Sopenharmony_ci ptrans->box.height, ptrans->stride, 908bf215546Sopenharmony_ci rsrc->image.layout.slices[level].row_stride, 909bf215546Sopenharmony_ci rsrc->image.layout.format); 910bf215546Sopenharmony_ci } 911bf215546Sopenharmony_ci} 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_cistatic void 914bf215546Sopenharmony_cipanfrost_store_tiled_images(struct panfrost_transfer *transfer, 915bf215546Sopenharmony_ci struct panfrost_resource *rsrc) 916bf215546Sopenharmony_ci{ 917bf215546Sopenharmony_ci struct panfrost_bo *bo = rsrc->image.data.bo; 918bf215546Sopenharmony_ci struct pipe_transfer *ptrans = &transfer->base; 919bf215546Sopenharmony_ci unsigned level = ptrans->level; 920bf215546Sopenharmony_ci unsigned stride = panfrost_get_layer_stride(&rsrc->image.layout, level); 921bf215546Sopenharmony_ci 922bf215546Sopenharmony_ci /* Otherwise, store each layer separately, required to store to 3D and 923bf215546Sopenharmony_ci * array textures. 924bf215546Sopenharmony_ci */ 925bf215546Sopenharmony_ci for (unsigned z = 0; z < ptrans->box.depth; ++z) { 926bf215546Sopenharmony_ci void *src = transfer->map + (ptrans->layer_stride * z); 927bf215546Sopenharmony_ci uint8_t *map = bo->ptr.cpu + 928bf215546Sopenharmony_ci rsrc->image.layout.slices[level].offset + 929bf215546Sopenharmony_ci (z + ptrans->box.z) * stride; 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_ci panfrost_store_tiled_image(map, src, 932bf215546Sopenharmony_ci ptrans->box.x, ptrans->box.y, 933bf215546Sopenharmony_ci ptrans->box.width, ptrans->box.height, 934bf215546Sopenharmony_ci rsrc->image.layout.slices[level].row_stride, 935bf215546Sopenharmony_ci ptrans->stride, rsrc->image.layout.format); 936bf215546Sopenharmony_ci } 937bf215546Sopenharmony_ci} 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_cistatic bool 940bf215546Sopenharmony_cipanfrost_box_covers_resource(const struct pipe_resource *resource, 941bf215546Sopenharmony_ci const struct pipe_box *box) 942bf215546Sopenharmony_ci{ 943bf215546Sopenharmony_ci return resource->last_level == 0 && 944bf215546Sopenharmony_ci util_texrange_covers_whole_level(resource, 0, box->x, box->y, 945bf215546Sopenharmony_ci box->z, box->width, box->height, 946bf215546Sopenharmony_ci box->depth); 947bf215546Sopenharmony_ci} 948bf215546Sopenharmony_ci 949bf215546Sopenharmony_cistatic void * 950bf215546Sopenharmony_cipanfrost_ptr_map(struct pipe_context *pctx, 951bf215546Sopenharmony_ci struct pipe_resource *resource, 952bf215546Sopenharmony_ci unsigned level, 953bf215546Sopenharmony_ci unsigned usage, /* a combination of PIPE_MAP_x */ 954bf215546Sopenharmony_ci const struct pipe_box *box, 955bf215546Sopenharmony_ci struct pipe_transfer **out_transfer) 956bf215546Sopenharmony_ci{ 957bf215546Sopenharmony_ci struct panfrost_context *ctx = pan_context(pctx); 958bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(pctx->screen); 959bf215546Sopenharmony_ci struct panfrost_resource *rsrc = pan_resource(resource); 960bf215546Sopenharmony_ci enum pipe_format format = rsrc->image.layout.format; 961bf215546Sopenharmony_ci int bytes_per_block = util_format_get_blocksize(format); 962bf215546Sopenharmony_ci struct panfrost_bo *bo = rsrc->image.data.bo; 963bf215546Sopenharmony_ci 964bf215546Sopenharmony_ci /* Can't map tiled/compressed directly */ 965bf215546Sopenharmony_ci if ((usage & PIPE_MAP_DIRECTLY) && rsrc->image.layout.modifier != DRM_FORMAT_MOD_LINEAR) 966bf215546Sopenharmony_ci return NULL; 967bf215546Sopenharmony_ci 968bf215546Sopenharmony_ci struct panfrost_transfer *transfer = rzalloc(pctx, struct panfrost_transfer); 969bf215546Sopenharmony_ci transfer->base.level = level; 970bf215546Sopenharmony_ci transfer->base.usage = usage; 971bf215546Sopenharmony_ci transfer->base.box = *box; 972bf215546Sopenharmony_ci 973bf215546Sopenharmony_ci pipe_resource_reference(&transfer->base.resource, resource); 974bf215546Sopenharmony_ci *out_transfer = &transfer->base; 975bf215546Sopenharmony_ci 976bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) 977bf215546Sopenharmony_ci rsrc->constant_stencil = false; 978bf215546Sopenharmony_ci 979bf215546Sopenharmony_ci /* We don't have s/w routines for AFBC, so use a staging texture */ 980bf215546Sopenharmony_ci if (drm_is_afbc(rsrc->image.layout.modifier)) { 981bf215546Sopenharmony_ci struct panfrost_resource *staging = pan_alloc_staging(ctx, rsrc, level, box); 982bf215546Sopenharmony_ci assert(staging); 983bf215546Sopenharmony_ci 984bf215546Sopenharmony_ci /* Staging resources have one LOD: level 0. Query the strides 985bf215546Sopenharmony_ci * on this LOD. 986bf215546Sopenharmony_ci */ 987bf215546Sopenharmony_ci transfer->base.stride = staging->image.layout.slices[0].row_stride; 988bf215546Sopenharmony_ci transfer->base.layer_stride = 989bf215546Sopenharmony_ci panfrost_get_layer_stride(&staging->image.layout, 0); 990bf215546Sopenharmony_ci 991bf215546Sopenharmony_ci transfer->staging.rsrc = &staging->base; 992bf215546Sopenharmony_ci 993bf215546Sopenharmony_ci transfer->staging.box = *box; 994bf215546Sopenharmony_ci transfer->staging.box.x = 0; 995bf215546Sopenharmony_ci transfer->staging.box.y = 0; 996bf215546Sopenharmony_ci transfer->staging.box.z = 0; 997bf215546Sopenharmony_ci 998bf215546Sopenharmony_ci assert(transfer->staging.rsrc != NULL); 999bf215546Sopenharmony_ci 1000bf215546Sopenharmony_ci bool valid = BITSET_TEST(rsrc->valid.data, level); 1001bf215546Sopenharmony_ci 1002bf215546Sopenharmony_ci if ((usage & PIPE_MAP_READ) && (valid || rsrc->track.nr_writers > 0)) { 1003bf215546Sopenharmony_ci pan_blit_to_staging(pctx, transfer); 1004bf215546Sopenharmony_ci panfrost_flush_writer(ctx, staging, "AFBC read staging blit"); 1005bf215546Sopenharmony_ci panfrost_bo_wait(staging->image.data.bo, INT64_MAX, false); 1006bf215546Sopenharmony_ci } 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci panfrost_bo_mmap(staging->image.data.bo); 1009bf215546Sopenharmony_ci return staging->image.data.bo->ptr.cpu; 1010bf215546Sopenharmony_ci } 1011bf215546Sopenharmony_ci 1012bf215546Sopenharmony_ci /* If we haven't already mmaped, now's the time */ 1013bf215546Sopenharmony_ci panfrost_bo_mmap(bo); 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci if (dev->debug & (PAN_DBG_TRACE | PAN_DBG_SYNC)) 1016bf215546Sopenharmony_ci pandecode_inject_mmap(bo->ptr.gpu, bo->ptr.cpu, bo->size, NULL); 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_ci /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is 1019bf215546Sopenharmony_ci * being mapped. 1020bf215546Sopenharmony_ci */ 1021bf215546Sopenharmony_ci if ((usage & PIPE_MAP_DISCARD_RANGE) && 1022bf215546Sopenharmony_ci !(usage & PIPE_MAP_UNSYNCHRONIZED) && 1023bf215546Sopenharmony_ci !(resource->flags & PIPE_RESOURCE_FLAG_MAP_PERSISTENT) && 1024bf215546Sopenharmony_ci panfrost_box_covers_resource(resource, box) && 1025bf215546Sopenharmony_ci !(rsrc->image.data.bo->flags & PAN_BO_SHARED)) { 1026bf215546Sopenharmony_ci 1027bf215546Sopenharmony_ci usage |= PIPE_MAP_DISCARD_WHOLE_RESOURCE; 1028bf215546Sopenharmony_ci } 1029bf215546Sopenharmony_ci 1030bf215546Sopenharmony_ci bool create_new_bo = usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE; 1031bf215546Sopenharmony_ci bool copy_resource = false; 1032bf215546Sopenharmony_ci 1033bf215546Sopenharmony_ci if (!create_new_bo && 1034bf215546Sopenharmony_ci !(usage & PIPE_MAP_UNSYNCHRONIZED) && 1035bf215546Sopenharmony_ci (usage & PIPE_MAP_WRITE) && 1036bf215546Sopenharmony_ci !(resource->target == PIPE_BUFFER 1037bf215546Sopenharmony_ci && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) && 1038bf215546Sopenharmony_ci rsrc->track.nr_users > 0) { 1039bf215546Sopenharmony_ci 1040bf215546Sopenharmony_ci /* When a resource to be modified is already being used by a 1041bf215546Sopenharmony_ci * pending batch, it is often faster to copy the whole BO than 1042bf215546Sopenharmony_ci * to flush and split the frame in two. 1043bf215546Sopenharmony_ci */ 1044bf215546Sopenharmony_ci 1045bf215546Sopenharmony_ci panfrost_flush_writer(ctx, rsrc, "Shadow resource creation"); 1046bf215546Sopenharmony_ci panfrost_bo_wait(bo, INT64_MAX, false); 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci create_new_bo = true; 1049bf215546Sopenharmony_ci copy_resource = !(usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE); 1050bf215546Sopenharmony_ci } 1051bf215546Sopenharmony_ci 1052bf215546Sopenharmony_ci /* Shadowing with separate stencil may require additional accounting. 1053bf215546Sopenharmony_ci * Bail in these exotic cases. 1054bf215546Sopenharmony_ci */ 1055bf215546Sopenharmony_ci if (rsrc->separate_stencil) { 1056bf215546Sopenharmony_ci create_new_bo = false; 1057bf215546Sopenharmony_ci copy_resource = false; 1058bf215546Sopenharmony_ci } 1059bf215546Sopenharmony_ci 1060bf215546Sopenharmony_ci if (create_new_bo) { 1061bf215546Sopenharmony_ci /* Make sure we re-emit any descriptors using this resource */ 1062bf215546Sopenharmony_ci panfrost_dirty_state_all(ctx); 1063bf215546Sopenharmony_ci 1064bf215546Sopenharmony_ci /* If the BO is used by one of the pending batches or if it's 1065bf215546Sopenharmony_ci * not ready yet (still accessed by one of the already flushed 1066bf215546Sopenharmony_ci * batches), we try to allocate a new one to avoid waiting. 1067bf215546Sopenharmony_ci */ 1068bf215546Sopenharmony_ci if (rsrc->track.nr_users > 0 || 1069bf215546Sopenharmony_ci !panfrost_bo_wait(bo, 0, true)) { 1070bf215546Sopenharmony_ci /* We want the BO to be MMAPed. */ 1071bf215546Sopenharmony_ci uint32_t flags = bo->flags & ~PAN_BO_DELAY_MMAP; 1072bf215546Sopenharmony_ci struct panfrost_bo *newbo = NULL; 1073bf215546Sopenharmony_ci 1074bf215546Sopenharmony_ci /* When the BO has been imported/exported, we can't 1075bf215546Sopenharmony_ci * replace it by another one, otherwise the 1076bf215546Sopenharmony_ci * importer/exporter wouldn't see the change we're 1077bf215546Sopenharmony_ci * doing to it. 1078bf215546Sopenharmony_ci */ 1079bf215546Sopenharmony_ci if (!(bo->flags & PAN_BO_SHARED)) 1080bf215546Sopenharmony_ci newbo = panfrost_bo_create(dev, bo->size, 1081bf215546Sopenharmony_ci flags, bo->label); 1082bf215546Sopenharmony_ci 1083bf215546Sopenharmony_ci if (newbo) { 1084bf215546Sopenharmony_ci if (copy_resource) 1085bf215546Sopenharmony_ci memcpy(newbo->ptr.cpu, rsrc->image.data.bo->ptr.cpu, bo->size); 1086bf215546Sopenharmony_ci 1087bf215546Sopenharmony_ci panfrost_resource_swap_bo(ctx, rsrc, newbo); 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_ci if (!copy_resource && 1090bf215546Sopenharmony_ci drm_is_afbc(rsrc->image.layout.modifier)) 1091bf215546Sopenharmony_ci panfrost_resource_init_afbc_headers(rsrc); 1092bf215546Sopenharmony_ci 1093bf215546Sopenharmony_ci bo = newbo; 1094bf215546Sopenharmony_ci } else { 1095bf215546Sopenharmony_ci /* Allocation failed or was impossible, let's 1096bf215546Sopenharmony_ci * fall back on a flush+wait. 1097bf215546Sopenharmony_ci */ 1098bf215546Sopenharmony_ci panfrost_flush_batches_accessing_rsrc(ctx, rsrc, 1099bf215546Sopenharmony_ci "Resource access with high memory pressure"); 1100bf215546Sopenharmony_ci panfrost_bo_wait(bo, INT64_MAX, true); 1101bf215546Sopenharmony_ci } 1102bf215546Sopenharmony_ci } 1103bf215546Sopenharmony_ci } else if ((usage & PIPE_MAP_WRITE) 1104bf215546Sopenharmony_ci && resource->target == PIPE_BUFFER 1105bf215546Sopenharmony_ci && !util_ranges_intersect(&rsrc->valid_buffer_range, box->x, box->x + box->width)) { 1106bf215546Sopenharmony_ci /* No flush for writes to uninitialized */ 1107bf215546Sopenharmony_ci } else if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { 1108bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) { 1109bf215546Sopenharmony_ci panfrost_flush_batches_accessing_rsrc(ctx, rsrc, "Synchronized write"); 1110bf215546Sopenharmony_ci panfrost_bo_wait(bo, INT64_MAX, true); 1111bf215546Sopenharmony_ci } else if (usage & PIPE_MAP_READ) { 1112bf215546Sopenharmony_ci panfrost_flush_writer(ctx, rsrc, "Synchronized read"); 1113bf215546Sopenharmony_ci panfrost_bo_wait(bo, INT64_MAX, false); 1114bf215546Sopenharmony_ci } 1115bf215546Sopenharmony_ci } 1116bf215546Sopenharmony_ci 1117bf215546Sopenharmony_ci /* For access to compressed textures, we want the (x, y, w, h) 1118bf215546Sopenharmony_ci * region-of-interest in blocks, not pixels. Then we compute the stride 1119bf215546Sopenharmony_ci * between rows of blocks as the width in blocks times the width per 1120bf215546Sopenharmony_ci * block, etc. 1121bf215546Sopenharmony_ci */ 1122bf215546Sopenharmony_ci struct pipe_box box_blocks; 1123bf215546Sopenharmony_ci u_box_pixels_to_blocks(&box_blocks, box, format); 1124bf215546Sopenharmony_ci 1125bf215546Sopenharmony_ci if (rsrc->image.layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) { 1126bf215546Sopenharmony_ci transfer->base.stride = box_blocks.width * bytes_per_block; 1127bf215546Sopenharmony_ci transfer->base.layer_stride = transfer->base.stride * box_blocks.height; 1128bf215546Sopenharmony_ci transfer->map = ralloc_size(transfer, transfer->base.layer_stride * box->depth); 1129bf215546Sopenharmony_ci 1130bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) 1131bf215546Sopenharmony_ci panfrost_load_tiled_images(transfer, rsrc); 1132bf215546Sopenharmony_ci 1133bf215546Sopenharmony_ci return transfer->map; 1134bf215546Sopenharmony_ci } else { 1135bf215546Sopenharmony_ci assert (rsrc->image.layout.modifier == DRM_FORMAT_MOD_LINEAR); 1136bf215546Sopenharmony_ci 1137bf215546Sopenharmony_ci /* Direct, persistent writes create holes in time for 1138bf215546Sopenharmony_ci * caching... I don't know if this is actually possible but we 1139bf215546Sopenharmony_ci * should still get it right */ 1140bf215546Sopenharmony_ci 1141bf215546Sopenharmony_ci unsigned dpw = PIPE_MAP_DIRECTLY | PIPE_MAP_WRITE | PIPE_MAP_PERSISTENT; 1142bf215546Sopenharmony_ci 1143bf215546Sopenharmony_ci if ((usage & dpw) == dpw && rsrc->index_cache) 1144bf215546Sopenharmony_ci return NULL; 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_ci transfer->base.stride = rsrc->image.layout.slices[level].row_stride; 1147bf215546Sopenharmony_ci transfer->base.layer_stride = 1148bf215546Sopenharmony_ci panfrost_get_layer_stride(&rsrc->image.layout, level); 1149bf215546Sopenharmony_ci 1150bf215546Sopenharmony_ci /* By mapping direct-write, we're implicitly already 1151bf215546Sopenharmony_ci * initialized (maybe), so be conservative */ 1152bf215546Sopenharmony_ci 1153bf215546Sopenharmony_ci if (usage & PIPE_MAP_WRITE) { 1154bf215546Sopenharmony_ci BITSET_SET(rsrc->valid.data, level); 1155bf215546Sopenharmony_ci panfrost_minmax_cache_invalidate(rsrc->index_cache, &transfer->base); 1156bf215546Sopenharmony_ci } 1157bf215546Sopenharmony_ci 1158bf215546Sopenharmony_ci return bo->ptr.cpu 1159bf215546Sopenharmony_ci + rsrc->image.layout.slices[level].offset 1160bf215546Sopenharmony_ci + box->z * transfer->base.layer_stride 1161bf215546Sopenharmony_ci + box_blocks.y * rsrc->image.layout.slices[level].row_stride 1162bf215546Sopenharmony_ci + box_blocks.x * bytes_per_block; 1163bf215546Sopenharmony_ci } 1164bf215546Sopenharmony_ci} 1165bf215546Sopenharmony_ci 1166bf215546Sopenharmony_civoid 1167bf215546Sopenharmony_cipan_resource_modifier_convert(struct panfrost_context *ctx, 1168bf215546Sopenharmony_ci struct panfrost_resource *rsrc, 1169bf215546Sopenharmony_ci uint64_t modifier, const char *reason) 1170bf215546Sopenharmony_ci{ 1171bf215546Sopenharmony_ci assert(!rsrc->modifier_constant); 1172bf215546Sopenharmony_ci 1173bf215546Sopenharmony_ci perf_debug_ctx(ctx, "Disabling AFBC with a blit. Reason: %s", reason); 1174bf215546Sopenharmony_ci 1175bf215546Sopenharmony_ci struct pipe_resource *tmp_prsrc = 1176bf215546Sopenharmony_ci panfrost_resource_create_with_modifier( 1177bf215546Sopenharmony_ci ctx->base.screen, &rsrc->base, modifier); 1178bf215546Sopenharmony_ci struct panfrost_resource *tmp_rsrc = pan_resource(tmp_prsrc); 1179bf215546Sopenharmony_ci enum pipe_format blit_fmt = pan_blit_format(tmp_rsrc->base.format); 1180bf215546Sopenharmony_ci 1181bf215546Sopenharmony_ci unsigned depth = rsrc->base.target == PIPE_TEXTURE_3D ? 1182bf215546Sopenharmony_ci rsrc->base.depth0 : rsrc->base.array_size; 1183bf215546Sopenharmony_ci 1184bf215546Sopenharmony_ci struct pipe_box box = 1185bf215546Sopenharmony_ci { 0, 0, 0, rsrc->base.width0, rsrc->base.height0, depth }; 1186bf215546Sopenharmony_ci 1187bf215546Sopenharmony_ci struct pipe_blit_info blit = { 1188bf215546Sopenharmony_ci .dst.resource = &tmp_rsrc->base, 1189bf215546Sopenharmony_ci .dst.format = blit_fmt, 1190bf215546Sopenharmony_ci .dst.box = box, 1191bf215546Sopenharmony_ci .src.resource = &rsrc->base, 1192bf215546Sopenharmony_ci .src.format = pan_blit_format(rsrc->base.format), 1193bf215546Sopenharmony_ci .src.box = box, 1194bf215546Sopenharmony_ci .mask = util_format_get_mask(blit_fmt), 1195bf215546Sopenharmony_ci .filter = PIPE_TEX_FILTER_NEAREST 1196bf215546Sopenharmony_ci }; 1197bf215546Sopenharmony_ci 1198bf215546Sopenharmony_ci for (int i = 0; i <= rsrc->base.last_level; i++) { 1199bf215546Sopenharmony_ci if (BITSET_TEST(rsrc->valid.data, i)) { 1200bf215546Sopenharmony_ci blit.dst.level = blit.src.level = i; 1201bf215546Sopenharmony_ci panfrost_blit(&ctx->base, &blit); 1202bf215546Sopenharmony_ci } 1203bf215546Sopenharmony_ci } 1204bf215546Sopenharmony_ci 1205bf215546Sopenharmony_ci panfrost_bo_unreference(rsrc->image.data.bo); 1206bf215546Sopenharmony_ci if (rsrc->image.crc.bo) 1207bf215546Sopenharmony_ci panfrost_bo_unreference(rsrc->image.crc.bo); 1208bf215546Sopenharmony_ci 1209bf215546Sopenharmony_ci rsrc->image.data.bo = tmp_rsrc->image.data.bo; 1210bf215546Sopenharmony_ci panfrost_bo_reference(rsrc->image.data.bo); 1211bf215546Sopenharmony_ci 1212bf215546Sopenharmony_ci panfrost_resource_setup(pan_device(ctx->base.screen), rsrc, modifier, 1213bf215546Sopenharmony_ci blit.dst.format); 1214bf215546Sopenharmony_ci pipe_resource_reference(&tmp_prsrc, NULL); 1215bf215546Sopenharmony_ci} 1216bf215546Sopenharmony_ci 1217bf215546Sopenharmony_ci/* Validate that an AFBC resource may be used as a particular format. If it may 1218bf215546Sopenharmony_ci * not, decompress it on the fly. Failure to do so can produce wrong results or 1219bf215546Sopenharmony_ci * invalid data faults when sampling or rendering to AFBC */ 1220bf215546Sopenharmony_ci 1221bf215546Sopenharmony_civoid 1222bf215546Sopenharmony_cipan_legalize_afbc_format(struct panfrost_context *ctx, 1223bf215546Sopenharmony_ci struct panfrost_resource *rsrc, 1224bf215546Sopenharmony_ci enum pipe_format format) 1225bf215546Sopenharmony_ci{ 1226bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(ctx->base.screen); 1227bf215546Sopenharmony_ci 1228bf215546Sopenharmony_ci if (!drm_is_afbc(rsrc->image.layout.modifier)) 1229bf215546Sopenharmony_ci return; 1230bf215546Sopenharmony_ci 1231bf215546Sopenharmony_ci if (panfrost_afbc_format(dev->arch, pan_blit_format(rsrc->base.format)) == 1232bf215546Sopenharmony_ci panfrost_afbc_format(dev->arch, pan_blit_format(format))) 1233bf215546Sopenharmony_ci return; 1234bf215546Sopenharmony_ci 1235bf215546Sopenharmony_ci pan_resource_modifier_convert(ctx, rsrc, 1236bf215546Sopenharmony_ci DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, 1237bf215546Sopenharmony_ci "Reinterpreting AFBC surface as incompatible format"); 1238bf215546Sopenharmony_ci} 1239bf215546Sopenharmony_ci 1240bf215546Sopenharmony_cistatic bool 1241bf215546Sopenharmony_cipanfrost_should_linear_convert(struct panfrost_device *dev, 1242bf215546Sopenharmony_ci struct panfrost_resource *prsrc, 1243bf215546Sopenharmony_ci struct pipe_transfer *transfer) 1244bf215546Sopenharmony_ci{ 1245bf215546Sopenharmony_ci if (prsrc->modifier_constant) 1246bf215546Sopenharmony_ci return false; 1247bf215546Sopenharmony_ci 1248bf215546Sopenharmony_ci /* Overwriting the entire resource indicates streaming, for which 1249bf215546Sopenharmony_ci * linear layout is most efficient due to the lack of expensive 1250bf215546Sopenharmony_ci * conversion. 1251bf215546Sopenharmony_ci * 1252bf215546Sopenharmony_ci * For now we just switch to linear after a number of complete 1253bf215546Sopenharmony_ci * overwrites to keep things simple, but we could do better. 1254bf215546Sopenharmony_ci * 1255bf215546Sopenharmony_ci * This mechanism is only implemented for 2D resources. This suffices 1256bf215546Sopenharmony_ci * for video players, its intended use case. 1257bf215546Sopenharmony_ci */ 1258bf215546Sopenharmony_ci 1259bf215546Sopenharmony_ci bool entire_overwrite = 1260bf215546Sopenharmony_ci panfrost_is_2d(prsrc) && 1261bf215546Sopenharmony_ci prsrc->base.last_level == 0 && 1262bf215546Sopenharmony_ci transfer->box.width == prsrc->base.width0 && 1263bf215546Sopenharmony_ci transfer->box.height == prsrc->base.height0 && 1264bf215546Sopenharmony_ci transfer->box.x == 0 && 1265bf215546Sopenharmony_ci transfer->box.y == 0; 1266bf215546Sopenharmony_ci 1267bf215546Sopenharmony_ci if (entire_overwrite) 1268bf215546Sopenharmony_ci ++prsrc->modifier_updates; 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci if (prsrc->modifier_updates >= LAYOUT_CONVERT_THRESHOLD) { 1271bf215546Sopenharmony_ci perf_debug(dev, "Transitioning to linear due to streaming usage"); 1272bf215546Sopenharmony_ci return true; 1273bf215546Sopenharmony_ci } else { 1274bf215546Sopenharmony_ci return false; 1275bf215546Sopenharmony_ci } 1276bf215546Sopenharmony_ci} 1277bf215546Sopenharmony_ci 1278bf215546Sopenharmony_cistatic void 1279bf215546Sopenharmony_cipanfrost_ptr_unmap(struct pipe_context *pctx, 1280bf215546Sopenharmony_ci struct pipe_transfer *transfer) 1281bf215546Sopenharmony_ci{ 1282bf215546Sopenharmony_ci /* Gallium expects writeback here, so we tile */ 1283bf215546Sopenharmony_ci 1284bf215546Sopenharmony_ci struct panfrost_transfer *trans = pan_transfer(transfer); 1285bf215546Sopenharmony_ci struct panfrost_resource *prsrc = (struct panfrost_resource *) transfer->resource; 1286bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(pctx->screen); 1287bf215546Sopenharmony_ci 1288bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE) 1289bf215546Sopenharmony_ci prsrc->valid.crc = false; 1290bf215546Sopenharmony_ci 1291bf215546Sopenharmony_ci /* AFBC will use a staging resource. `initialized` will be set when the 1292bf215546Sopenharmony_ci * fragment job is created; this is deferred to prevent useless surface 1293bf215546Sopenharmony_ci * reloads that can cascade into DATA_INVALID_FAULTs due to reading 1294bf215546Sopenharmony_ci * malformed AFBC data if uninitialized */ 1295bf215546Sopenharmony_ci 1296bf215546Sopenharmony_ci if (trans->staging.rsrc) { 1297bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE) { 1298bf215546Sopenharmony_ci if (panfrost_should_linear_convert(dev, prsrc, transfer)) { 1299bf215546Sopenharmony_ci 1300bf215546Sopenharmony_ci panfrost_bo_unreference(prsrc->image.data.bo); 1301bf215546Sopenharmony_ci if (prsrc->image.crc.bo) 1302bf215546Sopenharmony_ci panfrost_bo_unreference(prsrc->image.crc.bo); 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_ci panfrost_resource_setup(dev, prsrc, DRM_FORMAT_MOD_LINEAR, 1305bf215546Sopenharmony_ci prsrc->image.layout.format); 1306bf215546Sopenharmony_ci 1307bf215546Sopenharmony_ci prsrc->image.data.bo = pan_resource(trans->staging.rsrc)->image.data.bo; 1308bf215546Sopenharmony_ci panfrost_bo_reference(prsrc->image.data.bo); 1309bf215546Sopenharmony_ci } else { 1310bf215546Sopenharmony_ci pan_blit_from_staging(pctx, trans); 1311bf215546Sopenharmony_ci panfrost_flush_batches_accessing_rsrc(pan_context(pctx), 1312bf215546Sopenharmony_ci pan_resource(trans->staging.rsrc), 1313bf215546Sopenharmony_ci "AFBC write staging blit"); 1314bf215546Sopenharmony_ci } 1315bf215546Sopenharmony_ci } 1316bf215546Sopenharmony_ci 1317bf215546Sopenharmony_ci pipe_resource_reference(&trans->staging.rsrc, NULL); 1318bf215546Sopenharmony_ci } 1319bf215546Sopenharmony_ci 1320bf215546Sopenharmony_ci /* Tiling will occur in software from a staging cpu buffer */ 1321bf215546Sopenharmony_ci if (trans->map) { 1322bf215546Sopenharmony_ci struct panfrost_bo *bo = prsrc->image.data.bo; 1323bf215546Sopenharmony_ci 1324bf215546Sopenharmony_ci if (transfer->usage & PIPE_MAP_WRITE) { 1325bf215546Sopenharmony_ci BITSET_SET(prsrc->valid.data, transfer->level); 1326bf215546Sopenharmony_ci 1327bf215546Sopenharmony_ci if (prsrc->image.layout.modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED) { 1328bf215546Sopenharmony_ci if (panfrost_should_linear_convert(dev, prsrc, transfer)) { 1329bf215546Sopenharmony_ci panfrost_resource_setup(dev, prsrc, DRM_FORMAT_MOD_LINEAR, 1330bf215546Sopenharmony_ci prsrc->image.layout.format); 1331bf215546Sopenharmony_ci if (prsrc->image.layout.data_size > bo->size) { 1332bf215546Sopenharmony_ci const char *label = bo->label; 1333bf215546Sopenharmony_ci panfrost_bo_unreference(bo); 1334bf215546Sopenharmony_ci bo = prsrc->image.data.bo = 1335bf215546Sopenharmony_ci panfrost_bo_create(dev, prsrc->image.layout.data_size, 0, label); 1336bf215546Sopenharmony_ci assert(bo); 1337bf215546Sopenharmony_ci } 1338bf215546Sopenharmony_ci 1339bf215546Sopenharmony_ci util_copy_rect( 1340bf215546Sopenharmony_ci bo->ptr.cpu + prsrc->image.layout.slices[0].offset, 1341bf215546Sopenharmony_ci prsrc->base.format, 1342bf215546Sopenharmony_ci prsrc->image.layout.slices[0].row_stride, 1343bf215546Sopenharmony_ci 0, 0, 1344bf215546Sopenharmony_ci transfer->box.width, 1345bf215546Sopenharmony_ci transfer->box.height, 1346bf215546Sopenharmony_ci trans->map, 1347bf215546Sopenharmony_ci transfer->stride, 1348bf215546Sopenharmony_ci 0, 0); 1349bf215546Sopenharmony_ci } else { 1350bf215546Sopenharmony_ci panfrost_store_tiled_images(trans, prsrc); 1351bf215546Sopenharmony_ci } 1352bf215546Sopenharmony_ci } 1353bf215546Sopenharmony_ci } 1354bf215546Sopenharmony_ci } 1355bf215546Sopenharmony_ci 1356bf215546Sopenharmony_ci 1357bf215546Sopenharmony_ci util_range_add(&prsrc->base, &prsrc->valid_buffer_range, 1358bf215546Sopenharmony_ci transfer->box.x, 1359bf215546Sopenharmony_ci transfer->box.x + transfer->box.width); 1360bf215546Sopenharmony_ci 1361bf215546Sopenharmony_ci panfrost_minmax_cache_invalidate(prsrc->index_cache, transfer); 1362bf215546Sopenharmony_ci 1363bf215546Sopenharmony_ci /* Derefence the resource */ 1364bf215546Sopenharmony_ci pipe_resource_reference(&transfer->resource, NULL); 1365bf215546Sopenharmony_ci 1366bf215546Sopenharmony_ci /* Transfer itself is RALLOCed at the moment */ 1367bf215546Sopenharmony_ci ralloc_free(transfer); 1368bf215546Sopenharmony_ci} 1369bf215546Sopenharmony_ci 1370bf215546Sopenharmony_cistatic void 1371bf215546Sopenharmony_cipanfrost_ptr_flush_region(struct pipe_context *pctx, 1372bf215546Sopenharmony_ci struct pipe_transfer *transfer, 1373bf215546Sopenharmony_ci const struct pipe_box *box) 1374bf215546Sopenharmony_ci{ 1375bf215546Sopenharmony_ci struct panfrost_resource *rsc = pan_resource(transfer->resource); 1376bf215546Sopenharmony_ci 1377bf215546Sopenharmony_ci if (transfer->resource->target == PIPE_BUFFER) { 1378bf215546Sopenharmony_ci util_range_add(&rsc->base, &rsc->valid_buffer_range, 1379bf215546Sopenharmony_ci transfer->box.x + box->x, 1380bf215546Sopenharmony_ci transfer->box.x + box->x + box->width); 1381bf215546Sopenharmony_ci } else { 1382bf215546Sopenharmony_ci BITSET_SET(rsc->valid.data, transfer->level); 1383bf215546Sopenharmony_ci } 1384bf215546Sopenharmony_ci} 1385bf215546Sopenharmony_ci 1386bf215546Sopenharmony_cistatic void 1387bf215546Sopenharmony_cipanfrost_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsrc) 1388bf215546Sopenharmony_ci{ 1389bf215546Sopenharmony_ci struct panfrost_context *ctx = pan_context(pctx); 1390bf215546Sopenharmony_ci struct panfrost_batch *batch = panfrost_get_batch_for_fbo(ctx); 1391bf215546Sopenharmony_ci struct panfrost_resource *rsrc = pan_resource(prsrc); 1392bf215546Sopenharmony_ci 1393bf215546Sopenharmony_ci rsrc->constant_stencil = true; 1394bf215546Sopenharmony_ci 1395bf215546Sopenharmony_ci /* Handle the glInvalidateFramebuffer case */ 1396bf215546Sopenharmony_ci if (batch->key.zsbuf && batch->key.zsbuf->texture == prsrc) 1397bf215546Sopenharmony_ci batch->resolve &= ~PIPE_CLEAR_DEPTHSTENCIL; 1398bf215546Sopenharmony_ci 1399bf215546Sopenharmony_ci for (unsigned i = 0; i < batch->key.nr_cbufs; ++i) { 1400bf215546Sopenharmony_ci struct pipe_surface *surf = batch->key.cbufs[i]; 1401bf215546Sopenharmony_ci 1402bf215546Sopenharmony_ci if (surf && surf->texture == prsrc) 1403bf215546Sopenharmony_ci batch->resolve &= ~(PIPE_CLEAR_COLOR0 << i); 1404bf215546Sopenharmony_ci } 1405bf215546Sopenharmony_ci} 1406bf215546Sopenharmony_ci 1407bf215546Sopenharmony_cistatic enum pipe_format 1408bf215546Sopenharmony_cipanfrost_resource_get_internal_format(struct pipe_resource *rsrc) 1409bf215546Sopenharmony_ci{ 1410bf215546Sopenharmony_ci struct panfrost_resource *prsrc = (struct panfrost_resource *) rsrc; 1411bf215546Sopenharmony_ci return prsrc->image.layout.format; 1412bf215546Sopenharmony_ci} 1413bf215546Sopenharmony_ci 1414bf215546Sopenharmony_cistatic bool 1415bf215546Sopenharmony_cipanfrost_generate_mipmap( 1416bf215546Sopenharmony_ci struct pipe_context *pctx, 1417bf215546Sopenharmony_ci struct pipe_resource *prsrc, 1418bf215546Sopenharmony_ci enum pipe_format format, 1419bf215546Sopenharmony_ci unsigned base_level, 1420bf215546Sopenharmony_ci unsigned last_level, 1421bf215546Sopenharmony_ci unsigned first_layer, 1422bf215546Sopenharmony_ci unsigned last_layer) 1423bf215546Sopenharmony_ci{ 1424bf215546Sopenharmony_ci struct panfrost_resource *rsrc = pan_resource(prsrc); 1425bf215546Sopenharmony_ci 1426bf215546Sopenharmony_ci /* Generating a mipmap invalidates the written levels, so make that 1427bf215546Sopenharmony_ci * explicit so we don't try to wallpaper them back and end up with 1428bf215546Sopenharmony_ci * u_blitter recursion */ 1429bf215546Sopenharmony_ci 1430bf215546Sopenharmony_ci assert(rsrc->image.data.bo); 1431bf215546Sopenharmony_ci for (unsigned l = base_level + 1; l <= last_level; ++l) 1432bf215546Sopenharmony_ci BITSET_CLEAR(rsrc->valid.data, l); 1433bf215546Sopenharmony_ci 1434bf215546Sopenharmony_ci /* Beyond that, we just delegate the hard stuff. */ 1435bf215546Sopenharmony_ci 1436bf215546Sopenharmony_ci bool blit_res = util_gen_mipmap( 1437bf215546Sopenharmony_ci pctx, prsrc, format, 1438bf215546Sopenharmony_ci base_level, last_level, 1439bf215546Sopenharmony_ci first_layer, last_layer, 1440bf215546Sopenharmony_ci PIPE_TEX_FILTER_LINEAR); 1441bf215546Sopenharmony_ci 1442bf215546Sopenharmony_ci return blit_res; 1443bf215546Sopenharmony_ci} 1444bf215546Sopenharmony_ci 1445bf215546Sopenharmony_cistatic void 1446bf215546Sopenharmony_cipanfrost_resource_set_stencil(struct pipe_resource *prsrc, 1447bf215546Sopenharmony_ci struct pipe_resource *stencil) 1448bf215546Sopenharmony_ci{ 1449bf215546Sopenharmony_ci pan_resource(prsrc)->separate_stencil = pan_resource(stencil); 1450bf215546Sopenharmony_ci} 1451bf215546Sopenharmony_ci 1452bf215546Sopenharmony_cistatic struct pipe_resource * 1453bf215546Sopenharmony_cipanfrost_resource_get_stencil(struct pipe_resource *prsrc) 1454bf215546Sopenharmony_ci{ 1455bf215546Sopenharmony_ci if (!pan_resource(prsrc)->separate_stencil) 1456bf215546Sopenharmony_ci return NULL; 1457bf215546Sopenharmony_ci 1458bf215546Sopenharmony_ci return &pan_resource(prsrc)->separate_stencil->base; 1459bf215546Sopenharmony_ci} 1460bf215546Sopenharmony_ci 1461bf215546Sopenharmony_cistatic const struct u_transfer_vtbl transfer_vtbl = { 1462bf215546Sopenharmony_ci .resource_create = panfrost_resource_create, 1463bf215546Sopenharmony_ci .resource_destroy = panfrost_resource_destroy, 1464bf215546Sopenharmony_ci .transfer_map = panfrost_ptr_map, 1465bf215546Sopenharmony_ci .transfer_unmap = panfrost_ptr_unmap, 1466bf215546Sopenharmony_ci .transfer_flush_region = panfrost_ptr_flush_region, 1467bf215546Sopenharmony_ci .get_internal_format = panfrost_resource_get_internal_format, 1468bf215546Sopenharmony_ci .set_stencil = panfrost_resource_set_stencil, 1469bf215546Sopenharmony_ci .get_stencil = panfrost_resource_get_stencil, 1470bf215546Sopenharmony_ci}; 1471bf215546Sopenharmony_ci 1472bf215546Sopenharmony_civoid 1473bf215546Sopenharmony_cipanfrost_resource_screen_init(struct pipe_screen *pscreen) 1474bf215546Sopenharmony_ci{ 1475bf215546Sopenharmony_ci struct panfrost_device *dev = pan_device(pscreen); 1476bf215546Sopenharmony_ci 1477bf215546Sopenharmony_ci bool fake_rgtc = !panfrost_supports_compressed_format(dev, MALI_BC4_UNORM); 1478bf215546Sopenharmony_ci 1479bf215546Sopenharmony_ci pscreen->resource_create_with_modifiers = 1480bf215546Sopenharmony_ci panfrost_resource_create_with_modifiers; 1481bf215546Sopenharmony_ci pscreen->resource_create = u_transfer_helper_resource_create; 1482bf215546Sopenharmony_ci pscreen->resource_destroy = u_transfer_helper_resource_destroy; 1483bf215546Sopenharmony_ci pscreen->resource_from_handle = panfrost_resource_from_handle; 1484bf215546Sopenharmony_ci pscreen->resource_get_handle = panfrost_resource_get_handle; 1485bf215546Sopenharmony_ci pscreen->resource_get_param = panfrost_resource_get_param; 1486bf215546Sopenharmony_ci pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, 1487bf215546Sopenharmony_ci true, false, 1488bf215546Sopenharmony_ci fake_rgtc, true, false); 1489bf215546Sopenharmony_ci} 1490bf215546Sopenharmony_civoid 1491bf215546Sopenharmony_cipanfrost_resource_screen_destroy(struct pipe_screen *pscreen) 1492bf215546Sopenharmony_ci{ 1493bf215546Sopenharmony_ci u_transfer_helper_destroy(pscreen->transfer_helper); 1494bf215546Sopenharmony_ci} 1495bf215546Sopenharmony_ci 1496bf215546Sopenharmony_civoid 1497bf215546Sopenharmony_cipanfrost_resource_context_init(struct pipe_context *pctx) 1498bf215546Sopenharmony_ci{ 1499bf215546Sopenharmony_ci pctx->buffer_map = u_transfer_helper_transfer_map; 1500bf215546Sopenharmony_ci pctx->buffer_unmap = u_transfer_helper_transfer_unmap; 1501bf215546Sopenharmony_ci pctx->texture_map = u_transfer_helper_transfer_map; 1502bf215546Sopenharmony_ci pctx->texture_unmap = u_transfer_helper_transfer_unmap; 1503bf215546Sopenharmony_ci pctx->create_surface = panfrost_create_surface; 1504bf215546Sopenharmony_ci pctx->surface_destroy = panfrost_surface_destroy; 1505bf215546Sopenharmony_ci pctx->resource_copy_region = util_resource_copy_region; 1506bf215546Sopenharmony_ci pctx->blit = panfrost_blit; 1507bf215546Sopenharmony_ci pctx->generate_mipmap = panfrost_generate_mipmap; 1508bf215546Sopenharmony_ci pctx->flush_resource = panfrost_flush_resource; 1509bf215546Sopenharmony_ci pctx->invalidate_resource = panfrost_invalidate_resource; 1510bf215546Sopenharmony_ci pctx->transfer_flush_region = u_transfer_helper_transfer_flush_region; 1511bf215546Sopenharmony_ci pctx->buffer_subdata = u_default_buffer_subdata; 1512bf215546Sopenharmony_ci pctx->texture_subdata = u_default_texture_subdata; 1513bf215546Sopenharmony_ci pctx->clear_buffer = u_default_clear_buffer; 1514bf215546Sopenharmony_ci} 1515