1b8e80941Smrg/*
2b8e80941Smrg * Copyright (c) 2017-2019 Lima Project
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sub license,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the
12b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions
13b8e80941Smrg * of the Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b8e80941Smrg * DEALINGS IN THE SOFTWARE.
22b8e80941Smrg *
23b8e80941Smrg */
24b8e80941Smrg
25b8e80941Smrg#include "util/u_memory.h"
26b8e80941Smrg#include "util/u_blitter.h"
27b8e80941Smrg#include "util/u_format.h"
28b8e80941Smrg#include "util/u_inlines.h"
29b8e80941Smrg#include "util/u_math.h"
30b8e80941Smrg#include "util/u_debug.h"
31b8e80941Smrg#include "util/u_transfer.h"
32b8e80941Smrg#include "util/u_surface.h"
33b8e80941Smrg#include "util/hash_table.h"
34b8e80941Smrg#include "util/u_drm.h"
35b8e80941Smrg#include "renderonly/renderonly.h"
36b8e80941Smrg
37b8e80941Smrg#include "state_tracker/drm_driver.h"
38b8e80941Smrg
39b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
40b8e80941Smrg#include "drm-uapi/lima_drm.h"
41b8e80941Smrg
42b8e80941Smrg#include "lima_screen.h"
43b8e80941Smrg#include "lima_context.h"
44b8e80941Smrg#include "lima_resource.h"
45b8e80941Smrg#include "lima_bo.h"
46b8e80941Smrg#include "lima_util.h"
47b8e80941Smrg#include "lima_tiling.h"
48b8e80941Smrg
49b8e80941Smrgstatic struct pipe_resource *
50b8e80941Smrglima_resource_create_scanout(struct pipe_screen *pscreen,
51b8e80941Smrg                             const struct pipe_resource *templat,
52b8e80941Smrg                             unsigned width, unsigned height)
53b8e80941Smrg{
54b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
55b8e80941Smrg   struct renderonly_scanout *scanout;
56b8e80941Smrg   struct winsys_handle handle;
57b8e80941Smrg   struct pipe_resource *pres;
58b8e80941Smrg
59b8e80941Smrg   struct pipe_resource scanout_templat = *templat;
60b8e80941Smrg   scanout_templat.width0 = width;
61b8e80941Smrg   scanout_templat.height0 = height;
62b8e80941Smrg   scanout_templat.screen = pscreen;
63b8e80941Smrg
64b8e80941Smrg   scanout = renderonly_scanout_for_resource(&scanout_templat,
65b8e80941Smrg                                             screen->ro, &handle);
66b8e80941Smrg   if (!scanout)
67b8e80941Smrg      return NULL;
68b8e80941Smrg
69b8e80941Smrg   assert(handle.type == WINSYS_HANDLE_TYPE_FD);
70b8e80941Smrg   pres = pscreen->resource_from_handle(pscreen, templat, &handle,
71b8e80941Smrg                                        PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
72b8e80941Smrg
73b8e80941Smrg   close(handle.handle);
74b8e80941Smrg   if (!pres) {
75b8e80941Smrg      renderonly_scanout_destroy(scanout, screen->ro);
76b8e80941Smrg      return NULL;
77b8e80941Smrg   }
78b8e80941Smrg
79b8e80941Smrg   struct lima_resource *res = lima_resource(pres);
80b8e80941Smrg   res->scanout = scanout;
81b8e80941Smrg
82b8e80941Smrg   return pres;
83b8e80941Smrg}
84b8e80941Smrg
85b8e80941Smrgstatic uint32_t
86b8e80941Smrgsetup_miptree(struct lima_resource *res,
87b8e80941Smrg              unsigned width0, unsigned height0,
88b8e80941Smrg              bool should_align_dimensions)
89b8e80941Smrg{
90b8e80941Smrg   struct pipe_resource *pres = &res->base;
91b8e80941Smrg   unsigned level;
92b8e80941Smrg   unsigned width = width0;
93b8e80941Smrg   unsigned height = height0;
94b8e80941Smrg   unsigned depth = pres->depth0;
95b8e80941Smrg   uint32_t size = 0;
96b8e80941Smrg
97b8e80941Smrg   for (level = 0; level <= pres->last_level; level++) {
98b8e80941Smrg      uint32_t actual_level_size;
99b8e80941Smrg      uint32_t stride;
100b8e80941Smrg      unsigned aligned_width;
101b8e80941Smrg      unsigned aligned_height;
102b8e80941Smrg
103b8e80941Smrg      if (should_align_dimensions) {
104b8e80941Smrg         aligned_width = align(width, 16);
105b8e80941Smrg         aligned_height = align(height, 16);
106b8e80941Smrg      } else {
107b8e80941Smrg         aligned_width = width;
108b8e80941Smrg         aligned_height = height;
109b8e80941Smrg      }
110b8e80941Smrg
111b8e80941Smrg      stride = util_format_get_stride(pres->format, aligned_width);
112b8e80941Smrg      actual_level_size = stride *
113b8e80941Smrg         util_format_get_nblocksy(pres->format, aligned_height) *
114b8e80941Smrg         pres->array_size * depth;
115b8e80941Smrg
116b8e80941Smrg      res->levels[level].width = aligned_width;
117b8e80941Smrg      res->levels[level].stride = stride;
118b8e80941Smrg      res->levels[level].offset = size;
119b8e80941Smrg
120b8e80941Smrg      /* The start address of each level <= 10 must be 64-aligned
121b8e80941Smrg       * in order to be able to pass the addresses
122b8e80941Smrg       * to the hardware.
123b8e80941Smrg       * The start addresses of level 11 and level 12 are passed
124b8e80941Smrg       * implicitely: they start at an offset of respectively
125b8e80941Smrg       * 0x0400 and 0x0800 from the start address of level 10 */
126b8e80941Smrg      if (level < 10)
127b8e80941Smrg         size += align(actual_level_size, 64);
128b8e80941Smrg      else if (level != pres->last_level)
129b8e80941Smrg         size += 0x0400;
130b8e80941Smrg      else
131b8e80941Smrg         size += actual_level_size;  /* Save some memory */
132b8e80941Smrg
133b8e80941Smrg      width = u_minify(width, 1);
134b8e80941Smrg      height = u_minify(height, 1);
135b8e80941Smrg      depth = u_minify(depth, 1);
136b8e80941Smrg   }
137b8e80941Smrg
138b8e80941Smrg   return size;
139b8e80941Smrg}
140b8e80941Smrg
141b8e80941Smrgstatic struct pipe_resource *
142b8e80941Smrglima_resource_create_bo(struct pipe_screen *pscreen,
143b8e80941Smrg                        const struct pipe_resource *templat,
144b8e80941Smrg                        unsigned width, unsigned height,
145b8e80941Smrg                        bool should_align_dimensions)
146b8e80941Smrg{
147b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
148b8e80941Smrg   struct lima_resource *res;
149b8e80941Smrg   struct pipe_resource *pres;
150b8e80941Smrg
151b8e80941Smrg   res = CALLOC_STRUCT(lima_resource);
152b8e80941Smrg   if (!res)
153b8e80941Smrg      return NULL;
154b8e80941Smrg
155b8e80941Smrg   res->base = *templat;
156b8e80941Smrg   res->base.screen = pscreen;
157b8e80941Smrg   pipe_reference_init(&res->base.reference, 1);
158b8e80941Smrg
159b8e80941Smrg   pres = &res->base;
160b8e80941Smrg
161b8e80941Smrg   uint32_t size = setup_miptree(res, width, height, should_align_dimensions);
162b8e80941Smrg   size = align(size, LIMA_PAGE_SIZE);
163b8e80941Smrg
164b8e80941Smrg   res->bo = lima_bo_create(screen, size, 0);
165b8e80941Smrg   if (!res->bo) {
166b8e80941Smrg      FREE(res);
167b8e80941Smrg      return NULL;
168b8e80941Smrg   }
169b8e80941Smrg
170b8e80941Smrg   return pres;
171b8e80941Smrg}
172b8e80941Smrg
173b8e80941Smrgstatic struct pipe_resource *
174b8e80941Smrg_lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
175b8e80941Smrg                                     const struct pipe_resource *templat,
176b8e80941Smrg                                     const uint64_t *modifiers,
177b8e80941Smrg                                     int count)
178b8e80941Smrg{
179b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
180b8e80941Smrg   bool should_tile = false;
181b8e80941Smrg   unsigned width, height;
182b8e80941Smrg   bool should_align_dimensions;
183b8e80941Smrg
184b8e80941Smrg   /* VBOs/PBOs are untiled (and 1 height). */
185b8e80941Smrg   if (templat->target == PIPE_BUFFER)
186b8e80941Smrg      should_tile = false;
187b8e80941Smrg
188b8e80941Smrg   if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))
189b8e80941Smrg      should_tile = false;
190b8e80941Smrg
191b8e80941Smrg   /* if linear buffer is not allowed, alloc fail */
192b8e80941Smrg   if (!should_tile && !drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
193b8e80941Smrg      return NULL;
194b8e80941Smrg
195b8e80941Smrg   if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||
196b8e80941Smrg       (templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
197b8e80941Smrg      should_align_dimensions = true;
198b8e80941Smrg      width = align(templat->width0, 16);
199b8e80941Smrg      height = align(templat->height0, 16);
200b8e80941Smrg   }
201b8e80941Smrg   else {
202b8e80941Smrg      should_align_dimensions = false;
203b8e80941Smrg      width = templat->width0;
204b8e80941Smrg      height = templat->height0;
205b8e80941Smrg   }
206b8e80941Smrg
207b8e80941Smrg   struct pipe_resource *pres;
208b8e80941Smrg   if (screen->ro && (templat->bind & PIPE_BIND_SCANOUT))
209b8e80941Smrg      pres = lima_resource_create_scanout(pscreen, templat, width, height);
210b8e80941Smrg   else
211b8e80941Smrg      pres = lima_resource_create_bo(pscreen, templat, width, height,
212b8e80941Smrg                                     should_align_dimensions);
213b8e80941Smrg
214b8e80941Smrg   if (pres) {
215b8e80941Smrg      struct lima_resource *res = lima_resource(pres);
216b8e80941Smrg      res->tiled = should_tile;
217b8e80941Smrg
218b8e80941Smrg      debug_printf("%s: pres=%p width=%u height=%u depth=%u target=%d "
219b8e80941Smrg                   "bind=%x usage=%d tile=%d last_level=%d\n", __func__,
220b8e80941Smrg                   pres, pres->width0, pres->height0, pres->depth0,
221b8e80941Smrg                   pres->target, pres->bind, pres->usage, should_tile, templat->last_level);
222b8e80941Smrg   }
223b8e80941Smrg   return pres;
224b8e80941Smrg}
225b8e80941Smrg
226b8e80941Smrgstatic struct pipe_resource *
227b8e80941Smrglima_resource_create(struct pipe_screen *pscreen,
228b8e80941Smrg                     const struct pipe_resource *templat)
229b8e80941Smrg{
230b8e80941Smrg   static const uint64_t modifiers[] = {
231b8e80941Smrg      DRM_FORMAT_MOD_LINEAR,
232b8e80941Smrg   };
233b8e80941Smrg   return _lima_resource_create_with_modifiers(pscreen, templat, modifiers, ARRAY_SIZE(modifiers));
234b8e80941Smrg}
235b8e80941Smrg
236b8e80941Smrgstatic struct pipe_resource *
237b8e80941Smrglima_resource_create_with_modifiers(struct pipe_screen *pscreen,
238b8e80941Smrg                                    const struct pipe_resource *templat,
239b8e80941Smrg                                    const uint64_t *modifiers,
240b8e80941Smrg                                    int count)
241b8e80941Smrg{
242b8e80941Smrg   struct pipe_resource tmpl = *templat;
243b8e80941Smrg
244b8e80941Smrg   /* gbm_bo_create_with_modifiers & gbm_surface_create_with_modifiers
245b8e80941Smrg    * don't have usage parameter, but buffer created by these functions
246b8e80941Smrg    * may be used for scanout. So we assume buffer created by this
247b8e80941Smrg    * function always enable scanout if linear modifier is permitted.
248b8e80941Smrg    */
249b8e80941Smrg   if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
250b8e80941Smrg      tmpl.bind |= PIPE_BIND_SCANOUT;
251b8e80941Smrg
252b8e80941Smrg   return _lima_resource_create_with_modifiers(pscreen, &tmpl, modifiers, count);
253b8e80941Smrg}
254b8e80941Smrg
255b8e80941Smrgstatic void
256b8e80941Smrglima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)
257b8e80941Smrg{
258b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
259b8e80941Smrg   struct lima_resource *res = lima_resource(pres);
260b8e80941Smrg
261b8e80941Smrg   if (res->bo)
262b8e80941Smrg      lima_bo_free(res->bo);
263b8e80941Smrg
264b8e80941Smrg   if (res->scanout)
265b8e80941Smrg      renderonly_scanout_destroy(res->scanout, screen->ro);
266b8e80941Smrg
267b8e80941Smrg   FREE(res);
268b8e80941Smrg}
269b8e80941Smrg
270b8e80941Smrgstatic struct pipe_resource *
271b8e80941Smrglima_resource_from_handle(struct pipe_screen *pscreen,
272b8e80941Smrg        const struct pipe_resource *templat,
273b8e80941Smrg        struct winsys_handle *handle, unsigned usage)
274b8e80941Smrg{
275b8e80941Smrg   struct lima_resource *res;
276b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
277b8e80941Smrg
278b8e80941Smrg   res = CALLOC_STRUCT(lima_resource);
279b8e80941Smrg   if (!res)
280b8e80941Smrg      return NULL;
281b8e80941Smrg
282b8e80941Smrg   struct pipe_resource *pres = &res->base;
283b8e80941Smrg   *pres = *templat;
284b8e80941Smrg   pres->screen = pscreen;
285b8e80941Smrg   pipe_reference_init(&pres->reference, 1);
286b8e80941Smrg   res->levels[0].offset = 0;
287b8e80941Smrg   res->levels[0].stride = handle->stride;
288b8e80941Smrg
289b8e80941Smrg   res->bo = lima_bo_import(screen, handle);
290b8e80941Smrg   if (!res->bo) {
291b8e80941Smrg      FREE(res);
292b8e80941Smrg      return NULL;
293b8e80941Smrg   }
294b8e80941Smrg
295b8e80941Smrg   /* check alignment for the buffer */
296b8e80941Smrg   if (pres->bind & PIPE_BIND_RENDER_TARGET) {
297b8e80941Smrg      unsigned width, height, stride, size;
298b8e80941Smrg
299b8e80941Smrg      width = align(pres->width0, 16);
300b8e80941Smrg      height = align(pres->height0, 16);
301b8e80941Smrg      stride = util_format_get_stride(pres->format, width);
302b8e80941Smrg      size = util_format_get_2d_size(pres->format, stride, height);
303b8e80941Smrg
304b8e80941Smrg      if (res->levels[0].stride != stride || res->bo->size < size) {
305b8e80941Smrg         debug_error("import buffer not properly aligned\n");
306b8e80941Smrg         goto err_out;
307b8e80941Smrg      }
308b8e80941Smrg
309b8e80941Smrg      res->levels[0].width = width;
310b8e80941Smrg   }
311b8e80941Smrg   else
312b8e80941Smrg      res->levels[0].width = pres->width0;
313b8e80941Smrg
314b8e80941Smrg   handle->modifier = DRM_FORMAT_MOD_LINEAR;
315b8e80941Smrg   res->tiled = false;
316b8e80941Smrg
317b8e80941Smrg   return pres;
318b8e80941Smrg
319b8e80941Smrgerr_out:
320b8e80941Smrg   lima_resource_destroy(pscreen, pres);
321b8e80941Smrg   return NULL;
322b8e80941Smrg}
323b8e80941Smrg
324b8e80941Smrgstatic boolean
325b8e80941Smrglima_resource_get_handle(struct pipe_screen *pscreen,
326b8e80941Smrg                         struct pipe_context *pctx,
327b8e80941Smrg                         struct pipe_resource *pres,
328b8e80941Smrg                         struct winsys_handle *handle, unsigned usage)
329b8e80941Smrg{
330b8e80941Smrg   struct lima_screen *screen = lima_screen(pscreen);
331b8e80941Smrg   struct lima_resource *res = lima_resource(pres);
332b8e80941Smrg
333b8e80941Smrg   handle->modifier = DRM_FORMAT_MOD_LINEAR;
334b8e80941Smrg
335b8e80941Smrg   if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro &&
336b8e80941Smrg       renderonly_get_handle(res->scanout, handle))
337b8e80941Smrg      return TRUE;
338b8e80941Smrg
339b8e80941Smrg   if (!lima_bo_export(res->bo, handle))
340b8e80941Smrg      return FALSE;
341b8e80941Smrg
342b8e80941Smrg   handle->stride = res->levels[0].stride;
343b8e80941Smrg   return TRUE;
344b8e80941Smrg}
345b8e80941Smrg
346b8e80941Smrgvoid
347b8e80941Smrglima_resource_screen_init(struct lima_screen *screen)
348b8e80941Smrg{
349b8e80941Smrg   screen->base.resource_create = lima_resource_create;
350b8e80941Smrg   screen->base.resource_create_with_modifiers = lima_resource_create_with_modifiers;
351b8e80941Smrg   screen->base.resource_from_handle = lima_resource_from_handle;
352b8e80941Smrg   screen->base.resource_destroy = lima_resource_destroy;
353b8e80941Smrg   screen->base.resource_get_handle = lima_resource_get_handle;
354b8e80941Smrg}
355b8e80941Smrg
356b8e80941Smrgstatic struct pipe_surface *
357b8e80941Smrglima_surface_create(struct pipe_context *pctx,
358b8e80941Smrg                    struct pipe_resource *pres,
359b8e80941Smrg                    const struct pipe_surface *surf_tmpl)
360b8e80941Smrg{
361b8e80941Smrg   struct lima_surface *surf = CALLOC_STRUCT(lima_surface);
362b8e80941Smrg
363b8e80941Smrg   if (!surf)
364b8e80941Smrg      return NULL;
365b8e80941Smrg
366b8e80941Smrg   assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
367b8e80941Smrg
368b8e80941Smrg   struct pipe_surface *psurf = &surf->base;
369b8e80941Smrg   unsigned level = surf_tmpl->u.tex.level;
370b8e80941Smrg
371b8e80941Smrg   pipe_reference_init(&psurf->reference, 1);
372b8e80941Smrg   pipe_resource_reference(&psurf->texture, pres);
373b8e80941Smrg
374b8e80941Smrg   psurf->context = pctx;
375b8e80941Smrg   psurf->format = surf_tmpl->format;
376b8e80941Smrg   psurf->width = u_minify(pres->width0, level);
377b8e80941Smrg   psurf->height = u_minify(pres->height0, level);
378b8e80941Smrg   psurf->u.tex.level = level;
379b8e80941Smrg   psurf->u.tex.first_layer = surf_tmpl->u.tex.first_layer;
380b8e80941Smrg   psurf->u.tex.last_layer = surf_tmpl->u.tex.last_layer;
381b8e80941Smrg
382b8e80941Smrg   surf->tiled_w = align(psurf->width, 16) >> 4;
383b8e80941Smrg   surf->tiled_h = align(psurf->height, 16) >> 4;
384b8e80941Smrg
385b8e80941Smrg   struct lima_context *ctx = lima_context(pctx);
386b8e80941Smrg   if (ctx->plb_pp_stream) {
387b8e80941Smrg      struct lima_ctx_plb_pp_stream_key key = {
388b8e80941Smrg         .tiled_w = surf->tiled_w,
389b8e80941Smrg         .tiled_h = surf->tiled_h,
390b8e80941Smrg      };
391b8e80941Smrg
392b8e80941Smrg      for (int i = 0; i < lima_ctx_num_plb; i++) {
393b8e80941Smrg         key.plb_index = i;
394b8e80941Smrg
395b8e80941Smrg         struct hash_entry *entry =
396b8e80941Smrg            _mesa_hash_table_search(ctx->plb_pp_stream, &key);
397b8e80941Smrg         if (entry) {
398b8e80941Smrg            struct lima_ctx_plb_pp_stream *s = entry->data;
399b8e80941Smrg            s->refcnt++;
400b8e80941Smrg         }
401b8e80941Smrg         else {
402b8e80941Smrg            struct lima_ctx_plb_pp_stream *s =
403b8e80941Smrg               ralloc(ctx->plb_pp_stream, struct lima_ctx_plb_pp_stream);
404b8e80941Smrg            s->key.plb_index = i;
405b8e80941Smrg            s->key.tiled_w = surf->tiled_w;
406b8e80941Smrg            s->key.tiled_h = surf->tiled_h;
407b8e80941Smrg            s->refcnt = 1;
408b8e80941Smrg            s->bo = NULL;
409b8e80941Smrg            _mesa_hash_table_insert(ctx->plb_pp_stream, &s->key, s);
410b8e80941Smrg         }
411b8e80941Smrg      }
412b8e80941Smrg   }
413b8e80941Smrg
414b8e80941Smrg   return &surf->base;
415b8e80941Smrg}
416b8e80941Smrg
417b8e80941Smrgstatic void
418b8e80941Smrglima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
419b8e80941Smrg{
420b8e80941Smrg   struct lima_surface *surf = lima_surface(psurf);
421b8e80941Smrg   /* psurf->context may be not equal with pctx (i.e. glxinfo) */
422b8e80941Smrg   struct lima_context *ctx = lima_context(psurf->context);
423b8e80941Smrg
424b8e80941Smrg   if (ctx->plb_pp_stream) {
425b8e80941Smrg      struct lima_ctx_plb_pp_stream_key key = {
426b8e80941Smrg         .tiled_w = surf->tiled_w,
427b8e80941Smrg         .tiled_h = surf->tiled_h,
428b8e80941Smrg      };
429b8e80941Smrg
430b8e80941Smrg      for (int i = 0; i < lima_ctx_num_plb; i++) {
431b8e80941Smrg         key.plb_index = i;
432b8e80941Smrg
433b8e80941Smrg         struct hash_entry *entry =
434b8e80941Smrg            _mesa_hash_table_search(ctx->plb_pp_stream, &key);
435b8e80941Smrg         struct lima_ctx_plb_pp_stream *s = entry->data;
436b8e80941Smrg         if (--s->refcnt == 0) {
437b8e80941Smrg            if (s->bo)
438b8e80941Smrg               lima_bo_free(s->bo);
439b8e80941Smrg            _mesa_hash_table_remove(ctx->plb_pp_stream, entry);
440b8e80941Smrg            ralloc_free(s);
441b8e80941Smrg         }
442b8e80941Smrg      }
443b8e80941Smrg   }
444b8e80941Smrg
445b8e80941Smrg   pipe_resource_reference(&psurf->texture, NULL);
446b8e80941Smrg   FREE(surf);
447b8e80941Smrg}
448b8e80941Smrg
449b8e80941Smrgstatic void *
450b8e80941Smrglima_transfer_map(struct pipe_context *pctx,
451b8e80941Smrg                  struct pipe_resource *pres,
452b8e80941Smrg                  unsigned level,
453b8e80941Smrg                  unsigned usage,
454b8e80941Smrg                  const struct pipe_box *box,
455b8e80941Smrg                  struct pipe_transfer **pptrans)
456b8e80941Smrg{
457b8e80941Smrg   struct lima_context *ctx = lima_context(pctx);
458b8e80941Smrg   struct lima_resource *res = lima_resource(pres);
459b8e80941Smrg   struct lima_bo *bo = res->bo;
460b8e80941Smrg   struct lima_transfer *trans;
461b8e80941Smrg   struct pipe_transfer *ptrans;
462b8e80941Smrg
463b8e80941Smrg   /* No direct mappings of tiled, since we need to manually
464b8e80941Smrg    * tile/untile.
465b8e80941Smrg    */
466b8e80941Smrg   if (res->tiled && (usage & PIPE_TRANSFER_MAP_DIRECTLY))
467b8e80941Smrg      return NULL;
468b8e80941Smrg
469b8e80941Smrg   /* use once buffers are made sure to not read/write overlapped
470b8e80941Smrg    * range, so no need to sync */
471b8e80941Smrg   if (pres->usage != PIPE_USAGE_STREAM) {
472b8e80941Smrg      if (usage & PIPE_TRANSFER_READ_WRITE) {
473b8e80941Smrg         if (lima_need_flush(ctx, bo, usage & PIPE_TRANSFER_WRITE))
474b8e80941Smrg            lima_flush(ctx);
475b8e80941Smrg
476b8e80941Smrg         unsigned op = usage & PIPE_TRANSFER_WRITE ?
477b8e80941Smrg            LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
478b8e80941Smrg         lima_bo_wait(bo, op, PIPE_TIMEOUT_INFINITE);
479b8e80941Smrg      }
480b8e80941Smrg   }
481b8e80941Smrg
482b8e80941Smrg   if (!lima_bo_map(bo))
483b8e80941Smrg      return NULL;
484b8e80941Smrg
485b8e80941Smrg   trans = slab_alloc(&ctx->transfer_pool);
486b8e80941Smrg   if (!trans)
487b8e80941Smrg      return NULL;
488b8e80941Smrg
489b8e80941Smrg   memset(trans, 0, sizeof(*trans));
490b8e80941Smrg   ptrans = &trans->base;
491b8e80941Smrg
492b8e80941Smrg   pipe_resource_reference(&ptrans->resource, pres);
493b8e80941Smrg   ptrans->level = level;
494b8e80941Smrg   ptrans->usage = usage;
495b8e80941Smrg   ptrans->box = *box;
496b8e80941Smrg
497b8e80941Smrg   *pptrans = ptrans;
498b8e80941Smrg
499b8e80941Smrg   if (res->tiled) {
500b8e80941Smrg      ptrans->stride = util_format_get_stride(pres->format, ptrans->box.width);
501b8e80941Smrg      ptrans->layer_stride = ptrans->stride * ptrans->box.height;
502b8e80941Smrg
503b8e80941Smrg      trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
504b8e80941Smrg
505b8e80941Smrg      if (usage & PIPE_TRANSFER_READ)
506b8e80941Smrg         lima_load_tiled_image(trans->staging, bo->map + res->levels[level].offset,
507b8e80941Smrg                              &ptrans->box,
508b8e80941Smrg                              ptrans->stride,
509b8e80941Smrg                              res->levels[level].stride,
510b8e80941Smrg                              util_format_get_blocksize(pres->format));
511b8e80941Smrg
512b8e80941Smrg      return trans->staging;
513b8e80941Smrg   } else {
514b8e80941Smrg      ptrans->stride = res->levels[level].stride;
515b8e80941Smrg      ptrans->layer_stride = ptrans->stride * box->height;
516b8e80941Smrg
517b8e80941Smrg      return bo->map + res->levels[level].offset +
518b8e80941Smrg         box->z * ptrans->layer_stride +
519b8e80941Smrg         box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
520b8e80941Smrg         box->x / util_format_get_blockwidth(pres->format) *
521b8e80941Smrg         util_format_get_blocksize(pres->format);
522b8e80941Smrg   }
523b8e80941Smrg}
524b8e80941Smrg
525b8e80941Smrgstatic void
526b8e80941Smrglima_transfer_flush_region(struct pipe_context *pctx,
527b8e80941Smrg                           struct pipe_transfer *ptrans,
528b8e80941Smrg                           const struct pipe_box *box)
529b8e80941Smrg{
530b8e80941Smrg
531b8e80941Smrg}
532b8e80941Smrg
533b8e80941Smrgstatic void
534b8e80941Smrglima_transfer_unmap(struct pipe_context *pctx,
535b8e80941Smrg                    struct pipe_transfer *ptrans)
536b8e80941Smrg{
537b8e80941Smrg   struct lima_context *ctx = lima_context(pctx);
538b8e80941Smrg   struct lima_transfer *trans = lima_transfer(ptrans);
539b8e80941Smrg   struct lima_resource *res = lima_resource(ptrans->resource);
540b8e80941Smrg   struct lima_bo *bo = res->bo;
541b8e80941Smrg   struct pipe_resource *pres;
542b8e80941Smrg
543b8e80941Smrg   if (trans->staging) {
544b8e80941Smrg      pres = &res->base;
545b8e80941Smrg      if (ptrans->usage & PIPE_TRANSFER_WRITE)
546b8e80941Smrg         lima_store_tiled_image(bo->map + res->levels[ptrans->level].offset, trans->staging,
547b8e80941Smrg                              &ptrans->box,
548b8e80941Smrg                              res->levels[ptrans->level].stride,
549b8e80941Smrg                              ptrans->stride,
550b8e80941Smrg                              util_format_get_blocksize(pres->format));
551b8e80941Smrg      free(trans->staging);
552b8e80941Smrg   }
553b8e80941Smrg
554b8e80941Smrg   pipe_resource_reference(&ptrans->resource, NULL);
555b8e80941Smrg   slab_free(&ctx->transfer_pool, trans);
556b8e80941Smrg}
557b8e80941Smrg
558b8e80941Smrgstatic void
559b8e80941Smrglima_util_blitter_save_states(struct lima_context *ctx)
560b8e80941Smrg{
561b8e80941Smrg   util_blitter_save_blend(ctx->blitter, (void *)ctx->blend);
562b8e80941Smrg   util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->zsa);
563b8e80941Smrg   util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref);
564b8e80941Smrg   util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer);
565b8e80941Smrg   util_blitter_save_fragment_shader(ctx->blitter, ctx->fs);
566b8e80941Smrg   util_blitter_save_vertex_shader(ctx->blitter, ctx->vs);
567b8e80941Smrg   util_blitter_save_viewport(ctx->blitter,
568b8e80941Smrg                              &ctx->viewport.transform);
569b8e80941Smrg   util_blitter_save_scissor(ctx->blitter, &ctx->scissor);
570b8e80941Smrg   util_blitter_save_vertex_elements(ctx->blitter,
571b8e80941Smrg                                     ctx->vertex_elements);
572b8e80941Smrg   util_blitter_save_vertex_buffer_slot(ctx->blitter,
573b8e80941Smrg                                        ctx->vertex_buffers.vb);
574b8e80941Smrg
575b8e80941Smrg   util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer.base);
576b8e80941Smrg
577b8e80941Smrg   util_blitter_save_fragment_sampler_states(ctx->blitter,
578b8e80941Smrg                                             ctx->tex_stateobj.num_samplers,
579b8e80941Smrg                                             (void**)ctx->tex_stateobj.samplers);
580b8e80941Smrg   util_blitter_save_fragment_sampler_views(ctx->blitter,
581b8e80941Smrg                                            ctx->tex_stateobj.num_textures,
582b8e80941Smrg                                            ctx->tex_stateobj.textures);
583b8e80941Smrg}
584b8e80941Smrg
585b8e80941Smrgstatic void
586b8e80941Smrglima_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
587b8e80941Smrg{
588b8e80941Smrg   struct lima_context *ctx = lima_context(pctx);
589b8e80941Smrg   struct pipe_blit_info info = *blit_info;
590b8e80941Smrg
591b8e80941Smrg   if (util_try_blit_via_copy_region(pctx, &info)) {
592b8e80941Smrg      return; /* done */
593b8e80941Smrg   }
594b8e80941Smrg
595b8e80941Smrg   if (info.mask & PIPE_MASK_S) {
596b8e80941Smrg      debug_printf("lima: cannot blit stencil, skipping\n");
597b8e80941Smrg      info.mask &= ~PIPE_MASK_S;
598b8e80941Smrg   }
599b8e80941Smrg
600b8e80941Smrg   if (!util_blitter_is_blit_supported(ctx->blitter, &info)) {
601b8e80941Smrg      debug_printf("lima: blit unsupported %s -> %s\n",
602b8e80941Smrg                   util_format_short_name(info.src.resource->format),
603b8e80941Smrg                   util_format_short_name(info.dst.resource->format));
604b8e80941Smrg      return;
605b8e80941Smrg   }
606b8e80941Smrg
607b8e80941Smrg   lima_util_blitter_save_states(ctx);
608b8e80941Smrg
609b8e80941Smrg   util_blitter_blit(ctx->blitter, &info);
610b8e80941Smrg}
611b8e80941Smrg
612b8e80941Smrgstatic void
613b8e80941Smrglima_flush_resource(struct pipe_context *pctx, struct pipe_resource *resource)
614b8e80941Smrg{
615b8e80941Smrg
616b8e80941Smrg}
617b8e80941Smrg
618b8e80941Smrgvoid
619b8e80941Smrglima_resource_context_init(struct lima_context *ctx)
620b8e80941Smrg{
621b8e80941Smrg   ctx->base.create_surface = lima_surface_create;
622b8e80941Smrg   ctx->base.surface_destroy = lima_surface_destroy;
623b8e80941Smrg
624b8e80941Smrg   /* TODO: optimize these functions to read/write data directly
625b8e80941Smrg    * from/to target instead of creating a staging memory for tiled
626b8e80941Smrg    * buffer indirectly
627b8e80941Smrg    */
628b8e80941Smrg   ctx->base.buffer_subdata = u_default_buffer_subdata;
629b8e80941Smrg   ctx->base.texture_subdata = u_default_texture_subdata;
630b8e80941Smrg   ctx->base.resource_copy_region = util_resource_copy_region;
631b8e80941Smrg
632b8e80941Smrg   ctx->base.blit = lima_blit;
633b8e80941Smrg
634b8e80941Smrg   ctx->base.transfer_map = lima_transfer_map;
635b8e80941Smrg   ctx->base.transfer_flush_region = lima_transfer_flush_region;
636b8e80941Smrg   ctx->base.transfer_unmap = lima_transfer_unmap;
637b8e80941Smrg
638b8e80941Smrg   ctx->base.flush_resource = lima_flush_resource;
639b8e80941Smrg}
640