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