1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (c) 2017-2019 Lima Project 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sub license, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the 12bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 13bf215546Sopenharmony_ci * of the Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include "util/u_memory.h" 26bf215546Sopenharmony_ci#include "util/u_blitter.h" 27bf215546Sopenharmony_ci#include "util/format/u_format.h" 28bf215546Sopenharmony_ci#include "util/u_inlines.h" 29bf215546Sopenharmony_ci#include "util/u_math.h" 30bf215546Sopenharmony_ci#include "util/u_debug.h" 31bf215546Sopenharmony_ci#include "util/u_transfer.h" 32bf215546Sopenharmony_ci#include "util/u_surface.h" 33bf215546Sopenharmony_ci#include "util/u_transfer_helper.h" 34bf215546Sopenharmony_ci#include "util/hash_table.h" 35bf215546Sopenharmony_ci#include "util/ralloc.h" 36bf215546Sopenharmony_ci#include "util/u_drm.h" 37bf215546Sopenharmony_ci#include "renderonly/renderonly.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "frontend/drm_driver.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h" 42bf215546Sopenharmony_ci#include "drm-uapi/lima_drm.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci#include "lima_screen.h" 45bf215546Sopenharmony_ci#include "lima_context.h" 46bf215546Sopenharmony_ci#include "lima_resource.h" 47bf215546Sopenharmony_ci#include "lima_bo.h" 48bf215546Sopenharmony_ci#include "lima_util.h" 49bf215546Sopenharmony_ci#include "lima_blit.h" 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci#include "pan_minmax_cache.h" 52bf215546Sopenharmony_ci#include "pan_tiling.h" 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic struct pipe_resource * 55bf215546Sopenharmony_cilima_resource_create_scanout(struct pipe_screen *pscreen, 56bf215546Sopenharmony_ci const struct pipe_resource *templat, 57bf215546Sopenharmony_ci unsigned width, unsigned height) 58bf215546Sopenharmony_ci{ 59bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 60bf215546Sopenharmony_ci struct renderonly_scanout *scanout; 61bf215546Sopenharmony_ci struct winsys_handle handle; 62bf215546Sopenharmony_ci struct pipe_resource *pres; 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci struct pipe_resource scanout_templat = *templat; 65bf215546Sopenharmony_ci scanout_templat.width0 = width; 66bf215546Sopenharmony_ci scanout_templat.height0 = height; 67bf215546Sopenharmony_ci scanout_templat.screen = pscreen; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci scanout = renderonly_scanout_for_resource(&scanout_templat, 70bf215546Sopenharmony_ci screen->ro, &handle); 71bf215546Sopenharmony_ci if (!scanout) 72bf215546Sopenharmony_ci return NULL; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci assert(handle.type == WINSYS_HANDLE_TYPE_FD); 75bf215546Sopenharmony_ci pres = pscreen->resource_from_handle(pscreen, templat, &handle, 76bf215546Sopenharmony_ci PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE); 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci close(handle.handle); 79bf215546Sopenharmony_ci if (!pres) { 80bf215546Sopenharmony_ci renderonly_scanout_destroy(scanout, screen->ro); 81bf215546Sopenharmony_ci return NULL; 82bf215546Sopenharmony_ci } 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 85bf215546Sopenharmony_ci res->scanout = scanout; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci return pres; 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_cistatic uint32_t 91bf215546Sopenharmony_cisetup_miptree(struct lima_resource *res, 92bf215546Sopenharmony_ci unsigned width0, unsigned height0, 93bf215546Sopenharmony_ci bool align_to_tile) 94bf215546Sopenharmony_ci{ 95bf215546Sopenharmony_ci struct pipe_resource *pres = &res->base; 96bf215546Sopenharmony_ci unsigned level; 97bf215546Sopenharmony_ci unsigned width = width0; 98bf215546Sopenharmony_ci unsigned height = height0; 99bf215546Sopenharmony_ci unsigned depth = pres->depth0; 100bf215546Sopenharmony_ci unsigned nr_samples = MAX2(pres->nr_samples, 1); 101bf215546Sopenharmony_ci uint32_t size = 0; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci for (level = 0; level <= pres->last_level; level++) { 104bf215546Sopenharmony_ci uint32_t actual_level_size; 105bf215546Sopenharmony_ci uint32_t stride; 106bf215546Sopenharmony_ci unsigned aligned_width; 107bf215546Sopenharmony_ci unsigned aligned_height; 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci if (align_to_tile) { 110bf215546Sopenharmony_ci aligned_width = align(width, 16); 111bf215546Sopenharmony_ci aligned_height = align(height, 16); 112bf215546Sopenharmony_ci } else { 113bf215546Sopenharmony_ci aligned_width = width; 114bf215546Sopenharmony_ci aligned_height = height; 115bf215546Sopenharmony_ci } 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci stride = util_format_get_stride(pres->format, aligned_width); 118bf215546Sopenharmony_ci actual_level_size = stride * 119bf215546Sopenharmony_ci util_format_get_nblocksy(pres->format, aligned_height) * 120bf215546Sopenharmony_ci pres->array_size * depth; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci res->levels[level].width = aligned_width; 123bf215546Sopenharmony_ci res->levels[level].stride = stride; 124bf215546Sopenharmony_ci res->levels[level].offset = size; 125bf215546Sopenharmony_ci res->levels[level].layer_stride = util_format_get_stride(pres->format, align(width, 16)) * align(height, 16); 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci if (util_format_is_compressed(pres->format)) 128bf215546Sopenharmony_ci res->levels[level].layer_stride /= 4; 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci size += align(actual_level_size, 64); 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci width = u_minify(width, 1); 133bf215546Sopenharmony_ci height = u_minify(height, 1); 134bf215546Sopenharmony_ci depth = u_minify(depth, 1); 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci if (nr_samples > 1) 138bf215546Sopenharmony_ci res->mrt_pitch = size; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci size *= nr_samples; 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci return size; 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic struct pipe_resource * 146bf215546Sopenharmony_cilima_resource_create_bo(struct pipe_screen *pscreen, 147bf215546Sopenharmony_ci const struct pipe_resource *templat, 148bf215546Sopenharmony_ci unsigned width, unsigned height, 149bf215546Sopenharmony_ci bool align_to_tile) 150bf215546Sopenharmony_ci{ 151bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 152bf215546Sopenharmony_ci struct lima_resource *res; 153bf215546Sopenharmony_ci struct pipe_resource *pres; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci res = CALLOC_STRUCT(lima_resource); 156bf215546Sopenharmony_ci if (!res) 157bf215546Sopenharmony_ci return NULL; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci res->base = *templat; 160bf215546Sopenharmony_ci res->base.screen = pscreen; 161bf215546Sopenharmony_ci pipe_reference_init(&res->base.reference, 1); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci pres = &res->base; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci uint32_t size = setup_miptree(res, width, height, align_to_tile); 166bf215546Sopenharmony_ci size = align(size, LIMA_PAGE_SIZE); 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci res->bo = lima_bo_create(screen, size, 0); 169bf215546Sopenharmony_ci if (!res->bo) { 170bf215546Sopenharmony_ci FREE(res); 171bf215546Sopenharmony_ci return NULL; 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci return pres; 175bf215546Sopenharmony_ci} 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_cistatic struct pipe_resource * 178bf215546Sopenharmony_ci_lima_resource_create_with_modifiers(struct pipe_screen *pscreen, 179bf215546Sopenharmony_ci const struct pipe_resource *templat, 180bf215546Sopenharmony_ci const uint64_t *modifiers, 181bf215546Sopenharmony_ci int count) 182bf215546Sopenharmony_ci{ 183bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 184bf215546Sopenharmony_ci bool should_tile = lima_debug & LIMA_DEBUG_NO_TILING ? false : true; 185bf215546Sopenharmony_ci unsigned width, height; 186bf215546Sopenharmony_ci bool has_user_modifiers = true; 187bf215546Sopenharmony_ci bool align_to_tile = false; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) 190bf215546Sopenharmony_ci has_user_modifiers = false; 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci /* VBOs/PBOs are untiled (and 1 height). */ 193bf215546Sopenharmony_ci if (templat->target == PIPE_BUFFER) 194bf215546Sopenharmony_ci should_tile = false; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT)) 197bf215546Sopenharmony_ci should_tile = false; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci /* If there's no user modifiers and buffer is shared we use linear */ 200bf215546Sopenharmony_ci if (!has_user_modifiers && (templat->bind & PIPE_BIND_SHARED)) 201bf215546Sopenharmony_ci should_tile = false; 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci if (has_user_modifiers && 204bf215546Sopenharmony_ci !drm_find_modifier(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED, 205bf215546Sopenharmony_ci modifiers, count)) 206bf215546Sopenharmony_ci should_tile = false; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci /* Don't align index, vertex or constant buffers */ 209bf215546Sopenharmony_ci if (templat->bind & (PIPE_BIND_INDEX_BUFFER | 210bf215546Sopenharmony_ci PIPE_BIND_VERTEX_BUFFER | 211bf215546Sopenharmony_ci PIPE_BIND_CONSTANT_BUFFER)) { 212bf215546Sopenharmony_ci width = templat->width0; 213bf215546Sopenharmony_ci height = templat->height0; 214bf215546Sopenharmony_ci } else { 215bf215546Sopenharmony_ci width = align(templat->width0, 16); 216bf215546Sopenharmony_ci height = align(templat->height0, 16); 217bf215546Sopenharmony_ci align_to_tile = true; 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci struct pipe_resource *pres; 221bf215546Sopenharmony_ci if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT)) 222bf215546Sopenharmony_ci pres = lima_resource_create_scanout(pscreen, templat, width, height); 223bf215546Sopenharmony_ci else 224bf215546Sopenharmony_ci pres = lima_resource_create_bo(pscreen, templat, width, height, align_to_tile); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (pres) { 227bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 228bf215546Sopenharmony_ci res->tiled = should_tile; 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci if (templat->bind & PIPE_BIND_INDEX_BUFFER) 231bf215546Sopenharmony_ci res->index_cache = CALLOC_STRUCT(panfrost_minmax_cache); 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d " 234bf215546Sopenharmony_ci "bind=%x usage=%d tile=%d last_level=%d\n", __func__, 235bf215546Sopenharmony_ci pres, pres->width0, pres->height0, pres->depth0, 236bf215546Sopenharmony_ci pres->target, pres->bind, pres->usage, should_tile, templat->last_level); 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci return pres; 239bf215546Sopenharmony_ci} 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_cistatic struct pipe_resource * 242bf215546Sopenharmony_cilima_resource_create(struct pipe_screen *pscreen, 243bf215546Sopenharmony_ci const struct pipe_resource *templat) 244bf215546Sopenharmony_ci{ 245bf215546Sopenharmony_ci const uint64_t mod = DRM_FORMAT_MOD_INVALID; 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci return _lima_resource_create_with_modifiers(pscreen, templat, &mod, 1); 248bf215546Sopenharmony_ci} 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_cistatic struct pipe_resource * 251bf215546Sopenharmony_cilima_resource_create_with_modifiers(struct pipe_screen *pscreen, 252bf215546Sopenharmony_ci const struct pipe_resource *templat, 253bf215546Sopenharmony_ci const uint64_t *modifiers, 254bf215546Sopenharmony_ci int count) 255bf215546Sopenharmony_ci{ 256bf215546Sopenharmony_ci struct pipe_resource tmpl = *templat; 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci /* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers 259bf215546Sopenharmony_ci * don't have usage parameter, but buffer created by these functions 260bf215546Sopenharmony_ci * may be used for scanout. So we assume buffer created by this 261bf215546Sopenharmony_ci * function always enable scanout if linear modifier is permitted. 262bf215546Sopenharmony_ci */ 263bf215546Sopenharmony_ci if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count)) 264bf215546Sopenharmony_ci tmpl.bind |= PIPE_BIND_SCANOUT; 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count); 267bf215546Sopenharmony_ci} 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_cistatic void 270bf215546Sopenharmony_cilima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres) 271bf215546Sopenharmony_ci{ 272bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 273bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci if (res->bo) 276bf215546Sopenharmony_ci lima_bo_unreference(res->bo); 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci if (res->scanout) 279bf215546Sopenharmony_ci renderonly_scanout_destroy(res->scanout, screen->ro); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci if (res->damage.region) 282bf215546Sopenharmony_ci FREE(res->damage.region); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci if (res->index_cache) 285bf215546Sopenharmony_ci FREE(res->index_cache); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci FREE(res); 288bf215546Sopenharmony_ci} 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_cistatic struct pipe_resource * 291bf215546Sopenharmony_cilima_resource_from_handle(struct pipe_screen *pscreen, 292bf215546Sopenharmony_ci const struct pipe_resource *templat, 293bf215546Sopenharmony_ci struct winsys_handle *handle, unsigned usage) 294bf215546Sopenharmony_ci{ 295bf215546Sopenharmony_ci if (templat->bind & (PIPE_BIND_SAMPLER_VIEW | 296bf215546Sopenharmony_ci PIPE_BIND_RENDER_TARGET | 297bf215546Sopenharmony_ci PIPE_BIND_DEPTH_STENCIL)) { 298bf215546Sopenharmony_ci /* sampler hardware need offset alignment 64, while render hardware 299bf215546Sopenharmony_ci * need offset alignment 8, but due to render target may be reloaded 300bf215546Sopenharmony_ci * which uses the sampler, set alignment requrement to 64 for all 301bf215546Sopenharmony_ci */ 302bf215546Sopenharmony_ci if (handle->offset & 0x3f) { 303bf215546Sopenharmony_ci debug_error("import buffer offset not properly aligned\n"); 304bf215546Sopenharmony_ci return NULL; 305bf215546Sopenharmony_ci } 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci struct lima_resource *res = CALLOC_STRUCT(lima_resource); 309bf215546Sopenharmony_ci if (!res) 310bf215546Sopenharmony_ci return NULL; 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci struct pipe_resource *pres = &res->base; 313bf215546Sopenharmony_ci *pres = *templat; 314bf215546Sopenharmony_ci pres->screen = pscreen; 315bf215546Sopenharmony_ci pipe_reference_init(&pres->reference, 1); 316bf215546Sopenharmony_ci res->levels[0].offset = handle->offset; 317bf215546Sopenharmony_ci res->levels[0].stride = handle->stride; 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 320bf215546Sopenharmony_ci res->bo = lima_bo_import(screen, handle); 321bf215546Sopenharmony_ci if (!res->bo) { 322bf215546Sopenharmony_ci FREE(res); 323bf215546Sopenharmony_ci return NULL; 324bf215546Sopenharmony_ci } 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci res->modifier_constant = true; 327bf215546Sopenharmony_ci 328bf215546Sopenharmony_ci switch (handle->modifier) { 329bf215546Sopenharmony_ci case DRM_FORMAT_MOD_LINEAR: 330bf215546Sopenharmony_ci res->tiled = false; 331bf215546Sopenharmony_ci break; 332bf215546Sopenharmony_ci case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED: 333bf215546Sopenharmony_ci res->tiled = true; 334bf215546Sopenharmony_ci break; 335bf215546Sopenharmony_ci case DRM_FORMAT_MOD_INVALID: 336bf215546Sopenharmony_ci /* Modifier wasn't specified and it's shared buffer. We create these 337bf215546Sopenharmony_ci * as linear, so disable tiling. 338bf215546Sopenharmony_ci */ 339bf215546Sopenharmony_ci res->tiled = false; 340bf215546Sopenharmony_ci break; 341bf215546Sopenharmony_ci default: 342bf215546Sopenharmony_ci fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n", 343bf215546Sopenharmony_ci (long long)handle->modifier); 344bf215546Sopenharmony_ci goto err_out; 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci /* check alignment for the buffer */ 348bf215546Sopenharmony_ci if (res->tiled || 349bf215546Sopenharmony_ci (pres->bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL))) { 350bf215546Sopenharmony_ci unsigned width, height, stride, size; 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci width = align(pres->width0, 16); 353bf215546Sopenharmony_ci height = align(pres->height0, 16); 354bf215546Sopenharmony_ci stride = util_format_get_stride(pres->format, width); 355bf215546Sopenharmony_ci size = util_format_get_2d_size(pres->format, stride, height); 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci if (res->tiled && res->levels[0].stride != stride) { 358bf215546Sopenharmony_ci fprintf(stderr, "tiled imported buffer has mismatching stride: %d (BO) != %d (expected)", 359bf215546Sopenharmony_ci res->levels[0].stride, stride); 360bf215546Sopenharmony_ci goto err_out; 361bf215546Sopenharmony_ci } 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci if (!res->tiled && (res->levels[0].stride % 8)) { 364bf215546Sopenharmony_ci fprintf(stderr, "linear imported buffer stride is not aligned to 8 bytes: %d\n", 365bf215546Sopenharmony_ci res->levels[0].stride); 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci if (!res->tiled && res->levels[0].stride < stride) { 369bf215546Sopenharmony_ci fprintf(stderr, "linear imported buffer stride is smaller than minimal: %d (BO) < %d (min)", 370bf215546Sopenharmony_ci res->levels[0].stride, stride); 371bf215546Sopenharmony_ci goto err_out; 372bf215546Sopenharmony_ci } 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci if ((res->bo->size - res->levels[0].offset) < size) { 375bf215546Sopenharmony_ci fprintf(stderr, "imported bo size is smaller than expected: %d (BO) < %d (expected)\n", 376bf215546Sopenharmony_ci (res->bo->size - res->levels[0].offset), size); 377bf215546Sopenharmony_ci goto err_out; 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci res->levels[0].width = width; 381bf215546Sopenharmony_ci } 382bf215546Sopenharmony_ci else 383bf215546Sopenharmony_ci res->levels[0].width = pres->width0; 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci if (screen->ro) { 386bf215546Sopenharmony_ci /* Make sure that renderonly has a handle to our buffer in the 387bf215546Sopenharmony_ci * display's fd, so that a later renderonly_get_handle() 388bf215546Sopenharmony_ci * returns correct handles or GEM names. 389bf215546Sopenharmony_ci */ 390bf215546Sopenharmony_ci res->scanout = 391bf215546Sopenharmony_ci renderonly_create_gpu_import_for_resource(pres, 392bf215546Sopenharmony_ci screen->ro, 393bf215546Sopenharmony_ci NULL); 394bf215546Sopenharmony_ci /* ignore failiure to allow importing non-displayable buffer */ 395bf215546Sopenharmony_ci } 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci return pres; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_cierr_out: 400bf215546Sopenharmony_ci lima_resource_destroy(pscreen, pres); 401bf215546Sopenharmony_ci return NULL; 402bf215546Sopenharmony_ci} 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_cistatic bool 405bf215546Sopenharmony_cilima_resource_get_handle(struct pipe_screen *pscreen, 406bf215546Sopenharmony_ci struct pipe_context *pctx, 407bf215546Sopenharmony_ci struct pipe_resource *pres, 408bf215546Sopenharmony_ci struct winsys_handle *handle, unsigned usage) 409bf215546Sopenharmony_ci{ 410bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pscreen); 411bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci if (res->tiled) 414bf215546Sopenharmony_ci handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 415bf215546Sopenharmony_ci else 416bf215546Sopenharmony_ci handle->modifier = DRM_FORMAT_MOD_LINEAR; 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci res->modifier_constant = true; 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro) 421bf215546Sopenharmony_ci return renderonly_get_handle(res->scanout, handle); 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci if (!lima_bo_export(res->bo, handle)) 424bf215546Sopenharmony_ci return false; 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci handle->offset = res->levels[0].offset; 427bf215546Sopenharmony_ci handle->stride = res->levels[0].stride; 428bf215546Sopenharmony_ci return true; 429bf215546Sopenharmony_ci} 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_cistatic bool 432bf215546Sopenharmony_cilima_resource_get_param(struct pipe_screen *pscreen, 433bf215546Sopenharmony_ci struct pipe_context *pctx, 434bf215546Sopenharmony_ci struct pipe_resource *pres, 435bf215546Sopenharmony_ci unsigned plane, unsigned layer, unsigned level, 436bf215546Sopenharmony_ci enum pipe_resource_param param, 437bf215546Sopenharmony_ci unsigned usage, uint64_t *value) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci switch (param) { 442bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_STRIDE: 443bf215546Sopenharmony_ci *value = res->levels[level].stride; 444bf215546Sopenharmony_ci return true; 445bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_OFFSET: 446bf215546Sopenharmony_ci *value = res->levels[level].offset; 447bf215546Sopenharmony_ci return true; 448bf215546Sopenharmony_ci case PIPE_RESOURCE_PARAM_MODIFIER: 449bf215546Sopenharmony_ci if (res->tiled) 450bf215546Sopenharmony_ci *value = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 451bf215546Sopenharmony_ci else 452bf215546Sopenharmony_ci *value = DRM_FORMAT_MOD_LINEAR; 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci return true; 455bf215546Sopenharmony_ci default: 456bf215546Sopenharmony_ci return false; 457bf215546Sopenharmony_ci } 458bf215546Sopenharmony_ci} 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_cistatic void 461bf215546Sopenharmony_ciget_scissor_from_box(struct pipe_scissor_state *s, 462bf215546Sopenharmony_ci const struct pipe_box *b, int h) 463bf215546Sopenharmony_ci{ 464bf215546Sopenharmony_ci int y = h - (b->y + b->height); 465bf215546Sopenharmony_ci /* region in tile unit */ 466bf215546Sopenharmony_ci s->minx = b->x >> 4; 467bf215546Sopenharmony_ci s->miny = y >> 4; 468bf215546Sopenharmony_ci s->maxx = (b->x + b->width + 0xf) >> 4; 469bf215546Sopenharmony_ci s->maxy = (y + b->height + 0xf) >> 4; 470bf215546Sopenharmony_ci} 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_cistatic void 473bf215546Sopenharmony_ciget_damage_bound_box(struct pipe_resource *pres, 474bf215546Sopenharmony_ci const struct pipe_box *rects, 475bf215546Sopenharmony_ci unsigned int nrects, 476bf215546Sopenharmony_ci struct pipe_scissor_state *bound) 477bf215546Sopenharmony_ci{ 478bf215546Sopenharmony_ci struct pipe_box b = rects[0]; 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci for (int i = 1; i < nrects; i++) 481bf215546Sopenharmony_ci u_box_union_2d(&b, &b, rects + i); 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0); 484bf215546Sopenharmony_ci if (ret < 0) 485bf215546Sopenharmony_ci memset(bound, 0, sizeof(*bound)); 486bf215546Sopenharmony_ci else 487bf215546Sopenharmony_ci get_scissor_from_box(bound, &b, pres->height0); 488bf215546Sopenharmony_ci} 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_cistatic void 491bf215546Sopenharmony_cilima_resource_set_damage_region(struct pipe_screen *pscreen, 492bf215546Sopenharmony_ci struct pipe_resource *pres, 493bf215546Sopenharmony_ci unsigned int nrects, 494bf215546Sopenharmony_ci const struct pipe_box *rects) 495bf215546Sopenharmony_ci{ 496bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 497bf215546Sopenharmony_ci struct lima_damage_region *damage = &res->damage; 498bf215546Sopenharmony_ci int i; 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_ci if (damage->region) { 501bf215546Sopenharmony_ci FREE(damage->region); 502bf215546Sopenharmony_ci damage->region = NULL; 503bf215546Sopenharmony_ci damage->num_region = 0; 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci if (!nrects) 507bf215546Sopenharmony_ci return; 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_ci /* check full damage 510bf215546Sopenharmony_ci * 511bf215546Sopenharmony_ci * TODO: currently only check if there is any single damage 512bf215546Sopenharmony_ci * region that can cover the full render target; there may 513bf215546Sopenharmony_ci * be some accurate way, but a single window size damage 514bf215546Sopenharmony_ci * region is most of the case from weston 515bf215546Sopenharmony_ci */ 516bf215546Sopenharmony_ci for (i = 0; i < nrects; i++) { 517bf215546Sopenharmony_ci if (rects[i].x <= 0 && rects[i].y <= 0 && 518bf215546Sopenharmony_ci rects[i].x + rects[i].width >= pres->width0 && 519bf215546Sopenharmony_ci rects[i].y + rects[i].height >= pres->height0) 520bf215546Sopenharmony_ci return; 521bf215546Sopenharmony_ci } 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci struct pipe_scissor_state *bound = &damage->bound; 524bf215546Sopenharmony_ci get_damage_bound_box(pres, rects, nrects, bound); 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci damage->region = CALLOC(nrects, sizeof(*damage->region)); 527bf215546Sopenharmony_ci if (!damage->region) 528bf215546Sopenharmony_ci return; 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_ci for (i = 0; i < nrects; i++) 531bf215546Sopenharmony_ci get_scissor_from_box(damage->region + i, rects + i, 532bf215546Sopenharmony_ci pres->height0); 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci /* is region aligned to tiles? */ 535bf215546Sopenharmony_ci damage->aligned = true; 536bf215546Sopenharmony_ci for (i = 0; i < nrects; i++) { 537bf215546Sopenharmony_ci if (rects[i].x & 0xf || rects[i].y & 0xf || 538bf215546Sopenharmony_ci rects[i].width & 0xf || rects[i].height & 0xf) { 539bf215546Sopenharmony_ci damage->aligned = false; 540bf215546Sopenharmony_ci break; 541bf215546Sopenharmony_ci } 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci damage->num_region = nrects; 545bf215546Sopenharmony_ci} 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_cistatic struct pipe_surface * 548bf215546Sopenharmony_cilima_surface_create(struct pipe_context *pctx, 549bf215546Sopenharmony_ci struct pipe_resource *pres, 550bf215546Sopenharmony_ci const struct pipe_surface *surf_tmpl) 551bf215546Sopenharmony_ci{ 552bf215546Sopenharmony_ci struct lima_surface *surf = CALLOC_STRUCT(lima_surface); 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci if (!surf) 555bf215546Sopenharmony_ci return NULL; 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_ci assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer); 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ci struct pipe_surface *psurf = &surf->base; 560bf215546Sopenharmony_ci unsigned level = surf_tmpl->u.tex.level; 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci pipe_reference_init(&psurf->reference, 1); 563bf215546Sopenharmony_ci pipe_resource_reference(&psurf->texture, pres); 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci psurf->context = pctx; 566bf215546Sopenharmony_ci psurf->format = surf_tmpl->format; 567bf215546Sopenharmony_ci psurf->width = u_minify(pres->width0, level); 568bf215546Sopenharmony_ci psurf->height = u_minify(pres->height0, level); 569bf215546Sopenharmony_ci psurf->nr_samples = surf_tmpl->nr_samples; 570bf215546Sopenharmony_ci psurf->u.tex.level = level; 571bf215546Sopenharmony_ci psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer; 572bf215546Sopenharmony_ci psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer; 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci surf->tiled_w = align(psurf->width, 16) >> 4; 575bf215546Sopenharmony_ci surf->tiled_h = align(psurf->height, 16) >> 4; 576bf215546Sopenharmony_ci 577bf215546Sopenharmony_ci surf->reload = 0; 578bf215546Sopenharmony_ci if (util_format_has_stencil(util_format_description(psurf->format))) 579bf215546Sopenharmony_ci surf->reload |= PIPE_CLEAR_STENCIL; 580bf215546Sopenharmony_ci if (util_format_has_depth(util_format_description(psurf->format))) 581bf215546Sopenharmony_ci surf->reload |= PIPE_CLEAR_DEPTH; 582bf215546Sopenharmony_ci if (!util_format_is_depth_or_stencil(psurf->format)) 583bf215546Sopenharmony_ci surf->reload |= PIPE_CLEAR_COLOR0; 584bf215546Sopenharmony_ci 585bf215546Sopenharmony_ci return &surf->base; 586bf215546Sopenharmony_ci} 587bf215546Sopenharmony_ci 588bf215546Sopenharmony_cistatic void 589bf215546Sopenharmony_cilima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf) 590bf215546Sopenharmony_ci{ 591bf215546Sopenharmony_ci struct lima_surface *surf = lima_surface(psurf); 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci pipe_resource_reference(&psurf->texture, NULL); 594bf215546Sopenharmony_ci FREE(surf); 595bf215546Sopenharmony_ci} 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_cistatic void * 598bf215546Sopenharmony_cilima_transfer_map(struct pipe_context *pctx, 599bf215546Sopenharmony_ci struct pipe_resource *pres, 600bf215546Sopenharmony_ci unsigned level, 601bf215546Sopenharmony_ci unsigned usage, 602bf215546Sopenharmony_ci const struct pipe_box *box, 603bf215546Sopenharmony_ci struct pipe_transfer **pptrans) 604bf215546Sopenharmony_ci{ 605bf215546Sopenharmony_ci struct lima_screen *screen = lima_screen(pres->screen); 606bf215546Sopenharmony_ci struct lima_context *ctx = lima_context(pctx); 607bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(pres); 608bf215546Sopenharmony_ci struct lima_bo *bo = res->bo; 609bf215546Sopenharmony_ci struct lima_transfer *trans; 610bf215546Sopenharmony_ci struct pipe_transfer *ptrans; 611bf215546Sopenharmony_ci 612bf215546Sopenharmony_ci /* No direct mappings of tiled, since we need to manually 613bf215546Sopenharmony_ci * tile/untile. 614bf215546Sopenharmony_ci */ 615bf215546Sopenharmony_ci if (res->tiled && (usage & PIPE_MAP_DIRECTLY)) 616bf215546Sopenharmony_ci return NULL; 617bf215546Sopenharmony_ci 618bf215546Sopenharmony_ci /* bo might be in use in a previous stream draw. Allocate a new 619bf215546Sopenharmony_ci * one for the resource to avoid overwriting data in use. */ 620bf215546Sopenharmony_ci if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE) { 621bf215546Sopenharmony_ci struct lima_bo *new_bo; 622bf215546Sopenharmony_ci assert(res->bo && res->bo->size); 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci new_bo = lima_bo_create(screen, res->bo->size, res->bo->flags); 625bf215546Sopenharmony_ci if (!new_bo) 626bf215546Sopenharmony_ci return NULL; 627bf215546Sopenharmony_ci 628bf215546Sopenharmony_ci lima_bo_unreference(res->bo); 629bf215546Sopenharmony_ci res->bo = new_bo; 630bf215546Sopenharmony_ci 631bf215546Sopenharmony_ci if (pres->bind & PIPE_BIND_VERTEX_BUFFER) 632bf215546Sopenharmony_ci ctx->dirty |= LIMA_CONTEXT_DIRTY_VERTEX_BUFF; 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci bo = res->bo; 635bf215546Sopenharmony_ci } 636bf215546Sopenharmony_ci else if (!(usage & PIPE_MAP_UNSYNCHRONIZED) && 637bf215546Sopenharmony_ci (usage & PIPE_MAP_READ_WRITE)) { 638bf215546Sopenharmony_ci /* use once buffers are made sure to not read/write overlapped 639bf215546Sopenharmony_ci * range, so no need to sync */ 640bf215546Sopenharmony_ci lima_flush_job_accessing_bo(ctx, bo, usage & PIPE_MAP_WRITE); 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_ci unsigned op = usage & PIPE_MAP_WRITE ? 643bf215546Sopenharmony_ci LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ; 644bf215546Sopenharmony_ci lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE); 645bf215546Sopenharmony_ci } 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci if (!lima_bo_map(bo)) 648bf215546Sopenharmony_ci return NULL; 649bf215546Sopenharmony_ci 650bf215546Sopenharmony_ci trans = slab_zalloc(&ctx->transfer_pool); 651bf215546Sopenharmony_ci if (!trans) 652bf215546Sopenharmony_ci return NULL; 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_ci ptrans = &trans->base; 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, pres); 657bf215546Sopenharmony_ci ptrans->level = level; 658bf215546Sopenharmony_ci ptrans->usage = usage; 659bf215546Sopenharmony_ci ptrans->box = *box; 660bf215546Sopenharmony_ci 661bf215546Sopenharmony_ci *pptrans = ptrans; 662bf215546Sopenharmony_ci 663bf215546Sopenharmony_ci if (res->tiled) { 664bf215546Sopenharmony_ci ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width); 665bf215546Sopenharmony_ci ptrans->layer_stride = ptrans->stride * ptrans->box.height; 666bf215546Sopenharmony_ci 667bf215546Sopenharmony_ci trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth); 668bf215546Sopenharmony_ci 669bf215546Sopenharmony_ci if (usage & PIPE_MAP_READ) { 670bf215546Sopenharmony_ci unsigned line_stride = res->levels[level].stride; 671bf215546Sopenharmony_ci unsigned row_height = util_format_is_compressed(pres->format) ? 4 : 16; 672bf215546Sopenharmony_ci unsigned row_stride = line_stride * row_height; 673bf215546Sopenharmony_ci 674bf215546Sopenharmony_ci unsigned i; 675bf215546Sopenharmony_ci for (i = 0; i < ptrans->box.depth; i++) 676bf215546Sopenharmony_ci panfrost_load_tiled_image( 677bf215546Sopenharmony_ci trans->staging + i * ptrans->stride * ptrans->box.height, 678bf215546Sopenharmony_ci bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride, 679bf215546Sopenharmony_ci ptrans->box.x, ptrans->box.y, 680bf215546Sopenharmony_ci ptrans->box.width, ptrans->box.height, 681bf215546Sopenharmony_ci ptrans->stride, 682bf215546Sopenharmony_ci row_stride, 683bf215546Sopenharmony_ci pres->format); 684bf215546Sopenharmony_ci } 685bf215546Sopenharmony_ci 686bf215546Sopenharmony_ci return trans->staging; 687bf215546Sopenharmony_ci } else { 688bf215546Sopenharmony_ci unsigned dpw = PIPE_MAP_DIRECTLY | PIPE_MAP_WRITE | 689bf215546Sopenharmony_ci PIPE_MAP_PERSISTENT; 690bf215546Sopenharmony_ci if ((usage & dpw) == dpw && res->index_cache) 691bf215546Sopenharmony_ci return NULL; 692bf215546Sopenharmony_ci 693bf215546Sopenharmony_ci ptrans->stride = res->levels[level].stride; 694bf215546Sopenharmony_ci ptrans->layer_stride = res->levels[level].layer_stride; 695bf215546Sopenharmony_ci 696bf215546Sopenharmony_ci if ((usage & PIPE_MAP_WRITE) && (usage & PIPE_MAP_DIRECTLY)) 697bf215546Sopenharmony_ci panfrost_minmax_cache_invalidate(res->index_cache, ptrans); 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci return bo->map + res->levels[level].offset + 700bf215546Sopenharmony_ci box->z * res->levels[level].layer_stride + 701bf215546Sopenharmony_ci box->y / util_format_get_blockheight(pres->format) * ptrans->stride + 702bf215546Sopenharmony_ci box->x / util_format_get_blockwidth(pres->format) * 703bf215546Sopenharmony_ci util_format_get_blocksize(pres->format); 704bf215546Sopenharmony_ci } 705bf215546Sopenharmony_ci} 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_cistatic bool 708bf215546Sopenharmony_cilima_should_convert_linear(struct lima_resource *res, 709bf215546Sopenharmony_ci struct pipe_transfer *ptrans) 710bf215546Sopenharmony_ci{ 711bf215546Sopenharmony_ci if (res->modifier_constant) 712bf215546Sopenharmony_ci return false; 713bf215546Sopenharmony_ci 714bf215546Sopenharmony_ci /* Overwriting the entire resource indicates streaming, for which 715bf215546Sopenharmony_ci * linear layout is most efficient due to the lack of expensive 716bf215546Sopenharmony_ci * conversion. 717bf215546Sopenharmony_ci * 718bf215546Sopenharmony_ci * For now we just switch to linear after a number of complete 719bf215546Sopenharmony_ci * overwrites to keep things simple, but we could do better. 720bf215546Sopenharmony_ci */ 721bf215546Sopenharmony_ci 722bf215546Sopenharmony_ci unsigned depth = res->base.target == PIPE_TEXTURE_3D ? 723bf215546Sopenharmony_ci res->base.depth0 : res->base.array_size; 724bf215546Sopenharmony_ci bool entire_overwrite = 725bf215546Sopenharmony_ci res->base.last_level == 0 && 726bf215546Sopenharmony_ci ptrans->box.width == res->base.width0 && 727bf215546Sopenharmony_ci ptrans->box.height == res->base.height0 && 728bf215546Sopenharmony_ci ptrans->box.depth == depth && 729bf215546Sopenharmony_ci ptrans->box.x == 0 && 730bf215546Sopenharmony_ci ptrans->box.y == 0 && 731bf215546Sopenharmony_ci ptrans->box.z == 0; 732bf215546Sopenharmony_ci 733bf215546Sopenharmony_ci if (entire_overwrite) 734bf215546Sopenharmony_ci ++res->full_updates; 735bf215546Sopenharmony_ci 736bf215546Sopenharmony_ci return res->full_updates >= LAYOUT_CONVERT_THRESHOLD; 737bf215546Sopenharmony_ci} 738bf215546Sopenharmony_ci 739bf215546Sopenharmony_cistatic void 740bf215546Sopenharmony_cilima_transfer_flush_region(struct pipe_context *pctx, 741bf215546Sopenharmony_ci struct pipe_transfer *ptrans, 742bf215546Sopenharmony_ci const struct pipe_box *box) 743bf215546Sopenharmony_ci{ 744bf215546Sopenharmony_ci struct lima_context *ctx = lima_context(pctx); 745bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(ptrans->resource); 746bf215546Sopenharmony_ci struct lima_transfer *trans = lima_transfer(ptrans); 747bf215546Sopenharmony_ci struct lima_bo *bo = res->bo; 748bf215546Sopenharmony_ci struct pipe_resource *pres; 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci if (trans->staging) { 751bf215546Sopenharmony_ci pres = &res->base; 752bf215546Sopenharmony_ci if (trans->base.usage & PIPE_MAP_WRITE) { 753bf215546Sopenharmony_ci unsigned i; 754bf215546Sopenharmony_ci if (lima_should_convert_linear(res, ptrans)) { 755bf215546Sopenharmony_ci /* It's safe to re-use the same BO since tiled BO always has 756bf215546Sopenharmony_ci * aligned dimensions */ 757bf215546Sopenharmony_ci for (i = 0; i < trans->base.box.depth; i++) { 758bf215546Sopenharmony_ci util_copy_rect(bo->map + res->levels[0].offset + 759bf215546Sopenharmony_ci (i + trans->base.box.z) * res->levels[0].stride, 760bf215546Sopenharmony_ci res->base.format, 761bf215546Sopenharmony_ci res->levels[0].stride, 762bf215546Sopenharmony_ci 0, 0, 763bf215546Sopenharmony_ci ptrans->box.width, 764bf215546Sopenharmony_ci ptrans->box.height, 765bf215546Sopenharmony_ci trans->staging + i * ptrans->stride * ptrans->box.height, 766bf215546Sopenharmony_ci ptrans->stride, 767bf215546Sopenharmony_ci 0, 0); 768bf215546Sopenharmony_ci } 769bf215546Sopenharmony_ci res->tiled = false; 770bf215546Sopenharmony_ci res->modifier_constant = true; 771bf215546Sopenharmony_ci /* Update texture descriptor */ 772bf215546Sopenharmony_ci ctx->dirty |= LIMA_CONTEXT_DIRTY_TEXTURES; 773bf215546Sopenharmony_ci } else { 774bf215546Sopenharmony_ci unsigned line_stride = res->levels[ptrans->level].stride; 775bf215546Sopenharmony_ci unsigned row_height = util_format_is_compressed(pres->format) ? 4 : 16; 776bf215546Sopenharmony_ci unsigned row_stride = line_stride * row_height; 777bf215546Sopenharmony_ci 778bf215546Sopenharmony_ci for (i = 0; i < trans->base.box.depth; i++) 779bf215546Sopenharmony_ci panfrost_store_tiled_image( 780bf215546Sopenharmony_ci bo->map + res->levels[trans->base.level].offset + (i + trans->base.box.z) * res->levels[trans->base.level].layer_stride, 781bf215546Sopenharmony_ci trans->staging + i * ptrans->stride * ptrans->box.height, 782bf215546Sopenharmony_ci ptrans->box.x, ptrans->box.y, 783bf215546Sopenharmony_ci ptrans->box.width, ptrans->box.height, 784bf215546Sopenharmony_ci row_stride, 785bf215546Sopenharmony_ci ptrans->stride, 786bf215546Sopenharmony_ci pres->format); 787bf215546Sopenharmony_ci } 788bf215546Sopenharmony_ci } 789bf215546Sopenharmony_ci } 790bf215546Sopenharmony_ci} 791bf215546Sopenharmony_ci 792bf215546Sopenharmony_cistatic void 793bf215546Sopenharmony_cilima_transfer_unmap(struct pipe_context *pctx, 794bf215546Sopenharmony_ci struct pipe_transfer *ptrans) 795bf215546Sopenharmony_ci{ 796bf215546Sopenharmony_ci struct lima_context *ctx = lima_context(pctx); 797bf215546Sopenharmony_ci struct lima_transfer *trans = lima_transfer(ptrans); 798bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(ptrans->resource); 799bf215546Sopenharmony_ci 800bf215546Sopenharmony_ci struct pipe_box box; 801bf215546Sopenharmony_ci u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); 802bf215546Sopenharmony_ci lima_transfer_flush_region(pctx, ptrans, &box); 803bf215546Sopenharmony_ci if (trans->staging) 804bf215546Sopenharmony_ci free(trans->staging); 805bf215546Sopenharmony_ci panfrost_minmax_cache_invalidate(res->index_cache, ptrans); 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci pipe_resource_reference(&ptrans->resource, NULL); 808bf215546Sopenharmony_ci slab_free(&ctx->transfer_pool, trans); 809bf215546Sopenharmony_ci} 810bf215546Sopenharmony_ci 811bf215546Sopenharmony_cistatic void 812bf215546Sopenharmony_cilima_util_blitter_save_states(struct lima_context *ctx) 813bf215546Sopenharmony_ci{ 814bf215546Sopenharmony_ci util_blitter_save_blend(ctx->blitter, (void *)ctx->blend); 815bf215546Sopenharmony_ci util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa); 816bf215546Sopenharmony_ci util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref); 817bf215546Sopenharmony_ci util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer); 818bf215546Sopenharmony_ci util_blitter_save_fragment_shader(ctx->blitter, ctx->uncomp_fs); 819bf215546Sopenharmony_ci util_blitter_save_vertex_shader(ctx->blitter, ctx->uncomp_vs); 820bf215546Sopenharmony_ci util_blitter_save_viewport(ctx->blitter, 821bf215546Sopenharmony_ci &ctx->viewport.transform); 822bf215546Sopenharmony_ci util_blitter_save_scissor(ctx->blitter, &ctx->scissor); 823bf215546Sopenharmony_ci util_blitter_save_vertex_elements(ctx->blitter, 824bf215546Sopenharmony_ci ctx->vertex_elements); 825bf215546Sopenharmony_ci util_blitter_save_vertex_buffer_slot(ctx->blitter, 826bf215546Sopenharmony_ci ctx->vertex_buffers.vb); 827bf215546Sopenharmony_ci 828bf215546Sopenharmony_ci util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base); 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_ci util_blitter_save_fragment_sampler_states(ctx->blitter, 831bf215546Sopenharmony_ci ctx->tex_stateobj.num_samplers, 832bf215546Sopenharmony_ci (void**)ctx->tex_stateobj.samplers); 833bf215546Sopenharmony_ci util_blitter_save_fragment_sampler_views(ctx->blitter, 834bf215546Sopenharmony_ci ctx->tex_stateobj.num_textures, 835bf215546Sopenharmony_ci ctx->tex_stateobj.textures); 836bf215546Sopenharmony_ci} 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_cistatic void 839bf215546Sopenharmony_cilima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) 840bf215546Sopenharmony_ci{ 841bf215546Sopenharmony_ci struct lima_context *ctx = lima_context(pctx); 842bf215546Sopenharmony_ci struct pipe_blit_info info = *blit_info; 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci if (lima_do_blit(pctx, blit_info)) { 845bf215546Sopenharmony_ci return; 846bf215546Sopenharmony_ci } 847bf215546Sopenharmony_ci 848bf215546Sopenharmony_ci if (util_try_blit_via_copy_region(pctx, &info, false)) { 849bf215546Sopenharmony_ci return; /* done */ 850bf215546Sopenharmony_ci } 851bf215546Sopenharmony_ci 852bf215546Sopenharmony_ci if (info.mask & PIPE_MASK_S) { 853bf215546Sopenharmony_ci debug_printf("lima: cannot blit stencil, skipping\n"); 854bf215546Sopenharmony_ci info.mask &= ~PIPE_MASK_S; 855bf215546Sopenharmony_ci } 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_ci if (!util_blitter_is_blit_supported(ctx->blitter, &info)) { 858bf215546Sopenharmony_ci debug_printf("lima: blit unsupported %s -> %s\n", 859bf215546Sopenharmony_ci util_format_short_name(info.src.resource->format), 860bf215546Sopenharmony_ci util_format_short_name(info.dst.resource->format)); 861bf215546Sopenharmony_ci return; 862bf215546Sopenharmony_ci } 863bf215546Sopenharmony_ci 864bf215546Sopenharmony_ci lima_util_blitter_save_states(ctx); 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_ci util_blitter_blit(ctx->blitter, &info); 867bf215546Sopenharmony_ci} 868bf215546Sopenharmony_ci 869bf215546Sopenharmony_cistatic void 870bf215546Sopenharmony_cilima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource) 871bf215546Sopenharmony_ci{ 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci} 874bf215546Sopenharmony_ci 875bf215546Sopenharmony_cistatic void 876bf215546Sopenharmony_cilima_texture_subdata(struct pipe_context *pctx, 877bf215546Sopenharmony_ci struct pipe_resource *prsc, 878bf215546Sopenharmony_ci unsigned level, 879bf215546Sopenharmony_ci unsigned usage, 880bf215546Sopenharmony_ci const struct pipe_box *box, 881bf215546Sopenharmony_ci const void *data, 882bf215546Sopenharmony_ci unsigned stride, 883bf215546Sopenharmony_ci unsigned layer_stride) 884bf215546Sopenharmony_ci{ 885bf215546Sopenharmony_ci struct lima_context *ctx = lima_context(pctx); 886bf215546Sopenharmony_ci struct lima_resource *res = lima_resource(prsc); 887bf215546Sopenharmony_ci 888bf215546Sopenharmony_ci if (!res->tiled) { 889bf215546Sopenharmony_ci u_default_texture_subdata(pctx, prsc, level, usage, box, 890bf215546Sopenharmony_ci data, stride, layer_stride); 891bf215546Sopenharmony_ci return; 892bf215546Sopenharmony_ci } 893bf215546Sopenharmony_ci 894bf215546Sopenharmony_ci assert(!(usage & PIPE_MAP_READ)); 895bf215546Sopenharmony_ci 896bf215546Sopenharmony_ci struct lima_transfer t = { 897bf215546Sopenharmony_ci .base = { 898bf215546Sopenharmony_ci .resource = prsc, 899bf215546Sopenharmony_ci .usage = PIPE_MAP_WRITE, 900bf215546Sopenharmony_ci .level = level, 901bf215546Sopenharmony_ci .box = *box, 902bf215546Sopenharmony_ci .stride = stride, 903bf215546Sopenharmony_ci .layer_stride = layer_stride, 904bf215546Sopenharmony_ci }, 905bf215546Sopenharmony_ci .staging = (void *)data, 906bf215546Sopenharmony_ci }; 907bf215546Sopenharmony_ci 908bf215546Sopenharmony_ci lima_flush_job_accessing_bo(ctx, res->bo, true); 909bf215546Sopenharmony_ci lima_bo_wait(res->bo, LIMA_GEM_WAIT_WRITE, PIPE_TIMEOUT_INFINITE); 910bf215546Sopenharmony_ci if (!lima_bo_map(res->bo)) 911bf215546Sopenharmony_ci return; 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci struct pipe_box tbox; 914bf215546Sopenharmony_ci u_box_2d(0, 0, t.base.box.width, t.base.box.height, &tbox); 915bf215546Sopenharmony_ci lima_transfer_flush_region(pctx, &t.base, &tbox); 916bf215546Sopenharmony_ci} 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_cistatic const struct u_transfer_vtbl transfer_vtbl = { 919bf215546Sopenharmony_ci .resource_create = lima_resource_create, 920bf215546Sopenharmony_ci .resource_destroy = lima_resource_destroy, 921bf215546Sopenharmony_ci .transfer_map = lima_transfer_map, 922bf215546Sopenharmony_ci .transfer_unmap = lima_transfer_unmap, 923bf215546Sopenharmony_ci .transfer_flush_region = lima_transfer_flush_region, 924bf215546Sopenharmony_ci}; 925bf215546Sopenharmony_ci 926bf215546Sopenharmony_civoid 927bf215546Sopenharmony_cilima_resource_screen_init(struct lima_screen *screen) 928bf215546Sopenharmony_ci{ 929bf215546Sopenharmony_ci screen->base.resource_create = lima_resource_create; 930bf215546Sopenharmony_ci screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers; 931bf215546Sopenharmony_ci screen->base.resource_from_handle = lima_resource_from_handle; 932bf215546Sopenharmony_ci screen->base.resource_destroy = lima_resource_destroy; 933bf215546Sopenharmony_ci screen->base.resource_get_handle = lima_resource_get_handle; 934bf215546Sopenharmony_ci screen->base.resource_get_param = lima_resource_get_param; 935bf215546Sopenharmony_ci screen->base.set_damage_region = lima_resource_set_damage_region; 936bf215546Sopenharmony_ci screen->base.transfer_helper = u_transfer_helper_create(&transfer_vtbl, 937bf215546Sopenharmony_ci false, false, 938bf215546Sopenharmony_ci false, true, 939bf215546Sopenharmony_ci false); 940bf215546Sopenharmony_ci} 941bf215546Sopenharmony_ci 942bf215546Sopenharmony_civoid 943bf215546Sopenharmony_cilima_resource_context_init(struct lima_context *ctx) 944bf215546Sopenharmony_ci{ 945bf215546Sopenharmony_ci ctx->base.create_surface = lima_surface_create; 946bf215546Sopenharmony_ci ctx->base.surface_destroy = lima_surface_destroy; 947bf215546Sopenharmony_ci 948bf215546Sopenharmony_ci ctx->base.buffer_subdata = u_default_buffer_subdata; 949bf215546Sopenharmony_ci ctx->base.texture_subdata = lima_texture_subdata; 950bf215546Sopenharmony_ci /* TODO: optimize resource_copy_region to do copy directly 951bf215546Sopenharmony_ci * between 2 tiled or tiled and linear resources instead of 952bf215546Sopenharmony_ci * using staging buffer. 953bf215546Sopenharmony_ci */ 954bf215546Sopenharmony_ci ctx->base.resource_copy_region = util_resource_copy_region; 955bf215546Sopenharmony_ci 956bf215546Sopenharmony_ci ctx->base.blit = lima_blit; 957bf215546Sopenharmony_ci 958bf215546Sopenharmony_ci ctx->base.buffer_map = u_transfer_helper_transfer_map; 959bf215546Sopenharmony_ci ctx->base.texture_map = u_transfer_helper_transfer_map; 960bf215546Sopenharmony_ci ctx->base.transfer_flush_region = u_transfer_helper_transfer_flush_region; 961bf215546Sopenharmony_ci ctx->base.buffer_unmap = u_transfer_helper_transfer_unmap; 962bf215546Sopenharmony_ci ctx->base.texture_unmap = u_transfer_helper_transfer_unmap; 963bf215546Sopenharmony_ci 964bf215546Sopenharmony_ci ctx->base.flush_resource = lima_flush_resource; 965bf215546Sopenharmony_ci} 966