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