17ec681f3Smrg/* 27ec681f3Smrg * Copyright © 2017 Intel Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice shall be included 127ec681f3Smrg * in all copies or substantial portions of the Software. 137ec681f3Smrg * 147ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 157ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 187ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 197ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 207ec681f3Smrg * DEALINGS IN THE SOFTWARE. 217ec681f3Smrg */ 227ec681f3Smrg 237ec681f3Smrg#include <stdio.h> 247ec681f3Smrg#include <time.h> 257ec681f3Smrg#include "pipe/p_defines.h" 267ec681f3Smrg#include "pipe/p_state.h" 277ec681f3Smrg#include "util/ralloc.h" 287ec681f3Smrg#include "util/u_inlines.h" 297ec681f3Smrg#include "util/format/u_format.h" 307ec681f3Smrg#include "util/u_upload_mgr.h" 317ec681f3Smrg#include "drm-uapi/i915_drm.h" 327ec681f3Smrg#include "crocus_context.h" 337ec681f3Smrg#include "crocus_resource.h" 347ec681f3Smrg#include "crocus_screen.h" 357ec681f3Smrg#include "common/intel_defines.h" 367ec681f3Smrg#include "common/intel_sample_positions.h" 377ec681f3Smrg 387ec681f3Smrg/** 397ec681f3Smrg * The pipe->set_debug_callback() driver hook. 407ec681f3Smrg */ 417ec681f3Smrgstatic void 427ec681f3Smrgcrocus_set_debug_callback(struct pipe_context *ctx, 437ec681f3Smrg const struct pipe_debug_callback *cb) 447ec681f3Smrg{ 457ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 467ec681f3Smrg 477ec681f3Smrg if (cb) 487ec681f3Smrg ice->dbg = *cb; 497ec681f3Smrg else 507ec681f3Smrg memset(&ice->dbg, 0, sizeof(ice->dbg)); 517ec681f3Smrg} 527ec681f3Smrg 537ec681f3Smrgstatic bool 547ec681f3Smrgcrocus_init_identifier_bo(struct crocus_context *ice) 557ec681f3Smrg{ 567ec681f3Smrg void *bo_map; 577ec681f3Smrg 587ec681f3Smrg bo_map = crocus_bo_map(NULL, ice->workaround_bo, MAP_READ | MAP_WRITE); 597ec681f3Smrg if (!bo_map) 607ec681f3Smrg return false; 617ec681f3Smrg 627ec681f3Smrg ice->workaround_bo->kflags |= EXEC_OBJECT_CAPTURE; 637ec681f3Smrg ice->workaround_offset = ALIGN( 647ec681f3Smrg intel_debug_write_identifiers(bo_map, 4096, "Crocus") + 8, 8); 657ec681f3Smrg 667ec681f3Smrg crocus_bo_unmap(ice->workaround_bo); 677ec681f3Smrg 687ec681f3Smrg return true; 697ec681f3Smrg} 707ec681f3Smrg 717ec681f3Smrg/** 727ec681f3Smrg * Called from the batch module when it detects a GPU hang. 737ec681f3Smrg * 747ec681f3Smrg * In this case, we've lost our GEM context, and can't rely on any existing 757ec681f3Smrg * state on the GPU. We must mark everything dirty and wipe away any saved 767ec681f3Smrg * assumptions about the last known state of the GPU. 777ec681f3Smrg */ 787ec681f3Smrgvoid 797ec681f3Smrgcrocus_lost_context_state(struct crocus_batch *batch) 807ec681f3Smrg{ 817ec681f3Smrg /* The batch module doesn't have an crocus_context, because we want to 827ec681f3Smrg * avoid introducing lots of layering violations. Unfortunately, here 837ec681f3Smrg * we do need to inform the context of batch catastrophe. We know the 847ec681f3Smrg * batch is one of our context's, so hackily claw our way back. 857ec681f3Smrg */ 867ec681f3Smrg struct crocus_context *ice = batch->ice; 877ec681f3Smrg struct crocus_screen *screen = batch->screen; 887ec681f3Smrg if (batch->name == CROCUS_BATCH_RENDER) { 897ec681f3Smrg screen->vtbl.init_render_context(batch); 907ec681f3Smrg } else if (batch->name == CROCUS_BATCH_COMPUTE) { 917ec681f3Smrg screen->vtbl.init_compute_context(batch); 927ec681f3Smrg } else { 937ec681f3Smrg unreachable("unhandled batch reset"); 947ec681f3Smrg } 957ec681f3Smrg 967ec681f3Smrg ice->state.dirty = ~0ull; 977ec681f3Smrg memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid)); 987ec681f3Smrg batch->state_base_address_emitted = false; 997ec681f3Smrg screen->vtbl.lost_genx_state(ice, batch); 1007ec681f3Smrg} 1017ec681f3Smrg 1027ec681f3Smrgstatic enum pipe_reset_status 1037ec681f3Smrgcrocus_get_device_reset_status(struct pipe_context *ctx) 1047ec681f3Smrg{ 1057ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 1067ec681f3Smrg 1077ec681f3Smrg enum pipe_reset_status worst_reset = PIPE_NO_RESET; 1087ec681f3Smrg 1097ec681f3Smrg /* Check the reset status of each batch's hardware context, and take the 1107ec681f3Smrg * worst status (if one was guilty, proclaim guilt). 1117ec681f3Smrg */ 1127ec681f3Smrg for (int i = 0; i < ice->batch_count; i++) { 1137ec681f3Smrg /* This will also recreate the hardware contexts as necessary, so any 1147ec681f3Smrg * future queries will show no resets. We only want to report once. 1157ec681f3Smrg */ 1167ec681f3Smrg enum pipe_reset_status batch_reset = 1177ec681f3Smrg crocus_batch_check_for_reset(&ice->batches[i]); 1187ec681f3Smrg 1197ec681f3Smrg if (batch_reset == PIPE_NO_RESET) 1207ec681f3Smrg continue; 1217ec681f3Smrg 1227ec681f3Smrg if (worst_reset == PIPE_NO_RESET) { 1237ec681f3Smrg worst_reset = batch_reset; 1247ec681f3Smrg } else { 1257ec681f3Smrg /* GUILTY < INNOCENT < UNKNOWN */ 1267ec681f3Smrg worst_reset = MIN2(worst_reset, batch_reset); 1277ec681f3Smrg } 1287ec681f3Smrg } 1297ec681f3Smrg 1307ec681f3Smrg if (worst_reset != PIPE_NO_RESET && ice->reset.reset) 1317ec681f3Smrg ice->reset.reset(ice->reset.data, worst_reset); 1327ec681f3Smrg 1337ec681f3Smrg return worst_reset; 1347ec681f3Smrg} 1357ec681f3Smrg 1367ec681f3Smrgstatic void 1377ec681f3Smrgcrocus_set_device_reset_callback(struct pipe_context *ctx, 1387ec681f3Smrg const struct pipe_device_reset_callback *cb) 1397ec681f3Smrg{ 1407ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 1417ec681f3Smrg 1427ec681f3Smrg if (cb) 1437ec681f3Smrg ice->reset = *cb; 1447ec681f3Smrg else 1457ec681f3Smrg memset(&ice->reset, 0, sizeof(ice->reset)); 1467ec681f3Smrg} 1477ec681f3Smrg 1487ec681f3Smrgstatic void 1497ec681f3Smrgcrocus_get_sample_position(struct pipe_context *ctx, 1507ec681f3Smrg unsigned sample_count, 1517ec681f3Smrg unsigned sample_index, 1527ec681f3Smrg float *out_value) 1537ec681f3Smrg{ 1547ec681f3Smrg union { 1557ec681f3Smrg struct { 1567ec681f3Smrg float x[16]; 1577ec681f3Smrg float y[16]; 1587ec681f3Smrg } a; 1597ec681f3Smrg struct { 1607ec681f3Smrg float _0XOffset, _1XOffset, _2XOffset, _3XOffset, 1617ec681f3Smrg _4XOffset, _5XOffset, _6XOffset, _7XOffset, 1627ec681f3Smrg _8XOffset, _9XOffset, _10XOffset, _11XOffset, 1637ec681f3Smrg _12XOffset, _13XOffset, _14XOffset, _15XOffset; 1647ec681f3Smrg float _0YOffset, _1YOffset, _2YOffset, _3YOffset, 1657ec681f3Smrg _4YOffset, _5YOffset, _6YOffset, _7YOffset, 1667ec681f3Smrg _8YOffset, _9YOffset, _10YOffset, _11YOffset, 1677ec681f3Smrg _12YOffset, _13YOffset, _14YOffset, _15YOffset; 1687ec681f3Smrg } v; 1697ec681f3Smrg } u; 1707ec681f3Smrg switch (sample_count) { 1717ec681f3Smrg case 1: INTEL_SAMPLE_POS_1X(u.v._); break; 1727ec681f3Smrg case 2: INTEL_SAMPLE_POS_2X(u.v._); break; 1737ec681f3Smrg case 4: INTEL_SAMPLE_POS_4X(u.v._); break; 1747ec681f3Smrg case 8: INTEL_SAMPLE_POS_8X(u.v._); break; 1757ec681f3Smrg case 16: INTEL_SAMPLE_POS_16X(u.v._); break; 1767ec681f3Smrg default: unreachable("invalid sample count"); 1777ec681f3Smrg } 1787ec681f3Smrg 1797ec681f3Smrg out_value[0] = u.a.x[sample_index]; 1807ec681f3Smrg out_value[1] = u.a.y[sample_index]; 1817ec681f3Smrg} 1827ec681f3Smrg 1837ec681f3Smrg/** 1847ec681f3Smrg * Destroy a context, freeing any associated memory. 1857ec681f3Smrg */ 1867ec681f3Smrgstatic void 1877ec681f3Smrgcrocus_destroy_context(struct pipe_context *ctx) 1887ec681f3Smrg{ 1897ec681f3Smrg struct crocus_context *ice = (struct crocus_context *)ctx; 1907ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen *)ctx->screen; 1917ec681f3Smrg if (ctx->stream_uploader) 1927ec681f3Smrg u_upload_destroy(ctx->stream_uploader); 1937ec681f3Smrg 1947ec681f3Smrg if (ice->blitter) 1957ec681f3Smrg util_blitter_destroy(ice->blitter); 1967ec681f3Smrg screen->vtbl.destroy_state(ice); 1977ec681f3Smrg crocus_destroy_program_cache(ice); 1987ec681f3Smrg u_upload_destroy(ice->query_buffer_uploader); 1997ec681f3Smrg 2007ec681f3Smrg crocus_bo_unreference(ice->workaround_bo); 2017ec681f3Smrg 2027ec681f3Smrg slab_destroy_child(&ice->transfer_pool); 2037ec681f3Smrg slab_destroy_child(&ice->transfer_pool_unsync); 2047ec681f3Smrg 2057ec681f3Smrg crocus_batch_free(&ice->batches[CROCUS_BATCH_RENDER]); 2067ec681f3Smrg if (ice->batches[CROCUS_BATCH_COMPUTE].ice) 2077ec681f3Smrg crocus_batch_free(&ice->batches[CROCUS_BATCH_COMPUTE]); 2087ec681f3Smrg 2097ec681f3Smrg ralloc_free(ice); 2107ec681f3Smrg} 2117ec681f3Smrg 2127ec681f3Smrg#define genX_call(devinfo, func, ...) \ 2137ec681f3Smrg switch ((devinfo)->verx10) { \ 2147ec681f3Smrg case 80: \ 2157ec681f3Smrg gfx8_##func(__VA_ARGS__); \ 2167ec681f3Smrg break; \ 2177ec681f3Smrg case 75: \ 2187ec681f3Smrg gfx75_##func(__VA_ARGS__); \ 2197ec681f3Smrg break; \ 2207ec681f3Smrg case 70: \ 2217ec681f3Smrg gfx7_##func(__VA_ARGS__); \ 2227ec681f3Smrg break; \ 2237ec681f3Smrg case 60: \ 2247ec681f3Smrg gfx6_##func(__VA_ARGS__); \ 2257ec681f3Smrg break; \ 2267ec681f3Smrg case 50: \ 2277ec681f3Smrg gfx5_##func(__VA_ARGS__); \ 2287ec681f3Smrg break; \ 2297ec681f3Smrg case 45: \ 2307ec681f3Smrg gfx45_##func(__VA_ARGS__); \ 2317ec681f3Smrg break; \ 2327ec681f3Smrg case 40: \ 2337ec681f3Smrg gfx4_##func(__VA_ARGS__); \ 2347ec681f3Smrg break; \ 2357ec681f3Smrg default: \ 2367ec681f3Smrg unreachable("Unknown hardware generation"); \ 2377ec681f3Smrg } 2387ec681f3Smrg 2397ec681f3Smrg/** 2407ec681f3Smrg * Create a context. 2417ec681f3Smrg * 2427ec681f3Smrg * This is where each context begins. 2437ec681f3Smrg */ 2447ec681f3Smrgstruct pipe_context * 2457ec681f3Smrgcrocus_create_context(struct pipe_screen *pscreen, void *priv, unsigned flags) 2467ec681f3Smrg{ 2477ec681f3Smrg struct crocus_screen *screen = (struct crocus_screen*)pscreen; 2487ec681f3Smrg const struct intel_device_info *devinfo = &screen->devinfo; 2497ec681f3Smrg struct crocus_context *ice = rzalloc(NULL, struct crocus_context); 2507ec681f3Smrg 2517ec681f3Smrg if (!ice) 2527ec681f3Smrg return NULL; 2537ec681f3Smrg 2547ec681f3Smrg struct pipe_context *ctx = &ice->ctx; 2557ec681f3Smrg 2567ec681f3Smrg ctx->screen = pscreen; 2577ec681f3Smrg ctx->priv = priv; 2587ec681f3Smrg 2597ec681f3Smrg ctx->stream_uploader = u_upload_create_default(ctx); 2607ec681f3Smrg if (!ctx->stream_uploader) { 2617ec681f3Smrg free(ctx); 2627ec681f3Smrg return NULL; 2637ec681f3Smrg } 2647ec681f3Smrg ctx->const_uploader = ctx->stream_uploader; 2657ec681f3Smrg 2667ec681f3Smrg ctx->destroy = crocus_destroy_context; 2677ec681f3Smrg ctx->set_debug_callback = crocus_set_debug_callback; 2687ec681f3Smrg ctx->set_device_reset_callback = crocus_set_device_reset_callback; 2697ec681f3Smrg ctx->get_device_reset_status = crocus_get_device_reset_status; 2707ec681f3Smrg ctx->get_sample_position = crocus_get_sample_position; 2717ec681f3Smrg 2727ec681f3Smrg ice->shaders.urb_size = devinfo->urb.size; 2737ec681f3Smrg 2747ec681f3Smrg crocus_init_context_fence_functions(ctx); 2757ec681f3Smrg crocus_init_blit_functions(ctx); 2767ec681f3Smrg crocus_init_clear_functions(ctx); 2777ec681f3Smrg crocus_init_program_functions(ctx); 2787ec681f3Smrg crocus_init_resource_functions(ctx); 2797ec681f3Smrg crocus_init_flush_functions(ctx); 2807ec681f3Smrg 2817ec681f3Smrg crocus_init_program_cache(ice); 2827ec681f3Smrg 2837ec681f3Smrg slab_create_child(&ice->transfer_pool, &screen->transfer_pool); 2847ec681f3Smrg slab_create_child(&ice->transfer_pool_unsync, &screen->transfer_pool); 2857ec681f3Smrg 2867ec681f3Smrg ice->query_buffer_uploader = 2877ec681f3Smrg u_upload_create(ctx, 4096, PIPE_BIND_CUSTOM, PIPE_USAGE_STAGING, 2887ec681f3Smrg 0); 2897ec681f3Smrg 2907ec681f3Smrg ice->workaround_bo = 2917ec681f3Smrg crocus_bo_alloc(screen->bufmgr, "workaround", 4096); 2927ec681f3Smrg if (!ice->workaround_bo) 2937ec681f3Smrg return NULL; 2947ec681f3Smrg 2957ec681f3Smrg if (!crocus_init_identifier_bo(ice)) 2967ec681f3Smrg return NULL; 2977ec681f3Smrg 2987ec681f3Smrg genX_call(devinfo, crocus_init_state, ice); 2997ec681f3Smrg genX_call(devinfo, crocus_init_blorp, ice); 3007ec681f3Smrg genX_call(devinfo, crocus_init_query, ice); 3017ec681f3Smrg 3027ec681f3Smrg ice->blitter = util_blitter_create(&ice->ctx); 3037ec681f3Smrg if (ice->blitter == NULL) 3047ec681f3Smrg return NULL; 3057ec681f3Smrg int priority = 0; 3067ec681f3Smrg if (flags & PIPE_CONTEXT_HIGH_PRIORITY) 3077ec681f3Smrg priority = INTEL_CONTEXT_HIGH_PRIORITY; 3087ec681f3Smrg if (flags & PIPE_CONTEXT_LOW_PRIORITY) 3097ec681f3Smrg priority = INTEL_CONTEXT_LOW_PRIORITY; 3107ec681f3Smrg 3117ec681f3Smrg ice->batch_count = devinfo->ver >= 7 ? CROCUS_BATCH_COUNT : 1; 3127ec681f3Smrg for (int i = 0; i < ice->batch_count; i++) { 3137ec681f3Smrg crocus_init_batch(ice, (enum crocus_batch_name) i, 3147ec681f3Smrg priority); 3157ec681f3Smrg } 3167ec681f3Smrg 3177ec681f3Smrg ice->urb.size = devinfo->urb.size; 3187ec681f3Smrg screen->vtbl.init_render_context(&ice->batches[CROCUS_BATCH_RENDER]); 3197ec681f3Smrg if (ice->batch_count > 1) 3207ec681f3Smrg screen->vtbl.init_compute_context(&ice->batches[CROCUS_BATCH_COMPUTE]); 3217ec681f3Smrg 3227ec681f3Smrg if (!(flags & PIPE_CONTEXT_PREFER_THREADED)) 3237ec681f3Smrg return ctx; 3247ec681f3Smrg 3257ec681f3Smrg return threaded_context_create(ctx, &screen->transfer_pool, 3267ec681f3Smrg crocus_replace_buffer_storage, 3277ec681f3Smrg NULL, /* TODO: asynchronous flushes? */ 3287ec681f3Smrg &ice->thrctx); 3297ec681f3Smrg} 3307ec681f3Smrg 3317ec681f3Smrgbool 3327ec681f3Smrgcrocus_sw_check_cond_render(struct crocus_context *ice) 3337ec681f3Smrg{ 3347ec681f3Smrg struct crocus_query *q = ice->condition.query; 3357ec681f3Smrg union pipe_query_result result; 3367ec681f3Smrg 3377ec681f3Smrg bool wait = ice->condition.mode == PIPE_RENDER_COND_WAIT || 3387ec681f3Smrg ice->condition.mode == PIPE_RENDER_COND_BY_REGION_WAIT; 3397ec681f3Smrg if (!q) 3407ec681f3Smrg return true; 3417ec681f3Smrg 3427ec681f3Smrg bool ret = ice->ctx.get_query_result(&ice->ctx, (void *)q, wait, &result); 3437ec681f3Smrg if (!ret) 3447ec681f3Smrg return true; 3457ec681f3Smrg 3467ec681f3Smrg return ice->condition.condition ? result.u64 == 0 : result.u64 != 0; 3477ec681f3Smrg} 348