1/*
2 * Copyright (c) 2017-2019 Lima Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sub license,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#include "util/u_memory.h"
26#include "util/u_blitter.h"
27#include "util/u_upload_mgr.h"
28#include "util/u_math.h"
29#include "util/u_debug.h"
30#include "util/ralloc.h"
31#include "util/u_inlines.h"
32#include "util/u_suballoc.h"
33#include "util/hash_table.h"
34
35#include "lima_screen.h"
36#include "lima_context.h"
37#include "lima_resource.h"
38#include "lima_bo.h"
39#include "lima_submit.h"
40#include "lima_util.h"
41#include "lima_fence.h"
42
43#include <drm-uapi/lima_drm.h>
44#include <xf86drm.h>
45
46int lima_ctx_num_plb = LIMA_CTX_PLB_DEF_NUM;
47
48uint32_t
49lima_ctx_buff_va(struct lima_context *ctx, enum lima_ctx_buff buff, unsigned submit)
50{
51   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
52   struct lima_resource *res = lima_resource(cbs->res);
53
54   if (submit & LIMA_CTX_BUFF_SUBMIT_GP)
55      lima_submit_add_bo(ctx->gp_submit, res->bo, LIMA_SUBMIT_BO_READ);
56   if (submit & LIMA_CTX_BUFF_SUBMIT_PP)
57      lima_submit_add_bo(ctx->pp_submit, res->bo, LIMA_SUBMIT_BO_READ);
58
59   return res->bo->va + cbs->offset;
60}
61
62void *
63lima_ctx_buff_map(struct lima_context *ctx, enum lima_ctx_buff buff)
64{
65   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
66   struct lima_resource *res = lima_resource(cbs->res);
67
68   return lima_bo_map(res->bo) + cbs->offset;
69}
70
71void *
72lima_ctx_buff_alloc(struct lima_context *ctx, enum lima_ctx_buff buff,
73                    unsigned size, bool uploader)
74{
75   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
76   void *ret = NULL;
77
78   cbs->size = align(size, 0x40);
79
80   if (uploader)
81      u_upload_alloc(ctx->uploader, 0, cbs->size, 0x40, &cbs->offset,
82                     &cbs->res, &ret);
83   else
84      u_suballocator_alloc(ctx->suballocator, cbs->size, 0x10,
85                           &cbs->offset, &cbs->res);
86
87   return ret;
88}
89
90static int
91lima_context_create_drm_ctx(struct lima_screen *screen)
92{
93   struct drm_lima_ctx_create req = {0};
94
95   int ret = drmIoctl(screen->fd, DRM_IOCTL_LIMA_CTX_CREATE, &req);
96   if (ret)
97      return errno;
98
99   return req.id;
100}
101
102static void
103lima_context_free_drm_ctx(struct lima_screen *screen, int id)
104{
105   struct drm_lima_ctx_free req = {
106      .id = id,
107   };
108
109   drmIoctl(screen->fd, DRM_IOCTL_LIMA_CTX_FREE, &req);
110}
111
112static void
113lima_context_destroy(struct pipe_context *pctx)
114{
115   struct lima_context *ctx = lima_context(pctx);
116   struct lima_screen *screen = lima_screen(pctx->screen);
117
118   if (ctx->pp_submit)
119      lima_submit_free(ctx->pp_submit);
120   if (ctx->gp_submit)
121      lima_submit_free(ctx->gp_submit);
122
123   for (int i = 0; i < lima_ctx_buff_num; i++)
124      pipe_resource_reference(&ctx->buffer_state[i].res, NULL);
125
126   lima_state_fini(ctx);
127
128   if (ctx->blitter)
129      util_blitter_destroy(ctx->blitter);
130
131   if (ctx->suballocator)
132      u_suballocator_destroy(ctx->suballocator);
133
134   if (ctx->uploader)
135      u_upload_destroy(ctx->uploader);
136
137   slab_destroy_child(&ctx->transfer_pool);
138
139   for (int i = 0; i < LIMA_CTX_PLB_MAX_NUM; i++) {
140      if (ctx->plb[i])
141         lima_bo_free(ctx->plb[i]);
142      if (ctx->gp_tile_heap[i])
143         lima_bo_free(ctx->gp_tile_heap[i]);
144   }
145
146   if (ctx->plb_gp_stream)
147      lima_bo_free(ctx->plb_gp_stream);
148
149   if (ctx->plb_pp_stream)
150      assert(!_mesa_hash_table_num_entries(ctx->plb_pp_stream));
151
152   lima_context_free_drm_ctx(screen, ctx->id);
153
154   ralloc_free(ctx);
155}
156
157static uint32_t
158plb_pp_stream_hash(const void *key)
159{
160   return _mesa_hash_data(key, sizeof(struct lima_ctx_plb_pp_stream_key));
161}
162
163static bool
164plb_pp_stream_compare(const void *key1, const void *key2)
165{
166   return memcmp(key1, key2, sizeof(struct lima_ctx_plb_pp_stream_key)) == 0;
167}
168
169struct pipe_context *
170lima_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
171{
172   struct lima_screen *screen = lima_screen(pscreen);
173   struct lima_context *ctx;
174
175   ctx = rzalloc(screen, struct lima_context);
176   if (!ctx)
177      return NULL;
178
179   ctx->id = lima_context_create_drm_ctx(screen);
180   if (ctx->id < 0) {
181      ralloc_free(ctx);
182      return NULL;
183   }
184
185   ctx->base.screen = pscreen;
186   ctx->base.destroy = lima_context_destroy;
187
188   lima_resource_context_init(ctx);
189   lima_fence_context_init(ctx);
190   lima_state_init(ctx);
191   lima_draw_init(ctx);
192   lima_program_init(ctx);
193   lima_query_init(ctx);
194
195   slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);
196
197   ctx->blitter = util_blitter_create(&ctx->base);
198   if (!ctx->blitter)
199      goto err_out;
200
201   ctx->uploader = u_upload_create_default(&ctx->base);
202   if (!ctx->uploader)
203      goto err_out;
204   ctx->base.stream_uploader = ctx->uploader;
205   ctx->base.const_uploader = ctx->uploader;
206
207   /* for varying output which need not mmap */
208   ctx->suballocator =
209      u_suballocator_create(&ctx->base, 1024 * 1024, 0,
210                            PIPE_USAGE_STREAM, 0, false);
211   if (!ctx->suballocator)
212      goto err_out;
213
214   util_dynarray_init(&ctx->vs_cmd_array, ctx);
215   util_dynarray_init(&ctx->plbu_cmd_array, ctx);
216
217   if (screen->gpu_type == DRM_LIMA_PARAM_GPU_ID_MALI450)
218      ctx->plb_max_blk = 4096;
219   else
220      ctx->plb_max_blk = 512;
221   ctx->plb_size = ctx->plb_max_blk * LIMA_CTX_PLB_BLK_SIZE;
222   ctx->plb_gp_size = ctx->plb_max_blk * 4;
223
224   for (int i = 0; i < lima_ctx_num_plb; i++) {
225      ctx->plb[i] = lima_bo_create(screen, ctx->plb_size, 0);
226      if (!ctx->plb[i])
227         goto err_out;
228      ctx->gp_tile_heap[i] = lima_bo_create(screen, gp_tile_heap_size, 0);
229      if (!ctx->gp_tile_heap[i])
230         goto err_out;
231   }
232
233   unsigned plb_gp_stream_size =
234      align(ctx->plb_gp_size * lima_ctx_num_plb, LIMA_PAGE_SIZE);
235   ctx->plb_gp_stream =
236      lima_bo_create(screen, plb_gp_stream_size, 0);
237   if (!ctx->plb_gp_stream)
238      goto err_out;
239   lima_bo_map(ctx->plb_gp_stream);
240
241   /* plb gp stream is static for any framebuffer */
242   for (int i = 0; i < lima_ctx_num_plb; i++) {
243      uint32_t *plb_gp_stream = ctx->plb_gp_stream->map + i * ctx->plb_gp_size;
244      for (int j = 0; j < ctx->plb_max_blk; j++)
245         plb_gp_stream[j] = ctx->plb[i]->va + LIMA_CTX_PLB_BLK_SIZE * j;
246   }
247
248   if (screen->gpu_type == DRM_LIMA_PARAM_GPU_ID_MALI400) {
249      ctx->plb_pp_stream = _mesa_hash_table_create(
250         ctx, plb_pp_stream_hash, plb_pp_stream_compare);
251      if (!ctx->plb_pp_stream)
252         goto err_out;
253   }
254
255   ctx->gp_submit = lima_submit_create(ctx, LIMA_PIPE_GP);
256   if (!ctx->gp_submit)
257      goto err_out;
258
259   ctx->pp_submit = lima_submit_create(ctx, LIMA_PIPE_PP);
260   if (!ctx->pp_submit)
261      goto err_out;
262
263   return &ctx->base;
264
265err_out:
266   lima_context_destroy(&ctx->base);
267   return NULL;
268}
269
270bool
271lima_need_flush(struct lima_context *ctx, struct lima_bo *bo, bool write)
272{
273   return lima_submit_has_bo(ctx->gp_submit, bo, write) ||
274      lima_submit_has_bo(ctx->pp_submit, bo, write);
275}
276
277bool
278lima_is_scanout(struct lima_context *ctx)
279{
280        /* If there is no color buffer, it's an FBO */
281        if (!ctx->framebuffer.base.nr_cbufs)
282                return false;
283
284        return ctx->framebuffer.base.cbufs[0]->texture->bind & PIPE_BIND_DISPLAY_TARGET ||
285               ctx->framebuffer.base.cbufs[0]->texture->bind & PIPE_BIND_SCANOUT ||
286               ctx->framebuffer.base.cbufs[0]->texture->bind & PIPE_BIND_SHARED;
287}
288