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/hash_table.h"
33
34#include "lima_screen.h"
35#include "lima_context.h"
36#include "lima_resource.h"
37#include "lima_bo.h"
38#include "lima_job.h"
39#include "lima_util.h"
40#include "lima_fence.h"
41
42#include <drm-uapi/lima_drm.h>
43#include <xf86drm.h>
44
45int lima_ctx_num_plb = LIMA_CTX_PLB_DEF_NUM;
46
47uint32_t
48lima_ctx_buff_va(struct lima_context *ctx, enum lima_ctx_buff buff)
49{
50   struct lima_job *job = lima_job_get(ctx);
51   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
52   struct lima_resource *res = lima_resource(cbs->res);
53   int pipe = buff < lima_ctx_buff_num_gp ? LIMA_PIPE_GP : LIMA_PIPE_PP;
54
55   lima_job_add_bo(job, pipe, res->bo, LIMA_SUBMIT_BO_READ);
56
57   return res->bo->va + cbs->offset;
58}
59
60void *
61lima_ctx_buff_map(struct lima_context *ctx, enum lima_ctx_buff buff)
62{
63   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
64   struct lima_resource *res = lima_resource(cbs->res);
65
66   return lima_bo_map(res->bo) + cbs->offset;
67}
68
69void *
70lima_ctx_buff_alloc(struct lima_context *ctx, enum lima_ctx_buff buff,
71                    unsigned size)
72{
73   struct lima_ctx_buff_state *cbs = ctx->buffer_state + buff;
74   void *ret = NULL;
75
76   cbs->size = align(size, 0x40);
77
78   u_upload_alloc(ctx->uploader, 0, cbs->size, 0x40, &cbs->offset,
79                  &cbs->res, &ret);
80
81   return ret;
82}
83
84static int
85lima_context_create_drm_ctx(struct lima_screen *screen)
86{
87   struct drm_lima_ctx_create req = {0};
88
89   int ret = drmIoctl(screen->fd, DRM_IOCTL_LIMA_CTX_CREATE, &req);
90   if (ret)
91      return errno;
92
93   return req.id;
94}
95
96static void
97lima_context_free_drm_ctx(struct lima_screen *screen, int id)
98{
99   struct drm_lima_ctx_free req = {
100      .id = id,
101   };
102
103   drmIoctl(screen->fd, DRM_IOCTL_LIMA_CTX_FREE, &req);
104}
105
106static void
107lima_invalidate_resource(struct pipe_context *pctx, struct pipe_resource *prsc)
108{
109   struct lima_context *ctx = lima_context(pctx);
110
111   struct hash_entry *entry = _mesa_hash_table_search(ctx->write_jobs, prsc);
112   if (!entry)
113      return;
114
115   struct lima_job *job = entry->data;
116   if (job->key.zsbuf && (job->key.zsbuf->texture == prsc))
117      job->resolve &= ~(PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL);
118
119   if (job->key.cbuf && (job->key.cbuf->texture == prsc))
120      job->resolve &= ~PIPE_CLEAR_COLOR0;
121
122   _mesa_hash_table_remove_key(ctx->write_jobs, prsc);
123}
124
125static void
126plb_pp_stream_delete_fn(struct hash_entry *entry)
127{
128   struct lima_ctx_plb_pp_stream *s = entry->data;
129
130   lima_bo_unreference(s->bo);
131   list_del(&s->lru_list);
132   ralloc_free(s);
133}
134
135static void
136lima_context_destroy(struct pipe_context *pctx)
137{
138   struct lima_context *ctx = lima_context(pctx);
139   struct lima_screen *screen = lima_screen(pctx->screen);
140
141   lima_job_fini(ctx);
142
143   for (int i = 0; i < lima_ctx_buff_num; i++)
144      pipe_resource_reference(&ctx->buffer_state[i].res, NULL);
145
146   lima_program_fini(ctx);
147   lima_state_fini(ctx);
148
149   if (ctx->blitter)
150      util_blitter_destroy(ctx->blitter);
151
152   if (ctx->uploader)
153      u_upload_destroy(ctx->uploader);
154
155   slab_destroy_child(&ctx->transfer_pool);
156
157   for (int i = 0; i < LIMA_CTX_PLB_MAX_NUM; i++) {
158      if (ctx->plb[i])
159         lima_bo_unreference(ctx->plb[i]);
160      if (ctx->gp_tile_heap[i])
161         lima_bo_unreference(ctx->gp_tile_heap[i]);
162   }
163
164   if (ctx->plb_gp_stream)
165      lima_bo_unreference(ctx->plb_gp_stream);
166
167   if (ctx->gp_output)
168      lima_bo_unreference(ctx->gp_output);
169
170   _mesa_hash_table_destroy(ctx->plb_pp_stream,
171                            plb_pp_stream_delete_fn);
172
173   lima_context_free_drm_ctx(screen, ctx->id);
174
175   ralloc_free(ctx);
176}
177
178static uint32_t
179plb_pp_stream_hash(const void *key)
180{
181   return _mesa_hash_data(key, sizeof(struct lima_ctx_plb_pp_stream_key));
182}
183
184static bool
185plb_pp_stream_compare(const void *key1, const void *key2)
186{
187   return memcmp(key1, key2, sizeof(struct lima_ctx_plb_pp_stream_key)) == 0;
188}
189
190static void
191lima_set_debug_callback(struct pipe_context *pctx,
192                        const struct util_debug_callback *cb)
193{
194   struct lima_context *ctx = lima_context(pctx);
195
196   if (cb)
197      ctx->debug = *cb;
198   else
199      memset(&ctx->debug, 0, sizeof(ctx->debug));
200}
201
202struct pipe_context *
203lima_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
204{
205   struct lima_screen *screen = lima_screen(pscreen);
206   struct lima_context *ctx;
207
208   ctx = rzalloc(NULL, struct lima_context);
209   if (!ctx)
210      return NULL;
211
212   ctx->id = lima_context_create_drm_ctx(screen);
213   if (ctx->id < 0) {
214      ralloc_free(ctx);
215      return NULL;
216   }
217
218   ctx->sample_mask = (1 << LIMA_MAX_SAMPLES) - 1;
219
220   ctx->base.screen = pscreen;
221   ctx->base.destroy = lima_context_destroy;
222   ctx->base.set_debug_callback = lima_set_debug_callback;
223   ctx->base.invalidate_resource = lima_invalidate_resource;
224
225   lima_resource_context_init(ctx);
226   lima_fence_context_init(ctx);
227   lima_state_init(ctx);
228   lima_draw_init(ctx);
229   lima_program_init(ctx);
230   lima_query_init(ctx);
231
232   slab_create_child(&ctx->transfer_pool, &screen->transfer_pool);
233
234   ctx->blitter = util_blitter_create(&ctx->base);
235   if (!ctx->blitter)
236      goto err_out;
237
238   ctx->uploader = u_upload_create_default(&ctx->base);
239   if (!ctx->uploader)
240      goto err_out;
241   ctx->base.stream_uploader = ctx->uploader;
242   ctx->base.const_uploader = ctx->uploader;
243
244   ctx->plb_size = screen->plb_max_blk * LIMA_CTX_PLB_BLK_SIZE;
245   ctx->plb_gp_size = screen->plb_max_blk * 4;
246
247   uint32_t heap_flags;
248   if (screen->has_growable_heap_buffer) {
249      /* growable size buffer, initially will allocate 32K (by default)
250       * backup memory in kernel driver, and will allocate more when GP
251       * get out of memory interrupt. Max to 16M set here.
252       */
253      ctx->gp_tile_heap_size = 0x1000000;
254      heap_flags = LIMA_BO_FLAG_HEAP;
255   } else {
256      /* fix size buffer */
257      ctx->gp_tile_heap_size = 0x100000;
258      heap_flags = 0;
259   }
260
261   for (int i = 0; i < lima_ctx_num_plb; i++) {
262      ctx->plb[i] = lima_bo_create(screen, ctx->plb_size, 0);
263      if (!ctx->plb[i])
264         goto err_out;
265      ctx->gp_tile_heap[i] = lima_bo_create(screen, ctx->gp_tile_heap_size, heap_flags);
266      if (!ctx->gp_tile_heap[i])
267         goto err_out;
268   }
269
270   unsigned plb_gp_stream_size =
271      align(ctx->plb_gp_size * lima_ctx_num_plb, LIMA_PAGE_SIZE);
272   ctx->plb_gp_stream =
273      lima_bo_create(screen, plb_gp_stream_size, 0);
274   if (!ctx->plb_gp_stream)
275      goto err_out;
276   lima_bo_map(ctx->plb_gp_stream);
277
278   /* plb gp stream is static for any framebuffer */
279   for (int i = 0; i < lima_ctx_num_plb; i++) {
280      uint32_t *plb_gp_stream = ctx->plb_gp_stream->map + i * ctx->plb_gp_size;
281      for (int j = 0; j < screen->plb_max_blk; j++)
282         plb_gp_stream[j] = ctx->plb[i]->va + LIMA_CTX_PLB_BLK_SIZE * j;
283   }
284
285   list_inithead(&ctx->plb_pp_stream_lru_list);
286   ctx->plb_pp_stream = _mesa_hash_table_create(
287      ctx, plb_pp_stream_hash, plb_pp_stream_compare);
288   if (!ctx->plb_pp_stream)
289      goto err_out;
290
291   if (!lima_job_init(ctx))
292      goto err_out;
293
294   return &ctx->base;
295
296err_out:
297   lima_context_destroy(&ctx->base);
298   return NULL;
299}
300