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